Primo schema DB

This commit is contained in:
2026-04-28 12:42:25 +02:00
parent 375d556628
commit 1ede1d14ab
2 changed files with 353 additions and 0 deletions
+3
View File
@@ -3,6 +3,9 @@
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
*$py.class *$py.class
__pycache__/
*.py[cod]
.env
# C extensions # C extensions
*.so *.so
@@ -0,0 +1,350 @@
"""schema iniziale
Revision ID: 0001
Revises:
Create Date: 2026-04-28 12:40:08.000000
"""
from typing import Sequence, Union
from alembic import op
revision: str = "0001"
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.execute("""
DO $$ BEGIN
CREATE TYPE userrole AS ENUM ('venditore','valutatore','backoffice','operatore_perizie','approvatore_perizie','admin');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE valuationstatus AS ENUM ('bozza','inviata','in_lavorazione','completata','vinta','persa');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE valuationpriority AS ENUM ('contratto','preventivo','valutazione');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE retakeregime AS ENUM ('nuovo','usato');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE repairstatus AS ENUM ('bozza','inviata','in_approvazione','approvata','rifiutata','chiusa');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE repairdestination AS ENUM ('vendita','rottamazione','altro');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE offerstatus AS ENUM ('in_attesa','accettata','rifiutata');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
CREATE TABLE IF NOT EXISTS groups (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description VARCHAR(255),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
full_name VARCHAR(200) NOT NULL,
hashed_password VARCHAR(255) NOT NULL,
role userrole NOT NULL,
group_id INTEGER REFERENCES groups(id),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
notify_email BOOLEAN NOT NULL DEFAULT TRUE,
notify_push BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_users_email ON users (email);
CREATE TABLE IF NOT EXISTS vehicle_registry (
plate VARCHAR(10) PRIMARY KEY,
vin VARCHAR(17),
vehicle_type VARCHAR(50),
registration_date DATE,
homologation_code VARCHAR(50),
engine_code VARCHAR(20),
last_revision_date DATE,
foreign_plate VARCHAR(20),
foreign_registration_date DATE,
foreign_country VARCHAR(50),
is_foreign_registered BOOLEAN,
source VARCHAR(20),
raw_response JSONB,
fetched_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
selected_motornet_code VARCHAR(20)
);
CREATE TABLE IF NOT EXISTS vehicle_versions (
motornet_code VARCHAR(20) PRIMARY KEY,
brand_acronym VARCHAR(10),
brand_name VARCHAR(50),
model_code VARCHAR(10),
model_description VARCHAR(100),
gamma_code VARCHAR(10),
gamma_description VARCHAR(100),
series_code VARCHAR(10),
series_description VARCHAR(100),
historical_group_code VARCHAR(10),
historical_group_desc VARCHAR(100),
cod_desc_model_code VARCHAR(10),
cod_desc_model_desc VARCHAR(100),
version_label VARCHAR(200),
body_type VARCHAR(10),
doors SMALLINT,
wheelbase SMALLINT,
list_price NUMERIC(10,2),
production_start DATE,
production_end DATE,
commercial_start DATE,
commercial_end DATE,
first_seen_at TIMESTAMPTZ,
last_seen_at TIMESTAMPTZ,
seen_count INTEGER NOT NULL DEFAULT 1,
source VARCHAR(20)
);
CREATE TABLE IF NOT EXISTS plate_version_candidates (
plate VARCHAR(10) REFERENCES vehicle_registry(plate),
motornet_code VARCHAR(20) REFERENCES vehicle_versions(motornet_code),
is_selected BOOLEAN NOT NULL DEFAULT FALSE,
PRIMARY KEY (plate, motornet_code)
);
CREATE TABLE IF NOT EXISTS api_usage_log (
id SERIAL PRIMARY KEY,
source VARCHAR(20),
plate VARCHAR(10),
hit_cache BOOLEAN NOT NULL DEFAULT FALSE,
remaining_queries INTEGER,
called_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS valuations (
id SERIAL PRIMARY KEY,
plate VARCHAR(10) NOT NULL REFERENCES vehicle_registry(plate),
user_id INTEGER NOT NULL REFERENCES users(id),
group_id INTEGER REFERENCES groups(id),
motornet_code VARCHAR(20) REFERENCES vehicle_versions(motornet_code),
mileage INTEGER,
retake_regime retakeregime,
expected_return_date DATE,
interest_fuel VARCHAR(50),
priority valuationpriority NOT NULL DEFAULT 'valutazione',
notes TEXT,
status valuationstatus NOT NULL DEFAULT 'bozza',
final_value NUMERIC(10,2),
evaluator_id INTEGER REFERENCES users(id),
evaluator_notes TEXT,
is_frozen BOOLEAN NOT NULL DEFAULT FALSE,
priority_rank INTEGER NOT NULL DEFAULT 3,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_valuations_plate ON valuations (plate);
CREATE INDEX IF NOT EXISTS ix_valuations_status ON valuations (status);
CREATE TABLE IF NOT EXISTS valuation_photos (
id SERIAL PRIMARY KEY,
valuation_id INTEGER NOT NULL REFERENCES valuations(id),
filename VARCHAR(255) NOT NULL,
storage_path VARCHAR(500) NOT NULL,
uploaded_by INTEGER NOT NULL REFERENCES users(id),
uploaded_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS valuation_comments (
id SERIAL PRIMARY KEY,
valuation_id INTEGER NOT NULL REFERENCES valuations(id),
user_id INTEGER NOT NULL REFERENCES users(id),
content TEXT NOT NULL,
visible_to_all BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS valuation_history (
id SERIAL PRIMARY KEY,
valuation_id INTEGER NOT NULL REFERENCES valuations(id),
changed_by INTEGER NOT NULL REFERENCES users(id),
field_name VARCHAR(100) NOT NULL,
old_value TEXT,
new_value TEXT,
changed_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS contracts (
id SERIAL PRIMARY KEY,
contract_number VARCHAR(50) NOT NULL,
year INTEGER NOT NULL,
company VARCHAR(100) NOT NULL,
area VARCHAR(100),
plate VARCHAR(10),
customer_name VARCHAR(200),
import_batch VARCHAR(100),
imported_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS valuation_contracts (
id SERIAL PRIMARY KEY,
valuation_id INTEGER NOT NULL REFERENCES valuations(id),
contract_id INTEGER NOT NULL REFERENCES contracts(id),
linked_by INTEGER NOT NULL REFERENCES users(id),
linked_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS repairs (
id SERIAL PRIMARY KEY,
plate VARCHAR(10) NOT NULL REFERENCES vehicle_registry(plate),
company VARCHAR(100),
infinity_repair_number VARCHAR(50),
intervention_type VARCHAR(100),
delivery_location VARCHAR(100),
group_id INTEGER REFERENCES groups(id),
created_by INTEGER NOT NULL REFERENCES users(id),
status repairstatus NOT NULL DEFAULT 'bozza',
destination repairdestination,
offer_status offerstatus,
estimated_value NUMERIC(10,2),
actual_value NUMERIC(10,2),
subtotal NUMERIC(10,2),
notes TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_repairs_plate ON repairs (plate);
CREATE INDEX IF NOT EXISTS ix_repairs_status ON repairs (status);
CREATE TABLE IF NOT EXISTS repair_documents (
id SERIAL PRIMARY KEY,
repair_id INTEGER NOT NULL REFERENCES repairs(id),
filename VARCHAR(255) NOT NULL,
storage_path VARCHAR(500) NOT NULL,
uploaded_by INTEGER NOT NULL REFERENCES users(id),
uploaded_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS repair_comments (
id SERIAL PRIMARY KEY,
repair_id INTEGER NOT NULL REFERENCES repairs(id),
user_id INTEGER NOT NULL REFERENCES users(id),
content TEXT NOT NULL,
mentions TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS repair_history (
id SERIAL PRIMARY KEY,
repair_id INTEGER NOT NULL REFERENCES repairs(id),
changed_by INTEGER NOT NULL REFERENCES users(id),
field_name VARCHAR(100) NOT NULL,
old_value TEXT,
new_value TEXT,
changed_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS notifications (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
title VARCHAR(200) NOT NULL,
body TEXT,
link VARCHAR(500),
is_read BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS alert_config (
id SERIAL PRIMARY KEY,
key VARCHAR(100) NOT NULL UNIQUE,
value VARCHAR(255) NOT NULL,
description VARCHAR(500),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS vehicle_stock (
id SERIAL PRIMARY KEY,
plate VARCHAR(10) NOT NULL,
brand VARCHAR(50),
model VARCHAR(100),
version VARCHAR(200),
registration_date VARCHAR(20),
mileage INTEGER,
location VARCHAR(100),
import_batch VARCHAR(100),
imported_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_vehicle_stock_plate ON vehicle_stock (plate);
CREATE TABLE IF NOT EXISTS repair_costs_avg (
id SERIAL PRIMARY KEY,
model VARCHAR(100) NOT NULL,
avg_cost NUMERIC(10,2),
import_batch VARCHAR(100),
imported_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_repair_costs_avg_model ON repair_costs_avg (model);
CREATE TABLE IF NOT EXISTS vehicle_sales_avg (
id SERIAL PRIMARY KEY,
model VARCHAR(100) NOT NULL,
avg_stock_days NUMERIC(6,1),
avg_repair_cost NUMERIC(10,2),
avg_margin_eur NUMERIC(10,2),
avg_margin_pct NUMERIC(5,2),
avg_sale_price NUMERIC(10,2),
import_batch VARCHAR(100),
imported_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_vehicle_sales_avg_model ON vehicle_sales_avg (model);
INSERT INTO alert_config (key, value, description)
VALUES
('cache_ttl_days', '90', 'TTL cache targhe in giorni'),
('alert_days_threshold', '30', 'Giorni ritardo rientro per alert'),
('repair_alert_pct_consuntiva', '20', 'Soglia % preventivo vs consuntiva'),
('repair_alert_pct_preventiva', '20', 'Soglia % preventivo vs preventiva')
ON CONFLICT (key) DO NOTHING;
""")
def downgrade() -> None:
op.execute("""
DROP TABLE IF EXISTS vehicle_sales_avg CASCADE;
DROP TABLE IF EXISTS repair_costs_avg CASCADE;
DROP TABLE IF EXISTS vehicle_stock CASCADE;
DROP TABLE IF EXISTS alert_config CASCADE;
DROP TABLE IF EXISTS notifications CASCADE;
DROP TABLE IF EXISTS repair_history CASCADE;
DROP TABLE IF EXISTS repair_comments CASCADE;
DROP TABLE IF EXISTS repair_documents CASCADE;
DROP TABLE IF EXISTS repairs CASCADE;
DROP TABLE IF EXISTS valuation_contracts CASCADE;
DROP TABLE IF EXISTS contracts CASCADE;
DROP TABLE IF EXISTS valuation_history CASCADE;
DROP TABLE IF EXISTS valuation_comments CASCADE;
DROP TABLE IF EXISTS valuation_photos CASCADE;
DROP TABLE IF EXISTS valuations CASCADE;
DROP TABLE IF EXISTS api_usage_log CASCADE;
DROP TABLE IF EXISTS plate_version_candidates CASCADE;
DROP TABLE IF EXISTS vehicle_versions CASCADE;
DROP TABLE IF EXISTS vehicle_registry CASCADE;
DROP TABLE IF EXISTS users CASCADE;
DROP TABLE IF EXISTS groups CASCADE;
DROP TYPE IF EXISTS offerstatus;
DROP TYPE IF EXISTS repairdestination;
DROP TYPE IF EXISTS repairstatus;
DROP TYPE IF EXISTS retakeregime;
DROP TYPE IF EXISTS valuationpriority;
DROP TYPE IF EXISTS valuationstatus;
DROP TYPE IF EXISTS userrole;
""")