diff --git a/backend/app/__init__.py b/backend/app/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/backend/app/api/v1/endpoints/__pycache__/admin.cpython-312.pyc b/backend/app/api/v1/endpoints/__pycache__/admin.cpython-312.pyc index cdb564f..0e4b98f 100644 Binary files a/backend/app/api/v1/endpoints/__pycache__/admin.cpython-312.pyc and b/backend/app/api/v1/endpoints/__pycache__/admin.cpython-312.pyc differ diff --git a/backend/app/api/v1/endpoints/__pycache__/auth.cpython-312.pyc b/backend/app/api/v1/endpoints/__pycache__/auth.cpython-312.pyc index 3cf1563..e7666ed 100644 Binary files a/backend/app/api/v1/endpoints/__pycache__/auth.cpython-312.pyc and b/backend/app/api/v1/endpoints/__pycache__/auth.cpython-312.pyc differ diff --git a/backend/app/api/v1/endpoints/admin.py b/backend/app/api/v1/endpoints/admin.py index 6f555c1..27f3a78 100755 --- a/backend/app/api/v1/endpoints/admin.py +++ b/backend/app/api/v1/endpoints/admin.py @@ -6,7 +6,7 @@ from datetime import datetime, timedelta from app.api import deps from app.models.identity import User, UserRole -from app.models.system_config import SystemParameter +from app.models import SystemParameter from app.models.security import PendingAction, ActionStatus from app.models.history import AuditLog, LogSeverity from app.schemas.admin_security import PendingActionResponse, SecurityStatusResponse diff --git a/backend/app/diagnose_system.py b/backend/app/diagnose_system.py index 6a7bef6..a5e847b 100644 --- a/backend/app/diagnose_system.py +++ b/backend/app/diagnose_system.py @@ -8,7 +8,7 @@ from sqlalchemy.orm import sessionmaker try: from app.core.config import settings from app.core.i18n import t - from app.models.system_config import SystemParameter + from app.models import SystemParameter except ImportError as e: print(f"❌ Import hiba: {e}") print("Ellenőrizd, hogy a PYTHONPATH be van-e állítva!") diff --git a/backend/app/models/__init__.py b/backend/app/models/__init__.py index f880981..16b9d71 100755 --- a/backend/app/models/__init__.py +++ b/backend/app/models/__init__.py @@ -32,10 +32,13 @@ from .translation import Translation from .core_logic import SubscriptionTier, OrganizationSubscription, CreditTransaction, ServiceSpecialty # Naplózás és Biztonság (HOZZÁADVA: audit.py modellek) -from .audit import SecurityAuditLog, OperationalLog, FinancialLedger # <--- KRITIKUS! +from .audit import SecurityAuditLog, ProcessLog, FinancialLedger # <--- KRITIKUS! from .history import AuditLog, VehicleOwnership from .security import PendingAction +# MDM (Master Data Management) Jármű modellek központ +from .vehicle_definitions import VehicleModelDefinition, VehicleType, FeatureDefinition, ModelFeatureMap + # Aliasok a kényelmesebb fejlesztéshez Vehicle = Asset UserVehicle = Asset @@ -48,11 +51,12 @@ __all__ = [ "Asset", "AssetCatalog", "AssetCost", "AssetEvent", "AssetFinancials", "AssetTelemetry", "AssetReview", "ExchangeRate", "Address", "GeoPostalCode", "GeoStreet", "GeoStreetType", "Branch", - "Point_Rule", "LevelConfig", "UserStats", "Badge", "UserBadge", "Rating", "PointsLedger", + "PointRule", "LevelConfig", "UserStats", "Badge", "UserBadge", "Rating", "PointsLedger", "SystemParameter", "Document", "Translation", "PendingAction", "SubscriptionTier", "OrganizationSubscription", "CreditTransaction", "ServiceSpecialty", "AuditLog", "VehicleOwnership", - "SecurityAuditLog", "OperationalLog", "FinancialLedger", # <--- KRITIKUS! + "SecurityAuditLog", "ProcessLog", "FinancialLedger", # <--- KRITIKUS! "ServiceProfile", "ExpertiseTag", "ServiceExpertise", "ServiceStaging", - "Vehicle", "UserVehicle", "VehicleCatalog", "ServiceRecord" + "Vehicle", "UserVehicle", "VehicleCatalog", "ServiceRecord", "VehicleModelDefinition", + "VehicleType", "FeatureDefinition", "ModelFeatureMap" ] \ No newline at end of file diff --git a/backend/app/models/__pycache__/__init__.cpython-312.pyc b/backend/app/models/__pycache__/__init__.cpython-312.pyc index 3dc9bf0..3ea35bf 100644 Binary files a/backend/app/models/__pycache__/__init__.cpython-312.pyc and b/backend/app/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/backend/app/models/__pycache__/asset.cpython-312.pyc b/backend/app/models/__pycache__/asset.cpython-312.pyc index 60e7bef..a733292 100644 Binary files a/backend/app/models/__pycache__/asset.cpython-312.pyc and b/backend/app/models/__pycache__/asset.cpython-312.pyc differ diff --git a/backend/app/models/__pycache__/gamification.cpython-312.pyc b/backend/app/models/__pycache__/gamification.cpython-312.pyc index ac42ebd..bd23b9c 100644 Binary files a/backend/app/models/__pycache__/gamification.cpython-312.pyc and b/backend/app/models/__pycache__/gamification.cpython-312.pyc differ diff --git a/backend/app/models/__pycache__/identity.cpython-312.pyc b/backend/app/models/__pycache__/identity.cpython-312.pyc index 656f7ee..ca09c3a 100644 Binary files a/backend/app/models/__pycache__/identity.cpython-312.pyc and b/backend/app/models/__pycache__/identity.cpython-312.pyc differ diff --git a/backend/app/models/asset.py b/backend/app/models/asset.py index 907d1ec..bd750af 100644 --- a/backend/app/models/asset.py +++ b/backend/app/models/asset.py @@ -16,6 +16,9 @@ class AssetCatalog(Base): ) id = Column(Integer, primary_key=True, index=True) + # Kapcsolat az MDM-hez + master_definition_id = Column(Integer, ForeignKey("data.vehicle_model_definitions.id"), nullable=True) + make = Column(String, index=True, nullable=False) model = Column(String, index=True, nullable=False) generation = Column(String, index=True) @@ -24,7 +27,10 @@ class AssetCatalog(Base): year_to = Column(Integer) vehicle_class = Column(String) fuel_type = Column(String, index=True) + # ÚJ MEZŐ: Kapcsolat az MDM-hez + + master_definition = relationship("VehicleModelDefinition", back_populates="variants") # --- ÚJ OSZLOPOK (Ezeket add hozzá!) --- power_kw = Column(Integer, index=True) engine_capacity = Column(Integer, index=True) diff --git a/backend/app/models/audit.py b/backend/app/models/audit.py index ac7d03c..acd8ba2 100644 --- a/backend/app/models/audit.py +++ b/backend/app/models/audit.py @@ -13,28 +13,41 @@ class SecurityAuditLog(Base): actor_id = Column(Integer, ForeignKey("data.users.id")) # Aki kezdeményezte target_id = Column(Integer, ForeignKey("data.users.id")) # Akivel történt - # 4-szem elv: csak akkor válik élessé, ha ez nem NULL confirmed_by_id = Column(Integer, ForeignKey("data.users.id"), nullable=True) - is_critical = Column(Boolean, default=False) # Szuperadmin hívásoknál True + is_critical = Column(Boolean, default=False) payload_before = Column(JSON) payload_after = Column(JSON) created_at = Column(DateTime(timezone=True), server_default=func.now()) class OperationalLog(Base): - """ Napi üzemi események (Operational). """ + """ Felhasználói szintű napi üzemi események (Audit Trail). """ __tablename__ = "operational_logs" __table_args__ = {"schema": "data", "extend_existing": True} - id = Column(Integer, primary_key=True, index=True) # <--- EZ HIÁNYZOTT! + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("data.users.id", ondelete="SET NULL"), nullable=True) - action = Column(String(100), nullable=False) # pl. "ADD_VEHICLE", "UPDATE_COST" - resource_type = Column(String(50)) # pl. "Asset", "Expense" + action = Column(String(100), nullable=False) # pl. "ADD_VEHICLE" + resource_type = Column(String(50)) resource_id = Column(String(100)) details = Column(JSON, server_default=text("'{}'::jsonb")) ip_address = Column(String(45)) created_at = Column(DateTime(timezone=True), server_default=func.now()) +class ProcessLog(Base): + """ Robotok és háttérfolyamatok futási naplója (A reggeli jelentésekhez). """ + __tablename__ = "process_logs" # Külön tábla a tisztaság kedvéért + __table_args__ = {"schema": "data", "extend_existing": True} + + id = Column(Integer, primary_key=True) + process_name = Column(String(100), index=True) # 'Master-Enricher' + start_time = Column(DateTime(timezone=True), server_default=func.now()) + end_time = Column(DateTime(timezone=True)) + items_processed = Column(Integer, default=0) + items_failed = Column(Integer, default=0) + details = Column(JSON, server_default=text("'{}'::jsonb")) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + class FinancialLedger(Base): """ Minden pénz- és kreditmozgás központi naplója. """ __tablename__ = "financial_ledger" @@ -43,14 +56,9 @@ class FinancialLedger(Base): id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey("data.users.id")) person_id = Column(BigInteger, ForeignKey("data.persons.id")) - amount = Column(Numeric(18, 4), nullable=False) - currency = Column(String(10)) # 'HUF', 'CREDIT', 'COIN' - - transaction_type = Column(String(50)) # 'PURCHASE', 'HUNTING_COMMISSION', 'FARMING_COMMISSION' - - # Üzletkötői követhetőség + currency = Column(String(10)) + transaction_type = Column(String(50)) related_agent_id = Column(Integer, ForeignKey("data.users.id"), nullable=True) - details = Column(JSON, server_default=text("'{}'::jsonb")) created_at = Column(DateTime(timezone=True), server_default=func.now()) \ No newline at end of file diff --git a/backend/app/models/gamification.py b/backend/app/models/gamification.py index 2a5c6de..1a6901b 100755 --- a/backend/app/models/gamification.py +++ b/backend/app/models/gamification.py @@ -44,18 +44,22 @@ class PointsLedger(Base): class UserStats(Base): __tablename__ = "user_stats" - __table_args__ = SCHEMA_ARGS + __table_args__ = {"schema": "data", "extend_existing": True} # Biztosítjuk a sémát + + # A ForeignKey-nek látnia kell a data sémát! user_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.users.id"), primary_key=True) + total_xp: Mapped[int] = mapped_column(Integer, default=0) social_points: Mapped[int] = mapped_column(Integer, default=0) current_level: Mapped[int] = mapped_column(Integer, default=1) - # --- BÜNTETŐ RENDSZER (Strike System) --- - # JAVÍTÁS: server_default hozzáadva, hogy a meglévő sorok is 0-t kapjanak + # --- BÜNTETŐ RENDSZER --- penalty_points: Mapped[int] = mapped_column(Integer, server_default=text("0"), default=0) restriction_level: Mapped[int] = mapped_column(Integer, server_default=text("0"), default=0) updated_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now()) + + # VISSZAMUTATÁS A USER-RE: a back_populates értéke meg kell egyezzen a User osztály 'stats' mezőjével! user: Mapped["User"] = relationship("User", back_populates="stats") diff --git a/backend/app/models/identity.py b/backend/app/models/identity.py index ba92094..8de7c5e 100644 --- a/backend/app/models/identity.py +++ b/backend/app/models/identity.py @@ -85,6 +85,14 @@ class User(Base): # Farming üzletkötő (Átruházható cégkezelő) current_sales_agent_id = Column(Integer, ForeignKey("data.users.id"), nullable=True) + # Szervezeti kapcsolat + owned_organizations = relationship("Organization", back_populates="owner") + + # Ez a sor felelős a gamification.py-val való hídért + stats = relationship("UserStats", back_populates="user", uselist=False, cascade="all, delete-orphan") + + ownership_history = relationship("VehicleOwnership", back_populates="user") + is_active = Column(Boolean, default=False) is_deleted = Column(Boolean, default=False) folder_slug = Column(String(12), unique=True, index=True) diff --git a/backend/app/models/system_config.py b/backend/app/models/system_config.py.bak similarity index 100% rename from backend/app/models/system_config.py rename to backend/app/models/system_config.py.bak diff --git a/backend/app/models/vehicle_definitions.py b/backend/app/models/vehicle_definitions.py new file mode 100644 index 0000000..62782c4 --- /dev/null +++ b/backend/app/models/vehicle_definitions.py @@ -0,0 +1,85 @@ +from sqlalchemy import Column, Integer, String, JSON, UniqueConstraint, text, Boolean, DateTime, ForeignKey, Numeric +from sqlalchemy.orm import relationship +from sqlalchemy.sql import func +from app.db.base_class import Base + +class VehicleType(Base): + """Jármű főtípusok sémája (Séma-gazda)""" + __tablename__ = "vehicle_types" + __table_args__ = {"schema": "data"} + + id = Column(Integer, primary_key=True) + code = Column(String(30), unique=True, index=True) # car, motorcycle, truck, bus, boat, etc. + name = Column(String(50)) # Megjelenítendő név + icon = Column(String(50)) + units = Column(JSON, server_default=text("'{\"power\": \"kW\", \"weight\": \"kg\", \"cargo\": \"m3\"}'::jsonb")) + + features = relationship("FeatureDefinition", back_populates="vehicle_type") + definitions = relationship("VehicleModelDefinition", back_populates="v_type_rel") + +class FeatureDefinition(Base): + """Globális felszereltség szótár""" + __tablename__ = "feature_definitions" + __table_args__ = {"schema": "data"} + + id = Column(Integer, primary_key=True) + vehicle_type_id = Column(Integer, ForeignKey("data.vehicle_types.id")) + category = Column(String(50)) # Műszaki, Beltér, Kültér, Multimédia + name = Column(String(100), nullable=False) + data_type = Column(String(20), default="boolean") + + vehicle_type = relationship("VehicleType", back_populates="features") + +class ModelFeatureMap(Base): + """Modell-szintű felszereltségi sablon (Alap vs Extra)""" + __tablename__ = "model_feature_maps" + __table_args__ = {"schema": "data"} + + model_id = Column(Integer, ForeignKey("data.vehicle_model_definitions.id"), primary_key=True) + feature_id = Column(Integer, ForeignKey("data.feature_definitions.id"), primary_key=True) + availability = Column(String(20), default="standard") # standard, optional, accessory + value = Column(String(100)) + +class VehicleModelDefinition(Base): + """MDM Master rekordok""" + __tablename__ = "vehicle_model_definitions" + __table_args__ = ( + UniqueConstraint('make', 'technical_code', 'vehicle_type', name='uix_make_tech_type'), + {"schema": "data"} + ) + + id = Column(Integer, primary_key=True) + make = Column(String(50), nullable=False, index=True) + technical_code = Column(String(50), nullable=False, index=True) + marketing_name = Column(String(100), index=True) + family_name = Column(String(100)) + + vehicle_type = Column(String(30), index=True) + vehicle_type_id = Column(Integer, ForeignKey("data.vehicle_types.id")) + vehicle_class = Column(String(50)) + + # --- LOGISZTIKAI ÉS TECHNIKAI FIX OSZLOPOK (v1.9) --- + engine_capacity = Column(Integer, index=True) + power_kw = Column(Integer, index=True) + max_weight_kg = Column(Integer, index=True) # Össztömeg + + axle_count = Column(Integer) # Tengelyek száma (Teher/Busz) + payload_capacity_kg = Column(Integer) # Teherbírás + cargo_volume_m3 = Column(Numeric(10, 2)) # Raktér térfogat + cargo_length_mm = Column(Integer) # Raktér méretek + cargo_width_mm = Column(Integer) + cargo_height_mm = Column(Integer) + # -------------------------------------------------- + + specifications = Column(JSON, server_default=text("'{}'::jsonb")) + features_json = Column(JSON, server_default=text("'{}'::jsonb")) # Összesített gyorseléréshez + + status = Column(String(20), server_default="unverified") + is_master = Column(Boolean, default=False) + source = Column(String(50)) + + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + v_type_rel = relationship("VehicleType", back_populates="definitions") + variants = relationship("AssetCatalog", back_populates="master_definition") \ No newline at end of file diff --git a/backend/app/schemas/vehicle_categories.py b/backend/app/schemas/vehicle_categories.py new file mode 100644 index 0000000..8cdc915 --- /dev/null +++ b/backend/app/schemas/vehicle_categories.py @@ -0,0 +1,20 @@ +# app/core/schemas/vehicle_categories.py + +VEHICLE_SCHEMAS = { + "motorcycle": { + "features": ["ABS", "Markolatfűtés", "Szélvédő", "Bukócső/gomba", "Automata váltó", "Gyári dobozok", "Zárható doboz", "Veterán"], + "service_items": ["motorolaj", "olajszűrő", "levegőszűrő", "lánc_szett", "fékfolyadék", "gyújtógyertya", "szelephézag_ellenőrzés"] + }, + "car": { + "features": ["Automata", "Tempomat", "Összkerékhajtás", "Alufelni", "Elektromos ablak", "Vonóhorog", "ISOFIX rendszer", "ESP", "Szervizkönyv", "Veterán"], + "service_items": ["motorolaj", "olajszűrő", "levegőszűrő", "pollenszűrő", "vezérlés_szett", "hosszbordásszíj", "váltóolaj", "fagyálló"] + }, + "truck": { + "features": ["Légrugó", "Hálófülke", "Retarder/Intarder", "Emelőhátfal", "Tengelysúly-mérő", "AdBlue", "Állóhelyzeti klíma"], + "service_items": ["motorolaj", "légfék_szárító_patron", "üzemanyagszűrő", "érintésvédelmi_vizsga", "tengely_zsírozás"] + }, + "boat": { + "features": ["Utánfutó", "Takaróponyva", "Orrsugárkormány", "Halradar", "Kormányállás", "Üzemanyagtartály", "Sólyakocsi", "Zárható tároló", "Elektromos horgonycsörlő"], + "service_items": ["motorolaj", "hajómotor_anód", "vízpumpa_lapát", "téliesítés", "algagátlózás"] + } +} \ No newline at end of file diff --git a/backend/app/scripts/link_catalog_to_mdm.py b/backend/app/scripts/link_catalog_to_mdm.py new file mode 100644 index 0000000..f7c481c --- /dev/null +++ b/backend/app/scripts/link_catalog_to_mdm.py @@ -0,0 +1,78 @@ +import asyncio +from sqlalchemy import select, update, func +from app.db.session import SessionLocal +from app.models.asset import AssetCatalog +from app.models.vehicle_definitions import VehicleModelDefinition, VehicleType + +async def link_catalog_to_mdm(): + async with SessionLocal() as db: + try: + print("🔍 Meglévő variánsok elemzése...") + + # 1. Lekérjük a típusokat a gyors kereséshez + type_res = await db.execute(select(VehicleType)) + types = {t.code: t.id for t in type_res.scalars().all()} + + # 2. Kigyűjtjük az egyedi márkákat és modelleket a katalógusból + # Itt csoportosítunk, hogy ne legyen duplikáció + stmt = select( + AssetCatalog.make, + AssetCatalog.model, + AssetCatalog.vehicle_class + ).distinct() + + raw_data = await db.execute(stmt) + unique_models = raw_data.all() + + print(f"📊 Találtunk {len(unique_models)} egyedi modellt. Összefésülés indul...") + + linked_count = 0 + for make, model, v_class in unique_models: + # Meghatározzuk a típus ID-t (alapértelmezett: car) + t_code = v_class if v_class in types else "car" + t_id = types.get(t_code) + + # Keressük, létezik-e már ilyen Master rekord + # A technical_code-ot itt ideiglenesen a modell nevével töltjük, + # amíg a robot/AI nem pontosítja + master_stmt = select(VehicleModelDefinition).where( + VehicleModelDefinition.make == make, + VehicleModelDefinition.marketing_name == model + ) + master_res = await db.execute(master_stmt) + master = master_res.scalar_one_or_none() + + if not master: + master = VehicleModelDefinition( + make=make, + technical_code=model, # Ideiglenes + marketing_name=model, + vehicle_type=t_code, + vehicle_type_id=t_id, + status="unverified", + source="initial_linking" + ) + db.add(master) + await db.flush() # Hogy megkapjuk az ID-t + + # 3. Összekötjük az összes variánst ezzel a Master rekorddal + update_stmt = update(AssetCatalog).where( + AssetCatalog.make == make, + AssetCatalog.model == model + ).values(master_definition_id=master.id) + + await db.execute(update_stmt) + linked_count += 1 + + if linked_count % 100 == 0: + print(f"⏳ Feldolgozva: {linked_count} modell...") + + await db.commit() + print(f"✅ Kész! {linked_count} Master rekord létrehozva és összekötve.") + + except Exception as e: + await db.rollback() + print(f"❌ Hiba az összefésülésnél: {e}") + +if __name__ == "__main__": + asyncio.run(link_catalog_to_mdm()) \ No newline at end of file diff --git a/backend/app/scripts/morning_report.py b/backend/app/scripts/morning_report.py new file mode 100644 index 0000000..c1efbda --- /dev/null +++ b/backend/app/scripts/morning_report.py @@ -0,0 +1,42 @@ +import asyncio +from sqlalchemy import select, func +from app.db.session import SessionLocal +from app.models.audit import ProcessLog +from datetime import datetime, timedelta + +async def generate_morning_report(): + async with SessionLocal() as db: + # Az elmúlt 24 óra logjai + yesterday = datetime.now() - timedelta(days=1) + stmt = select(ProcessLog).where(ProcessLog.start_time >= yesterday) + res = await db.execute(stmt) + logs = res.scalars().all() + + report = f"📊 REGGELI ROBOT JELENTÉS - {datetime.now().date()}\n" + report += "="*40 + "\n" + + total_proc = 0 + total_fail = 0 + cleaned_list = [] + + for log in logs: + total_proc += log.items_processed + total_fail += log.items_failed + if "cleaned" in log.details: + cleaned_list.extend(log.details["cleaned"]) + + report += f"✅ Feldolgozott modellek: {total_proc}\n" + report += f"❌ Hibás/Sikertelen: {total_fail}\n" + report += f"🧹 AI névtisztítások száma: {len(cleaned_list)}\n\n" + + if cleaned_list: + report += "Példák a tisztított nevekre:\n" + for item in cleaned_list[:10]: # Csak az első 10-et listázzuk + report += f" - {item}\n" + + print(report) + # Itt hívható az EmailManager.send(...) + return report + +if __name__ == "__main__": + asyncio.run(generate_morning_report()) \ No newline at end of file diff --git a/backend/app/scripts/seed_system_params.py b/backend/app/scripts/seed_system_params.py index 58d7e8e..3a27dca 100644 --- a/backend/app/scripts/seed_system_params.py +++ b/backend/app/scripts/seed_system_params.py @@ -2,7 +2,7 @@ import asyncio import json from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker -from app.models.system_config import SystemParameter +from app.models import SystemParameter from app.core.config import settings async def seed_system(): diff --git a/backend/app/scripts/seed_v1_9_system.py b/backend/app/scripts/seed_v1_9_system.py new file mode 100644 index 0000000..f46f325 --- /dev/null +++ b/backend/app/scripts/seed_v1_9_system.py @@ -0,0 +1,84 @@ +import asyncio +from sqlalchemy import select +from sqlalchemy.orm import configure_mappers +from app.db.session import SessionLocal + +# Fontos: Importálunk minden modellt a regisztrációhoz +import app.models +from app.models.vehicle_definitions import VehicleType, FeatureDefinition + +async def seed_system_data(): + # Kényszerített mapper konfiguráció a hiba ellen + try: + configure_mappers() + except Exception as e: + print(f"⚠️ Mapper figyelmeztetés (lehet, hogy már kész): {e}") + + async with SessionLocal() as db: + try: + print("🚀 Kezdődik a rendszeradatok beoltása...") + + # 1. Jármű Fajták (Blueprints) + types_data = [ + {"code": "car", "name": "Személyautó", "icon": "directions_car"}, + {"code": "motorcycle", "name": "Motorkerékpár", "icon": "moped"}, + {"code": "truck", "name": "Teherautó/Kamion", "icon": "local_shipping"}, + {"code": "bus", "name": "Autóbusz", "icon": "directions_bus"}, + {"code": "boat", "name": "Hajó/Vitorlás", "icon": "sailing"}, + {"code": "camper", "name": "Lakóautó", "icon": "rv_hookup"}, + {"code": "machinery", "name": "Munkagép", "icon": "construction"}, + {"code": "trailer", "name": "Utánfutó", "icon": "trailer"} + ] + + type_id_map = {} + for t_info in types_data: + stmt = select(VehicleType).where(VehicleType.code == t_info["code"]) + res = await db.execute(stmt) + v_type = res.scalar_one_or_none() + if not v_type: + v_type = VehicleType(**t_info) + db.add(v_type) + await db.flush() + type_id_map[t_info["code"]] = v_type.id + + # 2. Extrák (Features) betöltése - A te listád alapján + features = { + "car": [ + ("Műszaki", "ABS (blokkolásgátló)"), ("Műszaki", "ESP (menetstabilizátor)"), + ("Műszaki", "távolságtartó tempomat"), ("Beltér", "ISOFIX rendszer"), + ("Multimédia", "Android Auto"), ("Multimédia", "Apple CarPlay") + ], + "truck": [ + ("Munkavégzés", "elektromos retarder"), ("Munkavégzés", "intarder"), + ("Munkavégzés", "AdBlue"), ("Fülke", "hálófülke") + ], + "boat": [ + ("Műszaki", "orrsugárkormány"), ("Műszaki", "halradar"), + ("Műszaki", "elektromos horgonycsörlő") + ] + } + + for code, items in features.items(): + t_id = type_id_map.get(code) + if not t_id: continue + for cat, name in items: + stmt = select(FeatureDefinition).where( + FeatureDefinition.name == name, + FeatureDefinition.vehicle_type_id == t_id + ) + res = await db.execute(stmt) + if not res.scalar_one_or_none(): + db.add(FeatureDefinition( + vehicle_type_id=t_id, category=cat, name=name, data_type="boolean" + )) + + await db.commit() + print("✅ Minden alapadat (Types & Features) sikeresen betöltve!") + + except Exception as e: + await db.rollback() + print(f"❌ Végzetes hiba a feltöltés során: {e}") + raise e + +if __name__ == "__main__": + asyncio.run(seed_system_data()) \ No newline at end of file diff --git a/backend/app/services/__pycache__/cost_service.cpython-312.pyc b/backend/app/services/__pycache__/cost_service.cpython-312.pyc index cc10c9d..54bf44a 100644 Binary files a/backend/app/services/__pycache__/cost_service.cpython-312.pyc and b/backend/app/services/__pycache__/cost_service.cpython-312.pyc differ diff --git a/backend/app/services/__pycache__/gamification_service.cpython-312.pyc b/backend/app/services/__pycache__/gamification_service.cpython-312.pyc index 923b6b5..1dffbd5 100644 Binary files a/backend/app/services/__pycache__/gamification_service.cpython-312.pyc and b/backend/app/services/__pycache__/gamification_service.cpython-312.pyc differ diff --git a/backend/app/services/__pycache__/security_service.cpython-312.pyc b/backend/app/services/__pycache__/security_service.cpython-312.pyc index 8c6b61f..2d4989a 100644 Binary files a/backend/app/services/__pycache__/security_service.cpython-312.pyc and b/backend/app/services/__pycache__/security_service.cpython-312.pyc differ diff --git a/backend/app/services/ai_service.py b/backend/app/services/ai_service.py new file mode 100644 index 0000000..de1f29e --- /dev/null +++ b/backend/app/services/ai_service.py @@ -0,0 +1,72 @@ +import os +import json +import logging +import google.generativeai as genai +from typing import Dict, Any, Optional + +logger = logging.getLogger("AI-Service") + +class AIService: + # Konfiguráció a .env-ből + api_key = os.getenv("GEMINI_API_KEY") + if api_key: + genai.configure(api_key=api_key) + + # 1.5 Flash a legjobb ár/érték/sebesség arányú multimodális modell + model = genai.GenerativeModel('gemini-1.5-flash') + + @classmethod + async def get_clean_vehicle_data(cls, make: str, raw_model: str, v_type: str) -> Optional[Dict[str, Any]]: + """Robot 2: Technikai dúsítás és névtisztítás (pl. Yamaha 4HN).""" + prompt = f""" + Rendszer: Technikai gépjárműszakértő vagy. + Feladat: Tisztítsd meg a '{make} {raw_model}' ({v_type}) adatot. + Kimenet: Kizárólag JSON, magyarázat nélkül. + Formátum: + {{ + "marketing_name": "Tiszta modellnév", + "technical_code": "Modellkód/Generáció", + "ccm": int, + "kw": int, + "maintenance": {{ + "oil_type": "pl. 10W-40", + "oil_qty": float, + "spark_plug": "típus", + "coolant": "típus" + }} + }} + """ + try: + response = cls.model.generate_content(prompt) + # A Gemini néha ```json ... ``` blokkba teszi, ezt le kell tisztítani + json_text = response.text.replace("```json", "").replace("```", "").strip() + return json.loads(json_text) + except Exception as e: + logger.error(f"❌ AI Dúsítás hiba: {e}") + return None + + @classmethod + async def analyze_document_image(cls, image_data: bytes, doc_type: str) -> Optional[Dict[str, Any]]: + """Robot 3: AI OCR - Forgalmi, Személyi, Számla, KM-óra elemzés.""" + + prompts = { + "identity": "Olvasd le az okmányról: vezetéknév, keresztnév, okmányszám, lejárati idő, születési dátum.", + "vehicle_reg": "Olvasd le a forgalmiból: rendszám, alvázszám (VIN), gyártmány, típus, kw, ccm, együttes tömeg, műszaki érvényesség.", + "invoice": "Olvasd le a számláról: eladó neve/adószáma, vevő neve, bruttó összeg, dátum, tételek (alkatrész/munkadíj).", + "odometer": "Olvasd le a képen látható műszerfalról a kilométeróra vagy üzemóra állását. Csak a számot add vissza." + } + + prompt = f"Rendszer: Profi OCR és dokumentum-elemző vagy. {prompts.get(doc_type, 'Elemezd a képet.')} Válaszolj tiszta JSON formátumban." + + try: + # A Gemini közvetlenül tud fogadni bytes adatot (képként) + contents = [ + prompt, + {"mime_type": "image/jpeg", "data": image_data} + ] + response = cls.model.generate_content(contents) + json_text = response.text.replace("```json", "").replace("```", "").strip() + return json.loads(json_text) + except Exception as e: + logger.error(f"❌ AI OCR hiba ({doc_type}): {e}") + return None \ No newline at end of file diff --git a/backend/app/services/cost_service.py b/backend/app/services/cost_service.py index 7bc1d64..84aa0b8 100644 --- a/backend/app/services/cost_service.py +++ b/backend/app/services/cost_service.py @@ -4,7 +4,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, desc from app.models.asset import AssetCost, AssetTelemetry, ExchangeRate from app.models.gamification import UserStats -from app.models.system_config import SystemParameter +from app.models import SystemParameter from app.schemas.asset_cost import AssetCostCreate from datetime import datetime diff --git a/backend/app/services/gamification_service.py b/backend/app/services/gamification_service.py index 33d3000..f67d5cb 100755 --- a/backend/app/services/gamification_service.py +++ b/backend/app/services/gamification_service.py @@ -6,7 +6,7 @@ from sqlalchemy import select from app.models.gamification import UserStats, PointsLedger from app.models.identity import User, Wallet from app.models.core_logic import CreditTransaction -from app.models.system_config import SystemParameter +from app.models import SystemParameter logger = logging.getLogger(__name__) diff --git a/backend/app/services/security_service.py b/backend/app/services/security_service.py index a9737f1..a55cf11 100644 --- a/backend/app/services/security_service.py +++ b/backend/app/services/security_service.py @@ -6,7 +6,7 @@ from sqlalchemy import select, func, and_ from app.models.security import PendingAction, ActionStatus from app.models.history import AuditLog, LogSeverity from app.models.identity import User -from app.models.system_config import SystemParameter +from app.models import SystemParameter logger = logging.getLogger(__name__) diff --git a/backend/app/workers/ocr_robot.py b/backend/app/workers/ocr_robot.py new file mode 100644 index 0000000..1232e02 --- /dev/null +++ b/backend/app/workers/ocr_robot.py @@ -0,0 +1,66 @@ +import asyncio +import os +import logging +from PIL import Image +from sqlalchemy import select, update +from app.db.session import SessionLocal +from app.models.document import Document # Feltételezve +from app.models.identity import User +from app.services.ai_service import AIService + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger("Robot-OCR-V3") + +NAS_BASE_PATH = os.getenv("NAS_STORAGE_PATH", "/mnt/nas/user_vault") + +class OCRRobot: + @classmethod + async def process_queue(cls): + async with SessionLocal() as db: + # 1. Csak a várólistás és prémium jogosultságú dokumentumokat keressük + stmt = select(Document, User).join(User).where( + Document.status == "pending_ocr", + User.subscription_plan.in_(["PREMIUM_PLUS", "VIP_PLUS"]) + ).limit(10) + + res = await db.execute(stmt) + tasks = res.all() + + for doc, user in tasks: + try: + logger.info(f"📸 OCR feldolgozás: {doc.filename} (User: {user.id})") + + # 2. AI OCR hívás + with open(doc.temp_path, "rb") as f: + image_bytes = f.read() + + ocr_result = await AIService.analyze_document_image(image_bytes, doc.doc_type) + + if ocr_result: + # 3. Kép átméretezése (Thumbnail és Standard) + target_dir = os.path.join(NAS_BASE_PATH, user.folder_slug, doc.doc_type) + os.makedirs(target_dir, exist_ok=True) + + final_path = os.path.join(target_dir, f"{doc.id}.jpg") + cls.resize_and_save(doc.temp_path, final_path) + + # 4. Adatbázis frissítése + doc.ocr_data = ocr_result + doc.file_link = final_path + doc.status = "processed" + + # Ideiglenes fájl törlése + os.remove(doc.temp_path) + + await db.commit() + except Exception as e: + logger.error(f"❌ OCR Hiba ({doc.id}): {e}") + await db.rollback() + + @staticmethod + def resize_and_save(source, target): + with Image.open(source) as img: + img.convert('RGB').save(target, "JPEG", quality=85, optimize=True) + +if __name__ == "__main__": + asyncio.run(OCRRobot.process_queue()) \ No newline at end of file diff --git a/backend/app/workers/technical_enricher.py b/backend/app/workers/technical_enricher.py index 81f2f2b..ae8f243 100644 --- a/backend/app/workers/technical_enricher.py +++ b/backend/app/workers/technical_enricher.py @@ -3,17 +3,22 @@ import httpx import logging import os import datetime -from sqlalchemy import text +import json +from sqlalchemy import text, select, update from app.db.session import SessionLocal +from app.models.vehicle_definitions import VehicleModelDefinition +from app.models.audit import ProcessLog +from app.services.ai_service import AIService +from app.services.email_manager import EmailManager # Feltételezve, hogy létezik logging.basicConfig(level=logging.INFO) -logger = logging.getLogger("Robot-v1.0.4-Master-Enricher") +logger = logging.getLogger("Robot-v1.1.0-Master-Enricher") class TechEnricher: """ - Master Enricher v1.0.4 - - Target: kyri-nuah (RDW Technical Catalogue) - - Fix: Visszaállás 'merk' mezőre + SQL fix az új oszlopokhoz. + Master Enricher v1.1.0 - Hybrid RDW & AI Clean Edition + - Cél: vehicle_model_definitions (Master) tábla tisztítása és dúsítása. + - Megtartja a v1.0.4 RDW logikát, de kiegészíti AI-al a zajos adatokhoz (pl. Yamaha 4HN). """ API_URL = "https://opendata.rdw.nl/resource/kyri-nuah.json" @@ -21,105 +26,110 @@ class TechEnricher: HEADERS = {"X-App-Token": RDW_TOKEN} if RDW_TOKEN else {} @classmethod - async def fetch_tech_data(cls, make, model): - # Tisztítás: Ha a modell névben benne van a márka, levágjuk - clean_model = str(model).upper().replace(str(make).upper(), "").strip() - - # Ha a modellnév csak szám vagy túl rövid, az RDW nem fogja szeretni - if len(clean_model) < 2: - return None + def clean_num(cls, v): + try: return int(float(v)) if v else None + except: return None - # PRÓBA 1: A 'merk' mezővel (Ez a leggyakoribb) - params = { - "merk": make.upper(), - "handelsbenaming": clean_model, - "$limit": 1 - } - + @classmethod + async def fetch_rdw_tech_data(cls, make, model): + """A v1.0.4-es RDW kereső logika.""" + clean_model = str(model).upper().replace(str(make).upper(), "").strip() + if len(clean_model) < 2: return None + + params = {"merk": make.upper(), "handelsbenaming": clean_model, "$limit": 1} async with httpx.AsyncClient(headers=cls.HEADERS) as client: try: - await asyncio.sleep(1.1) + await asyncio.sleep(1.1) # RDW Rate limit védelem resp = await client.get(cls.API_URL, params=params, timeout=20) - - # Ha a 'merk' nem tetszik neki (400-as hiba), megpróbáljuk 'merknaam'-al - if resp.status_code == 400: - params = {"merknaam": make.upper(), "handelsbenaming": clean_model, "$limit": 1} - resp = await client.get(cls.TECH_API_URL, params=params, timeout=20) - if resp.status_code == 200: data = resp.json() return data[0] if data else None - return None except Exception as e: - logger.error(f"❌ API Hiba: {e}") + logger.error(f"❌ RDW API Hiba: {e}") return None @classmethod async def run(cls): - logger.info("🚀 Master Enricher v1.0.4 - Új oszlopok töltése indul...") - - while True: - async with SessionLocal() as db: - # Olyan sorokat keresünk, ahol az új oszlopok még üresek - query = text(""" - SELECT id, make, model - FROM data.vehicle_catalog - WHERE fuel_type IS NULL OR fuel_type = 'Pending' OR fuel_type LIKE 'No-Tech%' - LIMIT 20 - """) - res = await db.execute(query) - tasks = res.fetchall() + logger.info("🚀 Master Enricher v1.1.0 INDUL...") + start_time = datetime.datetime.now() + stats = {"processed": 0, "failed": 0, "cleaned": []} - if not tasks: - logger.info("😴 Minden adat kész. Alvás 5 perc...") - await asyncio.sleep(300) - continue + async with SessionLocal() as db: + # Csak azokat a Master rekordokat nézzük, amik még nincsenek hitelesítve + stmt = select(VehicleModelDefinition).where( + VehicleModelDefinition.status == "unverified" + ).limit(30) # Kisebb batch a biztonság érdekében + + res = await db.execute(stmt) + masters = res.scalars().all() - for t_id, make, model in tasks: - logger.info(f"🧪 Gazdagítás: {make} | {model}") - tech = await cls.fetch_tech_data(make, model) + if not masters: + logger.info("😴 Nincs dúsításra váró adat.") + return + + for master in masters: + try: + logger.info(f"🧪 Feldolgozás: {master.make} {master.marketing_name}") - if tech: - # RDW mezők kinyerése - kw = tech.get("netto_maximum_vermogen_kw") - ccm = tech.get("cilinderinhoud") - weight = tech.get("technisch_toelaatbare_maximum_massa") - axles = tech.get("aantal_assen") - euro = tech.get("milieuklasse_eg_goedkeuring_licht") - fuel = tech.get("brandstof_omschrijving_brandstof_stam", "Standard") + # 1. Lépés: RDW adatok lekérése (v1.0.4 logika) + rdw_data = await cls.fetch_rdw_tech_data(master.make, master.marketing_name) + + # 2. Lépés: AI segítség kérése, ha az RDW nem elég vagy a név 'zajos' (pl. 4HN) + # Ha a névben gyanús kódok vannak, az AI tisztítja meg + if not rdw_data or "(" in master.marketing_name or len(master.marketing_name) < 5: + ai_data = await AIService.get_clean_vehicle_data( + master.make, master.marketing_name, master.vehicle_type + ) + if ai_data: + old_name = master.marketing_name + master.marketing_name = ai_data.get("marketing_name", old_name) + master.technical_code = ai_data.get("technical_code", master.technical_code) + master.engine_capacity = ai_data.get("ccm", master.engine_capacity) + master.power_kw = ai_data.get("kw", master.power_kw) + master.specifications = ai_data.get("maintenance", {}) + stats["cleaned"].append(f"{old_name} -> {master.marketing_name}") - # Biztonságos konverzió - def clean_num(v): - try: return int(float(v)) if v else None - except: return None - - update_query = text(""" - UPDATE data.vehicle_catalog - SET fuel_type = :fuel, - power_kw = :kw, - engine_capacity = :ccm, - max_weight_kg = :weight, - axle_count = :axles, - euro_class = :euro, - factory_data = factory_data || jsonb_build_object('enriched_at', :now) - WHERE id = :id - """) + # Ha volt RDW adatunk, de az AI nem írta felül, töltsük be az RDW-t + if rdw_data and master.status == "unverified": + master.power_kw = cls.clean_num(rdw_data.get("netto_maximum_vermogen_kw")) + master.engine_capacity = cls.clean_num(rdw_data.get("cilinderinhoud")) + master.axle_count = cls.clean_num(rdw_data.get("aantal_assen")) - await db.execute(update_query, { - "fuel": fuel, "kw": clean_num(kw), "ccm": clean_num(ccm), - "weight": clean_num(weight), "axles": clean_num(axles), - "euro": str(euro) if euro else None, - "id": t_id, "now": str(datetime.datetime.now()) - }) - await db.commit() - logger.info(f"✅ OK: {make} {model} -> {kw}kW") - else: - # Ha nem találtuk meg, megjelöljük, hogy ne próbálkozzon újra egy darabig - await db.execute(text("UPDATE data.vehicle_catalog SET fuel_type = 'No-Tech-V4' WHERE id = :id"), {"id": t_id}) - await db.commit() + master.status = "ai_enriched" + stats["processed"] += 1 + await db.commit() - await asyncio.sleep(0.5) + except Exception as e: + logger.error(f"❌ Hiba a(z) {master.id} rekordnál: {e}") + stats["failed"] += 1 + await db.rollback() + + # 3. JELENTÉS MENTÉSE ÉS EMAIL KÜLDÉS + end_time = datetime.datetime.now() + new_log = ProcessLog( + process_name="Master-Enricher", + start_time=start_time, + end_time=end_time, + items_processed=stats["processed"], + items_failed=stats["failed"], + details=stats + ) + db.add(new_log) + await db.commit() + + # Email küldés (Dummy hívás a meglévő EmailManager-hez) + await cls.send_report_email(stats) + + @classmethod + async def send_report_email(cls, stats): + report_body = f"Reggeli Robot Jelentés - {datetime.date.today()}\n\n" + report_body += f"Sikeresen feldolgozva: {stats['processed']}\n" + report_body += f"Hibák: {stats['failed']}\n\n" + report_body += "Tisztított nevek:\n" + "\n".join(stats['cleaned']) + + logger.info("📧 Email jelentés elküldve az adminnak.") + # EmailManager.send_admin_notification("Robot Report", report_body) if __name__ == "__main__": asyncio.run(TechEnricher.run()) \ No newline at end of file diff --git a/backend/migrations/versions/495fe225e904_add_vehicle_mdm_and_audit_v1_8.py b/backend/migrations/versions/495fe225e904_add_vehicle_mdm_and_audit_v1_8.py new file mode 100644 index 0000000..5a7e410 --- /dev/null +++ b/backend/migrations/versions/495fe225e904_add_vehicle_mdm_and_audit_v1_8.py @@ -0,0 +1,302 @@ +"""add_vehicle_mdm_and_audit_v1_8 + +Revision ID: 495fe225e904 +Revises: e78ce92243ed +Create Date: 2026-02-16 19:47:33.146097 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = '495fe225e904' +down_revision: Union[str, Sequence[str], None] = 'e78ce92243ed' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Upgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('vehicle_model_definitions', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('make', sa.String(length=50), nullable=False), + sa.Column('technical_code', sa.String(length=50), nullable=False), + sa.Column('marketing_name', sa.String(length=100), nullable=True), + sa.Column('family_name', sa.String(length=100), nullable=True), + sa.Column('vehicle_type', sa.String(length=30), nullable=True), + sa.Column('vehicle_class', sa.String(length=50), nullable=True), + sa.Column('specifications', sa.JSON(), server_default=sa.text("'{}'::jsonb"), nullable=True), + sa.Column('features', sa.JSON(), server_default=sa.text("'{}'::jsonb"), nullable=True), + sa.Column('status', sa.String(length=20), server_default='unverified', nullable=True), + sa.Column('is_master', sa.Boolean(), nullable=True), + sa.Column('source', sa.String(length=50), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('make', 'technical_code', name='uix_make_tech_code'), + schema='data' + ) + op.create_index(op.f('ix_data_vehicle_model_definitions_make'), 'vehicle_model_definitions', ['make'], unique=False, schema='data') + op.create_index(op.f('ix_data_vehicle_model_definitions_marketing_name'), 'vehicle_model_definitions', ['marketing_name'], unique=False, schema='data') + op.create_index(op.f('ix_data_vehicle_model_definitions_technical_code'), 'vehicle_model_definitions', ['technical_code'], unique=False, schema='data') + op.create_index(op.f('ix_data_vehicle_model_definitions_vehicle_type'), 'vehicle_model_definitions', ['vehicle_type'], unique=False, schema='data') + op.drop_constraint(op.f('addresses_postal_code_id_fkey'), 'addresses', type_='foreignkey') + op.create_foreign_key(None, 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', type_='foreignkey') + op.drop_constraint(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', type_='foreignkey') + op.drop_constraint(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', type_='foreignkey') + op.create_foreign_key(None, 'asset_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_assignments', 'branches', ['branch_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_assignments', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_costs_organization_id_fkey'), 'asset_costs', type_='foreignkey') + op.drop_constraint(op.f('asset_costs_driver_id_fkey'), 'asset_costs', type_='foreignkey') + op.drop_constraint(op.f('asset_costs_asset_id_fkey'), 'asset_costs', type_='foreignkey') + op.create_foreign_key(None, 'asset_costs', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_costs', 'users', ['driver_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_costs', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_events_asset_id_fkey'), 'asset_events', type_='foreignkey') + op.create_foreign_key(None, 'asset_events', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_financials_asset_id_fkey'), 'asset_financials', type_='foreignkey') + op.create_foreign_key(None, 'asset_financials', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', type_='foreignkey') + op.drop_constraint(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', type_='foreignkey') + op.create_foreign_key(None, 'asset_reviews', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_reviews', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', type_='foreignkey') + op.create_foreign_key(None, 'asset_telemetry', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('assets_catalog_id_fkey'), 'assets', type_='foreignkey') + op.drop_constraint(op.f('assets_current_organization_id_fkey'), 'assets', type_='foreignkey') + op.create_foreign_key(None, 'assets', 'organizations', ['current_organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'assets', 'vehicle_catalog', ['catalog_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('audit_logs_user_id_fkey'), 'audit_logs', type_='foreignkey') + op.create_foreign_key(None, 'audit_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('branches_address_id_fkey'), 'branches', type_='foreignkey') + op.drop_constraint(op.f('branches_organization_id_fkey'), 'branches', type_='foreignkey') + op.create_foreign_key(None, 'branches', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'branches', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('credit_logs_org_id_fkey'), 'credit_logs', type_='foreignkey') + op.create_foreign_key(None, 'credit_logs', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('documents_uploaded_by_fkey'), 'documents', type_='foreignkey') + op.create_foreign_key(None, 'documents', 'users', ['uploaded_by'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('financial_ledger_related_agent_id_fkey'), 'financial_ledger', type_='foreignkey') + op.drop_constraint(op.f('financial_ledger_person_id_fkey'), 'financial_ledger', type_='foreignkey') + op.drop_constraint(op.f('financial_ledger_user_id_fkey'), 'financial_ledger', type_='foreignkey') + op.create_foreign_key(None, 'financial_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'financial_ledger', 'users', ['related_agent_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'financial_ledger', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', type_='foreignkey') + op.create_foreign_key(None, 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('operational_logs_user_id_fkey'), 'operational_logs', type_='foreignkey') + op.create_foreign_key(None, 'operational_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='SET NULL') + op.drop_constraint(op.f('org_sales_assignments_organization_id_fkey'), 'org_sales_assignments', type_='foreignkey') + op.drop_constraint(op.f('org_sales_assignments_agent_user_id_fkey'), 'org_sales_assignments', type_='foreignkey') + op.create_foreign_key(None, 'org_sales_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'org_sales_assignments', 'users', ['agent_user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', type_='foreignkey') + op.drop_constraint(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', type_='foreignkey') + op.create_foreign_key(None, 'org_subscriptions', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('organization_financials_organization_id_fkey'), 'organization_financials', type_='foreignkey') + op.create_foreign_key(None, 'organization_financials', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.alter_column('organization_members', 'role', + existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'), + type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True), + existing_nullable=True) + op.drop_constraint(op.f('organization_members_organization_id_fkey'), 'organization_members', type_='foreignkey') + op.drop_constraint(op.f('organization_members_user_id_fkey'), 'organization_members', type_='foreignkey') + op.drop_constraint(op.f('organization_members_person_id_fkey'), 'organization_members', type_='foreignkey') + op.create_foreign_key(None, 'organization_members', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'organization_members', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'organization_members', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.alter_column('organizations', 'org_type', + existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'), + type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True), + existing_nullable=True) + op.drop_constraint(op.f('organizations_owner_id_fkey'), 'organizations', type_='foreignkey') + op.drop_constraint(op.f('organizations_address_id_fkey'), 'organizations', type_='foreignkey') + op.create_foreign_key(None, 'organizations', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'organizations', 'users', ['owner_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('pending_actions_requester_id_fkey'), 'pending_actions', type_='foreignkey') + op.drop_constraint(op.f('pending_actions_approver_id_fkey'), 'pending_actions', type_='foreignkey') + op.create_foreign_key(None, 'pending_actions', 'users', ['approver_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'pending_actions', 'users', ['requester_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('persons_address_id_fkey'), 'persons', type_='foreignkey') + op.create_foreign_key(None, 'persons', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('points_ledger_user_id_fkey'), 'points_ledger', type_='foreignkey') + op.create_foreign_key(None, 'points_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('ratings_author_id_fkey'), 'ratings', type_='foreignkey') + op.create_foreign_key(None, 'ratings', 'users', ['author_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('security_audit_logs_target_id_fkey'), 'security_audit_logs', type_='foreignkey') + op.drop_constraint(op.f('security_audit_logs_actor_id_fkey'), 'security_audit_logs', type_='foreignkey') + op.drop_constraint(op.f('security_audit_logs_confirmed_by_id_fkey'), 'security_audit_logs', type_='foreignkey') + op.create_foreign_key(None, 'security_audit_logs', 'users', ['actor_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'security_audit_logs', 'users', ['confirmed_by_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'security_audit_logs', 'users', ['target_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', type_='foreignkey') + op.drop_constraint(op.f('service_expertises_service_id_fkey'), 'service_expertises', type_='foreignkey') + op.create_foreign_key(None, 'service_expertises', 'service_profiles', ['service_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('service_profiles_organization_id_fkey'), 'service_profiles', type_='foreignkey') + op.create_foreign_key(None, 'service_profiles', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('service_specialties_parent_id_fkey'), 'service_specialties', type_='foreignkey') + op.create_foreign_key(None, 'service_specialties', 'service_specialties', ['parent_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('social_accounts_user_id_fkey'), 'social_accounts', type_='foreignkey') + op.create_foreign_key(None, 'social_accounts', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE') + op.drop_constraint(op.f('user_badges_badge_id_fkey'), 'user_badges', type_='foreignkey') + op.drop_constraint(op.f('user_badges_user_id_fkey'), 'user_badges', type_='foreignkey') + op.create_foreign_key(None, 'user_badges', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'user_badges', 'badges', ['badge_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('user_stats_user_id_fkey'), 'user_stats', type_='foreignkey') + op.create_foreign_key(None, 'user_stats', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('users_person_id_fkey'), 'users', type_='foreignkey') + op.drop_constraint(op.f('users_current_sales_agent_id_fkey'), 'users', type_='foreignkey') + op.drop_constraint(op.f('users_referred_by_id_fkey'), 'users', type_='foreignkey') + op.create_foreign_key(None, 'users', 'users', ['referred_by_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'users', 'users', ['current_sales_agent_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'users', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', type_='foreignkey') + op.drop_constraint(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', type_='foreignkey') + op.create_foreign_key(None, 'vehicle_ownerships', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', type_='foreignkey') + op.create_foreign_key(None, 'verification_tokens', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE') + op.drop_constraint(op.f('wallets_user_id_fkey'), 'wallets', type_='foreignkey') + op.create_foreign_key(None, 'wallets', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(None, 'wallets', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('wallets_user_id_fkey'), 'wallets', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'verification_tokens', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', 'users', ['user_id'], ['id'], ondelete='CASCADE') + op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey') + op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id']) + op.create_foreign_key(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'users', schema='data', type_='foreignkey') + op.drop_constraint(None, 'users', schema='data', type_='foreignkey') + op.drop_constraint(None, 'users', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('users_referred_by_id_fkey'), 'users', 'users', ['referred_by_id'], ['id']) + op.create_foreign_key(op.f('users_current_sales_agent_id_fkey'), 'users', 'users', ['current_sales_agent_id'], ['id']) + op.create_foreign_key(op.f('users_person_id_fkey'), 'users', 'persons', ['person_id'], ['id']) + op.drop_constraint(None, 'user_stats', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('user_stats_user_id_fkey'), 'user_stats', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey') + op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('user_badges_user_id_fkey'), 'user_badges', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('user_badges_badge_id_fkey'), 'user_badges', 'badges', ['badge_id'], ['id']) + op.drop_constraint(None, 'social_accounts', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('social_accounts_user_id_fkey'), 'social_accounts', 'users', ['user_id'], ['id'], ondelete='CASCADE') + op.drop_constraint(None, 'service_specialties', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('service_specialties_parent_id_fkey'), 'service_specialties', 'service_specialties', ['parent_id'], ['id']) + op.drop_constraint(None, 'service_profiles', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('service_profiles_organization_id_fkey'), 'service_profiles', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey') + op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('service_expertises_service_id_fkey'), 'service_expertises', 'service_profiles', ['service_id'], ['id']) + op.create_foreign_key(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', 'expertise_tags', ['expertise_id'], ['id']) + op.drop_constraint(None, 'security_audit_logs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'security_audit_logs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'security_audit_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('security_audit_logs_confirmed_by_id_fkey'), 'security_audit_logs', 'users', ['confirmed_by_id'], ['id']) + op.create_foreign_key(op.f('security_audit_logs_actor_id_fkey'), 'security_audit_logs', 'users', ['actor_id'], ['id']) + op.create_foreign_key(op.f('security_audit_logs_target_id_fkey'), 'security_audit_logs', 'users', ['target_id'], ['id']) + op.drop_constraint(None, 'ratings', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('ratings_author_id_fkey'), 'ratings', 'users', ['author_id'], ['id']) + op.drop_constraint(None, 'points_ledger', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('points_ledger_user_id_fkey'), 'points_ledger', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'persons', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('persons_address_id_fkey'), 'persons', 'addresses', ['address_id'], ['id']) + op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey') + op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('pending_actions_approver_id_fkey'), 'pending_actions', 'users', ['approver_id'], ['id']) + op.create_foreign_key(op.f('pending_actions_requester_id_fkey'), 'pending_actions', 'users', ['requester_id'], ['id']) + op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey') + op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('organizations_address_id_fkey'), 'organizations', 'addresses', ['address_id'], ['id']) + op.create_foreign_key(op.f('organizations_owner_id_fkey'), 'organizations', 'users', ['owner_id'], ['id']) + op.alter_column('organizations', 'org_type', + existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True), + type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'), + existing_nullable=True) + op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey') + op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey') + op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('organization_members_person_id_fkey'), 'organization_members', 'persons', ['person_id'], ['id']) + op.create_foreign_key(op.f('organization_members_user_id_fkey'), 'organization_members', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('organization_members_organization_id_fkey'), 'organization_members', 'organizations', ['organization_id'], ['id']) + op.alter_column('organization_members', 'role', + existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True), + type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'), + existing_nullable=True) + op.drop_constraint(None, 'organization_financials', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('organization_financials_organization_id_fkey'), 'organization_financials', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey') + op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id']) + op.create_foreign_key(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', 'organizations', ['org_id'], ['id']) + op.drop_constraint(None, 'org_sales_assignments', schema='data', type_='foreignkey') + op.drop_constraint(None, 'org_sales_assignments', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('org_sales_assignments_agent_user_id_fkey'), 'org_sales_assignments', 'users', ['agent_user_id'], ['id']) + op.create_foreign_key(op.f('org_sales_assignments_organization_id_fkey'), 'org_sales_assignments', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'operational_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('operational_logs_user_id_fkey'), 'operational_logs', 'users', ['user_id'], ['id'], ondelete='SET NULL') + op.drop_constraint(None, 'geo_streets', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id']) + op.drop_constraint(None, 'financial_ledger', schema='data', type_='foreignkey') + op.drop_constraint(None, 'financial_ledger', schema='data', type_='foreignkey') + op.drop_constraint(None, 'financial_ledger', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('financial_ledger_user_id_fkey'), 'financial_ledger', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('financial_ledger_person_id_fkey'), 'financial_ledger', 'persons', ['person_id'], ['id']) + op.create_foreign_key(op.f('financial_ledger_related_agent_id_fkey'), 'financial_ledger', 'users', ['related_agent_id'], ['id']) + op.drop_constraint(None, 'documents', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('documents_uploaded_by_fkey'), 'documents', 'users', ['uploaded_by'], ['id']) + op.drop_constraint(None, 'credit_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('credit_logs_org_id_fkey'), 'credit_logs', 'organizations', ['org_id'], ['id']) + op.drop_constraint(None, 'branches', schema='data', type_='foreignkey') + op.drop_constraint(None, 'branches', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('branches_organization_id_fkey'), 'branches', 'organizations', ['organization_id'], ['id']) + op.create_foreign_key(op.f('branches_address_id_fkey'), 'branches', 'addresses', ['address_id'], ['id']) + op.drop_constraint(None, 'audit_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('audit_logs_user_id_fkey'), 'audit_logs', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'assets', schema='data', type_='foreignkey') + op.drop_constraint(None, 'assets', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('assets_current_organization_id_fkey'), 'assets', 'organizations', ['current_organization_id'], ['id']) + op.create_foreign_key(op.f('assets_catalog_id_fkey'), 'assets', 'vehicle_catalog', ['catalog_id'], ['id']) + op.drop_constraint(None, 'asset_telemetry', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_financials', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_financials_asset_id_fkey'), 'asset_financials', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_events', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_events_asset_id_fkey'), 'asset_events', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_costs_asset_id_fkey'), 'asset_costs', 'assets', ['asset_id'], ['id']) + op.create_foreign_key(op.f('asset_costs_driver_id_fkey'), 'asset_costs', 'users', ['driver_id'], ['id']) + op.create_foreign_key(op.f('asset_costs_organization_id_fkey'), 'asset_costs', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', 'organizations', ['organization_id'], ['id']) + op.create_foreign_key(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', 'branches', ['branch_id'], ['id']) + op.create_foreign_key(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'addresses', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('addresses_postal_code_id_fkey'), 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id']) + op.drop_index(op.f('ix_data_vehicle_model_definitions_vehicle_type'), table_name='vehicle_model_definitions', schema='data') + op.drop_index(op.f('ix_data_vehicle_model_definitions_technical_code'), table_name='vehicle_model_definitions', schema='data') + op.drop_index(op.f('ix_data_vehicle_model_definitions_marketing_name'), table_name='vehicle_model_definitions', schema='data') + op.drop_index(op.f('ix_data_vehicle_model_definitions_make'), table_name='vehicle_model_definitions', schema='data') + op.drop_table('vehicle_model_definitions', schema='data') + # ### end Alembic commands ### diff --git a/backend/migrations/versions/8f09b4b22f14_v1_9_deep_asset_catalog_and_logistics.py b/backend/migrations/versions/8f09b4b22f14_v1_9_deep_asset_catalog_and_logistics.py new file mode 100644 index 0000000..78686ed --- /dev/null +++ b/backend/migrations/versions/8f09b4b22f14_v1_9_deep_asset_catalog_and_logistics.py @@ -0,0 +1,348 @@ +"""v1_9_deep_asset_catalog_and_logistics + +Revision ID: 8f09b4b22f14 +Revises: 495fe225e904 +Create Date: 2026-02-16 22:56:12.137340 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = '8f09b4b22f14' +down_revision: Union[str, Sequence[str], None] = '495fe225e904' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Upgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('vehicle_types', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('code', sa.String(length=30), nullable=True), + sa.Column('name', sa.String(length=50), nullable=True), + sa.Column('icon', sa.String(length=50), nullable=True), + sa.Column('units', sa.JSON(), server_default=sa.text('\'{"power": "kW", "weight": "kg", "cargo": "m3"}\'::jsonb'), nullable=True), + sa.PrimaryKeyConstraint('id'), + schema='data' + ) + op.create_index(op.f('ix_data_vehicle_types_code'), 'vehicle_types', ['code'], unique=True, schema='data') + op.create_table('feature_definitions', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('vehicle_type_id', sa.Integer(), nullable=True), + sa.Column('category', sa.String(length=50), nullable=True), + sa.Column('name', sa.String(length=100), nullable=False), + sa.Column('data_type', sa.String(length=20), nullable=True), + sa.ForeignKeyConstraint(['vehicle_type_id'], ['data.vehicle_types.id'], ), + sa.PrimaryKeyConstraint('id'), + schema='data' + ) + op.create_table('model_feature_maps', + sa.Column('model_id', sa.Integer(), nullable=False), + sa.Column('feature_id', sa.Integer(), nullable=False), + sa.Column('availability', sa.String(length=20), nullable=True), + sa.Column('value', sa.String(length=100), nullable=True), + sa.ForeignKeyConstraint(['feature_id'], ['data.feature_definitions.id'], ), + sa.ForeignKeyConstraint(['model_id'], ['data.vehicle_model_definitions.id'], ), + sa.PrimaryKeyConstraint('model_id', 'feature_id'), + schema='data' + ) + op.drop_constraint(op.f('addresses_postal_code_id_fkey'), 'addresses', type_='foreignkey') + op.create_foreign_key(None, 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', type_='foreignkey') + op.drop_constraint(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', type_='foreignkey') + op.drop_constraint(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', type_='foreignkey') + op.create_foreign_key(None, 'asset_assignments', 'branches', ['branch_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_assignments', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_costs_asset_id_fkey'), 'asset_costs', type_='foreignkey') + op.drop_constraint(op.f('asset_costs_driver_id_fkey'), 'asset_costs', type_='foreignkey') + op.drop_constraint(op.f('asset_costs_organization_id_fkey'), 'asset_costs', type_='foreignkey') + op.create_foreign_key(None, 'asset_costs', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_costs', 'users', ['driver_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_costs', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_events_asset_id_fkey'), 'asset_events', type_='foreignkey') + op.create_foreign_key(None, 'asset_events', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_financials_asset_id_fkey'), 'asset_financials', type_='foreignkey') + op.create_foreign_key(None, 'asset_financials', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', type_='foreignkey') + op.drop_constraint(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', type_='foreignkey') + op.create_foreign_key(None, 'asset_reviews', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_reviews', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', type_='foreignkey') + op.create_foreign_key(None, 'asset_telemetry', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('assets_current_organization_id_fkey'), 'assets', type_='foreignkey') + op.drop_constraint(op.f('assets_catalog_id_fkey'), 'assets', type_='foreignkey') + op.create_foreign_key(None, 'assets', 'vehicle_catalog', ['catalog_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'assets', 'organizations', ['current_organization_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('audit_logs_user_id_fkey'), 'audit_logs', type_='foreignkey') + op.create_foreign_key(None, 'audit_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('branches_organization_id_fkey'), 'branches', type_='foreignkey') + op.drop_constraint(op.f('branches_address_id_fkey'), 'branches', type_='foreignkey') + op.create_foreign_key(None, 'branches', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'branches', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('credit_logs_org_id_fkey'), 'credit_logs', type_='foreignkey') + op.create_foreign_key(None, 'credit_logs', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('documents_uploaded_by_fkey'), 'documents', type_='foreignkey') + op.create_foreign_key(None, 'documents', 'users', ['uploaded_by'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('financial_ledger_person_id_fkey'), 'financial_ledger', type_='foreignkey') + op.drop_constraint(op.f('financial_ledger_related_agent_id_fkey'), 'financial_ledger', type_='foreignkey') + op.drop_constraint(op.f('financial_ledger_user_id_fkey'), 'financial_ledger', type_='foreignkey') + op.create_foreign_key(None, 'financial_ledger', 'users', ['related_agent_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'financial_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'financial_ledger', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', type_='foreignkey') + op.create_foreign_key(None, 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('operational_logs_user_id_fkey'), 'operational_logs', type_='foreignkey') + op.create_foreign_key(None, 'operational_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='SET NULL') + op.drop_constraint(op.f('org_sales_assignments_organization_id_fkey'), 'org_sales_assignments', type_='foreignkey') + op.drop_constraint(op.f('org_sales_assignments_agent_user_id_fkey'), 'org_sales_assignments', type_='foreignkey') + op.create_foreign_key(None, 'org_sales_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'org_sales_assignments', 'users', ['agent_user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', type_='foreignkey') + op.drop_constraint(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', type_='foreignkey') + op.create_foreign_key(None, 'org_subscriptions', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('organization_financials_organization_id_fkey'), 'organization_financials', type_='foreignkey') + op.create_foreign_key(None, 'organization_financials', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.alter_column('organization_members', 'role', + existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'), + type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True), + existing_nullable=True) + op.drop_constraint(op.f('organization_members_user_id_fkey'), 'organization_members', type_='foreignkey') + op.drop_constraint(op.f('organization_members_organization_id_fkey'), 'organization_members', type_='foreignkey') + op.drop_constraint(op.f('organization_members_person_id_fkey'), 'organization_members', type_='foreignkey') + op.create_foreign_key(None, 'organization_members', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'organization_members', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'organization_members', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data') + op.alter_column('organizations', 'org_type', + existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'), + type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True), + existing_nullable=True) + op.drop_constraint(op.f('organizations_owner_id_fkey'), 'organizations', type_='foreignkey') + op.drop_constraint(op.f('organizations_address_id_fkey'), 'organizations', type_='foreignkey') + op.create_foreign_key(None, 'organizations', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'organizations', 'users', ['owner_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('pending_actions_requester_id_fkey'), 'pending_actions', type_='foreignkey') + op.drop_constraint(op.f('pending_actions_approver_id_fkey'), 'pending_actions', type_='foreignkey') + op.create_foreign_key(None, 'pending_actions', 'users', ['approver_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'pending_actions', 'users', ['requester_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('persons_address_id_fkey'), 'persons', type_='foreignkey') + op.create_foreign_key(None, 'persons', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('points_ledger_user_id_fkey'), 'points_ledger', type_='foreignkey') + op.create_foreign_key(None, 'points_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('ratings_author_id_fkey'), 'ratings', type_='foreignkey') + op.create_foreign_key(None, 'ratings', 'users', ['author_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('security_audit_logs_confirmed_by_id_fkey'), 'security_audit_logs', type_='foreignkey') + op.drop_constraint(op.f('security_audit_logs_actor_id_fkey'), 'security_audit_logs', type_='foreignkey') + op.drop_constraint(op.f('security_audit_logs_target_id_fkey'), 'security_audit_logs', type_='foreignkey') + op.create_foreign_key(None, 'security_audit_logs', 'users', ['confirmed_by_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'security_audit_logs', 'users', ['actor_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'security_audit_logs', 'users', ['target_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('service_expertises_service_id_fkey'), 'service_expertises', type_='foreignkey') + op.drop_constraint(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', type_='foreignkey') + op.create_foreign_key(None, 'service_expertises', 'service_profiles', ['service_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('service_profiles_organization_id_fkey'), 'service_profiles', type_='foreignkey') + op.create_foreign_key(None, 'service_profiles', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('service_specialties_parent_id_fkey'), 'service_specialties', type_='foreignkey') + op.create_foreign_key(None, 'service_specialties', 'service_specialties', ['parent_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('social_accounts_user_id_fkey'), 'social_accounts', type_='foreignkey') + op.create_foreign_key(None, 'social_accounts', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE') + op.drop_constraint(op.f('user_badges_user_id_fkey'), 'user_badges', type_='foreignkey') + op.drop_constraint(op.f('user_badges_badge_id_fkey'), 'user_badges', type_='foreignkey') + op.create_foreign_key(None, 'user_badges', 'badges', ['badge_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'user_badges', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('user_stats_user_id_fkey'), 'user_stats', type_='foreignkey') + op.create_foreign_key(None, 'user_stats', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('users_referred_by_id_fkey'), 'users', type_='foreignkey') + op.drop_constraint(op.f('users_current_sales_agent_id_fkey'), 'users', type_='foreignkey') + op.drop_constraint(op.f('users_person_id_fkey'), 'users', type_='foreignkey') + op.create_foreign_key(None, 'users', 'users', ['referred_by_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'users', 'users', ['current_sales_agent_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'users', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data') + op.add_column('vehicle_catalog', sa.Column('master_definition_id', sa.Integer(), nullable=True)) + op.create_foreign_key(None, 'vehicle_catalog', 'vehicle_model_definitions', ['master_definition_id'], ['id'], source_schema='data', referent_schema='data') + op.add_column('vehicle_model_definitions', sa.Column('vehicle_type_id', sa.Integer(), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('engine_capacity', sa.Integer(), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('power_kw', sa.Integer(), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('max_weight_kg', sa.Integer(), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('axle_count', sa.Integer(), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('payload_capacity_kg', sa.Integer(), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('cargo_volume_m3', sa.Numeric(precision=10, scale=2), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('cargo_length_mm', sa.Integer(), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('cargo_width_mm', sa.Integer(), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('cargo_height_mm', sa.Integer(), nullable=True)) + op.add_column('vehicle_model_definitions', sa.Column('features_json', sa.JSON(), server_default=sa.text("'{}'::jsonb"), nullable=True)) + op.drop_constraint(op.f('uix_make_tech_code'), 'vehicle_model_definitions', type_='unique') + op.create_index(op.f('ix_data_vehicle_model_definitions_engine_capacity'), 'vehicle_model_definitions', ['engine_capacity'], unique=False, schema='data') + op.create_index(op.f('ix_data_vehicle_model_definitions_max_weight_kg'), 'vehicle_model_definitions', ['max_weight_kg'], unique=False, schema='data') + op.create_index(op.f('ix_data_vehicle_model_definitions_power_kw'), 'vehicle_model_definitions', ['power_kw'], unique=False, schema='data') + op.create_unique_constraint('uix_make_tech_type', 'vehicle_model_definitions', ['make', 'technical_code', 'vehicle_type'], schema='data') + op.create_foreign_key(None, 'vehicle_model_definitions', 'vehicle_types', ['vehicle_type_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_column('vehicle_model_definitions', 'features') + op.drop_constraint(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', type_='foreignkey') + op.drop_constraint(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', type_='foreignkey') + op.create_foreign_key(None, 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'vehicle_ownerships', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', type_='foreignkey') + op.create_foreign_key(None, 'verification_tokens', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE') + op.drop_constraint(op.f('wallets_user_id_fkey'), 'wallets', type_='foreignkey') + op.create_foreign_key(None, 'wallets', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(None, 'wallets', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('wallets_user_id_fkey'), 'wallets', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'verification_tokens', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', 'users', ['user_id'], ['id'], ondelete='CASCADE') + op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey') + op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id']) + op.add_column('vehicle_model_definitions', sa.Column('features', postgresql.JSON(astext_type=sa.Text()), server_default=sa.text("'{}'::jsonb"), autoincrement=False, nullable=True)) + op.drop_constraint(None, 'vehicle_model_definitions', schema='data', type_='foreignkey') + op.drop_constraint('uix_make_tech_type', 'vehicle_model_definitions', schema='data', type_='unique') + op.drop_index(op.f('ix_data_vehicle_model_definitions_power_kw'), table_name='vehicle_model_definitions', schema='data') + op.drop_index(op.f('ix_data_vehicle_model_definitions_max_weight_kg'), table_name='vehicle_model_definitions', schema='data') + op.drop_index(op.f('ix_data_vehicle_model_definitions_engine_capacity'), table_name='vehicle_model_definitions', schema='data') + op.create_unique_constraint(op.f('uix_make_tech_code'), 'vehicle_model_definitions', ['make', 'technical_code'], postgresql_nulls_not_distinct=False) + op.drop_column('vehicle_model_definitions', 'features_json') + op.drop_column('vehicle_model_definitions', 'cargo_height_mm') + op.drop_column('vehicle_model_definitions', 'cargo_width_mm') + op.drop_column('vehicle_model_definitions', 'cargo_length_mm') + op.drop_column('vehicle_model_definitions', 'cargo_volume_m3') + op.drop_column('vehicle_model_definitions', 'payload_capacity_kg') + op.drop_column('vehicle_model_definitions', 'axle_count') + op.drop_column('vehicle_model_definitions', 'max_weight_kg') + op.drop_column('vehicle_model_definitions', 'power_kw') + op.drop_column('vehicle_model_definitions', 'engine_capacity') + op.drop_column('vehicle_model_definitions', 'vehicle_type_id') + op.drop_constraint(None, 'vehicle_catalog', schema='data', type_='foreignkey') + op.drop_column('vehicle_catalog', 'master_definition_id') + op.drop_constraint(None, 'users', schema='data', type_='foreignkey') + op.drop_constraint(None, 'users', schema='data', type_='foreignkey') + op.drop_constraint(None, 'users', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('users_person_id_fkey'), 'users', 'persons', ['person_id'], ['id']) + op.create_foreign_key(op.f('users_current_sales_agent_id_fkey'), 'users', 'users', ['current_sales_agent_id'], ['id']) + op.create_foreign_key(op.f('users_referred_by_id_fkey'), 'users', 'users', ['referred_by_id'], ['id']) + op.drop_constraint(None, 'user_stats', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('user_stats_user_id_fkey'), 'user_stats', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey') + op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('user_badges_badge_id_fkey'), 'user_badges', 'badges', ['badge_id'], ['id']) + op.create_foreign_key(op.f('user_badges_user_id_fkey'), 'user_badges', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'social_accounts', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('social_accounts_user_id_fkey'), 'social_accounts', 'users', ['user_id'], ['id'], ondelete='CASCADE') + op.drop_constraint(None, 'service_specialties', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('service_specialties_parent_id_fkey'), 'service_specialties', 'service_specialties', ['parent_id'], ['id']) + op.drop_constraint(None, 'service_profiles', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('service_profiles_organization_id_fkey'), 'service_profiles', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey') + op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', 'expertise_tags', ['expertise_id'], ['id']) + op.create_foreign_key(op.f('service_expertises_service_id_fkey'), 'service_expertises', 'service_profiles', ['service_id'], ['id']) + op.drop_constraint(None, 'security_audit_logs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'security_audit_logs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'security_audit_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('security_audit_logs_target_id_fkey'), 'security_audit_logs', 'users', ['target_id'], ['id']) + op.create_foreign_key(op.f('security_audit_logs_actor_id_fkey'), 'security_audit_logs', 'users', ['actor_id'], ['id']) + op.create_foreign_key(op.f('security_audit_logs_confirmed_by_id_fkey'), 'security_audit_logs', 'users', ['confirmed_by_id'], ['id']) + op.drop_constraint(None, 'ratings', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('ratings_author_id_fkey'), 'ratings', 'users', ['author_id'], ['id']) + op.drop_constraint(None, 'points_ledger', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('points_ledger_user_id_fkey'), 'points_ledger', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'persons', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('persons_address_id_fkey'), 'persons', 'addresses', ['address_id'], ['id']) + op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey') + op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('pending_actions_approver_id_fkey'), 'pending_actions', 'users', ['approver_id'], ['id']) + op.create_foreign_key(op.f('pending_actions_requester_id_fkey'), 'pending_actions', 'users', ['requester_id'], ['id']) + op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey') + op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('organizations_address_id_fkey'), 'organizations', 'addresses', ['address_id'], ['id']) + op.create_foreign_key(op.f('organizations_owner_id_fkey'), 'organizations', 'users', ['owner_id'], ['id']) + op.alter_column('organizations', 'org_type', + existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True), + type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'), + existing_nullable=True) + op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey') + op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey') + op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('organization_members_person_id_fkey'), 'organization_members', 'persons', ['person_id'], ['id']) + op.create_foreign_key(op.f('organization_members_organization_id_fkey'), 'organization_members', 'organizations', ['organization_id'], ['id']) + op.create_foreign_key(op.f('organization_members_user_id_fkey'), 'organization_members', 'users', ['user_id'], ['id']) + op.alter_column('organization_members', 'role', + existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True), + type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'), + existing_nullable=True) + op.drop_constraint(None, 'organization_financials', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('organization_financials_organization_id_fkey'), 'organization_financials', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey') + op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id']) + op.create_foreign_key(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', 'organizations', ['org_id'], ['id']) + op.drop_constraint(None, 'org_sales_assignments', schema='data', type_='foreignkey') + op.drop_constraint(None, 'org_sales_assignments', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('org_sales_assignments_agent_user_id_fkey'), 'org_sales_assignments', 'users', ['agent_user_id'], ['id']) + op.create_foreign_key(op.f('org_sales_assignments_organization_id_fkey'), 'org_sales_assignments', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'operational_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('operational_logs_user_id_fkey'), 'operational_logs', 'users', ['user_id'], ['id'], ondelete='SET NULL') + op.drop_constraint(None, 'geo_streets', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id']) + op.drop_constraint(None, 'financial_ledger', schema='data', type_='foreignkey') + op.drop_constraint(None, 'financial_ledger', schema='data', type_='foreignkey') + op.drop_constraint(None, 'financial_ledger', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('financial_ledger_user_id_fkey'), 'financial_ledger', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('financial_ledger_related_agent_id_fkey'), 'financial_ledger', 'users', ['related_agent_id'], ['id']) + op.create_foreign_key(op.f('financial_ledger_person_id_fkey'), 'financial_ledger', 'persons', ['person_id'], ['id']) + op.drop_constraint(None, 'documents', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('documents_uploaded_by_fkey'), 'documents', 'users', ['uploaded_by'], ['id']) + op.drop_constraint(None, 'credit_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('credit_logs_org_id_fkey'), 'credit_logs', 'organizations', ['org_id'], ['id']) + op.drop_constraint(None, 'branches', schema='data', type_='foreignkey') + op.drop_constraint(None, 'branches', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('branches_address_id_fkey'), 'branches', 'addresses', ['address_id'], ['id']) + op.create_foreign_key(op.f('branches_organization_id_fkey'), 'branches', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'audit_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('audit_logs_user_id_fkey'), 'audit_logs', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'assets', schema='data', type_='foreignkey') + op.drop_constraint(None, 'assets', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('assets_catalog_id_fkey'), 'assets', 'vehicle_catalog', ['catalog_id'], ['id']) + op.create_foreign_key(op.f('assets_current_organization_id_fkey'), 'assets', 'organizations', ['current_organization_id'], ['id']) + op.drop_constraint(None, 'asset_telemetry', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_financials', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_financials_asset_id_fkey'), 'asset_financials', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_events', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_events_asset_id_fkey'), 'asset_events', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_costs_organization_id_fkey'), 'asset_costs', 'organizations', ['organization_id'], ['id']) + op.create_foreign_key(op.f('asset_costs_driver_id_fkey'), 'asset_costs', 'users', ['driver_id'], ['id']) + op.create_foreign_key(op.f('asset_costs_asset_id_fkey'), 'asset_costs', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', 'branches', ['branch_id'], ['id']) + op.create_foreign_key(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', 'organizations', ['organization_id'], ['id']) + op.create_foreign_key(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'addresses', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('addresses_postal_code_id_fkey'), 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id']) + op.drop_table('model_feature_maps', schema='data') + op.drop_table('feature_definitions', schema='data') + op.drop_index(op.f('ix_data_vehicle_types_code'), table_name='vehicle_types', schema='data') + op.drop_table('vehicle_types', schema='data') + # ### end Alembic commands ### diff --git a/backend/migrations/versions/f30c0005c446_v1_9_final_mdm_and_process_logs.py b/backend/migrations/versions/f30c0005c446_v1_9_final_mdm_and_process_logs.py new file mode 100644 index 0000000..d7896e4 --- /dev/null +++ b/backend/migrations/versions/f30c0005c446_v1_9_final_mdm_and_process_logs.py @@ -0,0 +1,309 @@ +"""v1_9_final_mdm_and_process_logs + +Revision ID: f30c0005c446 +Revises: 8f09b4b22f14 +Create Date: 2026-02-17 00:04:12.575332 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = 'f30c0005c446' +down_revision: Union[str, Sequence[str], None] = '8f09b4b22f14' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Upgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('process_logs', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('process_name', sa.String(length=100), nullable=True), + sa.Column('start_time', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('end_time', sa.DateTime(timezone=True), nullable=True), + sa.Column('items_processed', sa.Integer(), nullable=True), + sa.Column('items_failed', sa.Integer(), nullable=True), + sa.Column('details', sa.JSON(), server_default=sa.text("'{}'::jsonb"), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.PrimaryKeyConstraint('id'), + schema='data' + ) + op.create_index(op.f('ix_data_process_logs_process_name'), 'process_logs', ['process_name'], unique=False, schema='data') + op.drop_constraint(op.f('addresses_postal_code_id_fkey'), 'addresses', type_='foreignkey') + op.create_foreign_key(None, 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', type_='foreignkey') + op.drop_constraint(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', type_='foreignkey') + op.drop_constraint(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', type_='foreignkey') + op.create_foreign_key(None, 'asset_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_assignments', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_assignments', 'branches', ['branch_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_costs_driver_id_fkey'), 'asset_costs', type_='foreignkey') + op.drop_constraint(op.f('asset_costs_asset_id_fkey'), 'asset_costs', type_='foreignkey') + op.drop_constraint(op.f('asset_costs_organization_id_fkey'), 'asset_costs', type_='foreignkey') + op.create_foreign_key(None, 'asset_costs', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_costs', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_costs', 'users', ['driver_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_events_asset_id_fkey'), 'asset_events', type_='foreignkey') + op.create_foreign_key(None, 'asset_events', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_financials_asset_id_fkey'), 'asset_financials', type_='foreignkey') + op.create_foreign_key(None, 'asset_financials', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', type_='foreignkey') + op.drop_constraint(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', type_='foreignkey') + op.create_foreign_key(None, 'asset_reviews', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'asset_reviews', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', type_='foreignkey') + op.create_foreign_key(None, 'asset_telemetry', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('assets_current_organization_id_fkey'), 'assets', type_='foreignkey') + op.drop_constraint(op.f('assets_catalog_id_fkey'), 'assets', type_='foreignkey') + op.create_foreign_key(None, 'assets', 'vehicle_catalog', ['catalog_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'assets', 'organizations', ['current_organization_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('audit_logs_user_id_fkey'), 'audit_logs', type_='foreignkey') + op.create_foreign_key(None, 'audit_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('branches_organization_id_fkey'), 'branches', type_='foreignkey') + op.drop_constraint(op.f('branches_address_id_fkey'), 'branches', type_='foreignkey') + op.create_foreign_key(None, 'branches', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'branches', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('credit_logs_org_id_fkey'), 'credit_logs', type_='foreignkey') + op.create_foreign_key(None, 'credit_logs', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('documents_uploaded_by_fkey'), 'documents', type_='foreignkey') + op.create_foreign_key(None, 'documents', 'users', ['uploaded_by'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('feature_definitions_vehicle_type_id_fkey'), 'feature_definitions', type_='foreignkey') + op.create_foreign_key(None, 'feature_definitions', 'vehicle_types', ['vehicle_type_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('financial_ledger_person_id_fkey'), 'financial_ledger', type_='foreignkey') + op.drop_constraint(op.f('financial_ledger_user_id_fkey'), 'financial_ledger', type_='foreignkey') + op.drop_constraint(op.f('financial_ledger_related_agent_id_fkey'), 'financial_ledger', type_='foreignkey') + op.create_foreign_key(None, 'financial_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'financial_ledger', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'financial_ledger', 'users', ['related_agent_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', type_='foreignkey') + op.create_foreign_key(None, 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('model_feature_maps_model_id_fkey'), 'model_feature_maps', type_='foreignkey') + op.drop_constraint(op.f('model_feature_maps_feature_id_fkey'), 'model_feature_maps', type_='foreignkey') + op.create_foreign_key(None, 'model_feature_maps', 'feature_definitions', ['feature_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'model_feature_maps', 'vehicle_model_definitions', ['model_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('operational_logs_user_id_fkey'), 'operational_logs', type_='foreignkey') + op.create_foreign_key(None, 'operational_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='SET NULL') + op.drop_constraint(op.f('org_sales_assignments_organization_id_fkey'), 'org_sales_assignments', type_='foreignkey') + op.drop_constraint(op.f('org_sales_assignments_agent_user_id_fkey'), 'org_sales_assignments', type_='foreignkey') + op.create_foreign_key(None, 'org_sales_assignments', 'users', ['agent_user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'org_sales_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', type_='foreignkey') + op.drop_constraint(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', type_='foreignkey') + op.create_foreign_key(None, 'org_subscriptions', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('organization_financials_organization_id_fkey'), 'organization_financials', type_='foreignkey') + op.create_foreign_key(None, 'organization_financials', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.alter_column('organization_members', 'role', + existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'), + type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True), + existing_nullable=True) + op.drop_constraint(op.f('organization_members_user_id_fkey'), 'organization_members', type_='foreignkey') + op.drop_constraint(op.f('organization_members_organization_id_fkey'), 'organization_members', type_='foreignkey') + op.drop_constraint(op.f('organization_members_person_id_fkey'), 'organization_members', type_='foreignkey') + op.create_foreign_key(None, 'organization_members', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'organization_members', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'organization_members', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.alter_column('organizations', 'org_type', + existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'), + type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True), + existing_nullable=True) + op.drop_constraint(op.f('organizations_owner_id_fkey'), 'organizations', type_='foreignkey') + op.drop_constraint(op.f('organizations_address_id_fkey'), 'organizations', type_='foreignkey') + op.create_foreign_key(None, 'organizations', 'users', ['owner_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'organizations', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('pending_actions_requester_id_fkey'), 'pending_actions', type_='foreignkey') + op.drop_constraint(op.f('pending_actions_approver_id_fkey'), 'pending_actions', type_='foreignkey') + op.create_foreign_key(None, 'pending_actions', 'users', ['approver_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'pending_actions', 'users', ['requester_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('persons_address_id_fkey'), 'persons', type_='foreignkey') + op.create_foreign_key(None, 'persons', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('points_ledger_user_id_fkey'), 'points_ledger', type_='foreignkey') + op.create_foreign_key(None, 'points_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('ratings_author_id_fkey'), 'ratings', type_='foreignkey') + op.create_foreign_key(None, 'ratings', 'users', ['author_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('security_audit_logs_target_id_fkey'), 'security_audit_logs', type_='foreignkey') + op.drop_constraint(op.f('security_audit_logs_actor_id_fkey'), 'security_audit_logs', type_='foreignkey') + op.drop_constraint(op.f('security_audit_logs_confirmed_by_id_fkey'), 'security_audit_logs', type_='foreignkey') + op.create_foreign_key(None, 'security_audit_logs', 'users', ['confirmed_by_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'security_audit_logs', 'users', ['target_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'security_audit_logs', 'users', ['actor_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('service_expertises_service_id_fkey'), 'service_expertises', type_='foreignkey') + op.drop_constraint(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', type_='foreignkey') + op.create_foreign_key(None, 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'service_expertises', 'service_profiles', ['service_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('service_profiles_organization_id_fkey'), 'service_profiles', type_='foreignkey') + op.create_foreign_key(None, 'service_profiles', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('service_specialties_parent_id_fkey'), 'service_specialties', type_='foreignkey') + op.create_foreign_key(None, 'service_specialties', 'service_specialties', ['parent_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('social_accounts_user_id_fkey'), 'social_accounts', type_='foreignkey') + op.create_foreign_key(None, 'social_accounts', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE') + op.drop_constraint(op.f('user_badges_badge_id_fkey'), 'user_badges', type_='foreignkey') + op.drop_constraint(op.f('user_badges_user_id_fkey'), 'user_badges', type_='foreignkey') + op.create_foreign_key(None, 'user_badges', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'user_badges', 'badges', ['badge_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('user_stats_user_id_fkey'), 'user_stats', type_='foreignkey') + op.create_foreign_key(None, 'user_stats', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('users_referred_by_id_fkey'), 'users', type_='foreignkey') + op.drop_constraint(op.f('users_person_id_fkey'), 'users', type_='foreignkey') + op.drop_constraint(op.f('users_current_sales_agent_id_fkey'), 'users', type_='foreignkey') + op.create_foreign_key(None, 'users', 'users', ['referred_by_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'users', 'users', ['current_sales_agent_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'users', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('vehicle_catalog_master_definition_id_fkey'), 'vehicle_catalog', type_='foreignkey') + op.create_foreign_key(None, 'vehicle_catalog', 'vehicle_model_definitions', ['master_definition_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('vehicle_model_definitions_vehicle_type_id_fkey'), 'vehicle_model_definitions', type_='foreignkey') + op.create_foreign_key(None, 'vehicle_model_definitions', 'vehicle_types', ['vehicle_type_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', type_='foreignkey') + op.drop_constraint(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', type_='foreignkey') + op.create_foreign_key(None, 'vehicle_ownerships', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + op.create_foreign_key(None, 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'], source_schema='data', referent_schema='data') + op.drop_constraint(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', type_='foreignkey') + op.create_foreign_key(None, 'verification_tokens', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE') + op.drop_constraint(op.f('wallets_user_id_fkey'), 'wallets', type_='foreignkey') + op.create_foreign_key(None, 'wallets', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data') + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(None, 'wallets', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('wallets_user_id_fkey'), 'wallets', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'verification_tokens', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', 'users', ['user_id'], ['id'], ondelete='CASCADE') + op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey') + op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id']) + op.create_foreign_key(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'vehicle_model_definitions', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('vehicle_model_definitions_vehicle_type_id_fkey'), 'vehicle_model_definitions', 'vehicle_types', ['vehicle_type_id'], ['id']) + op.drop_constraint(None, 'vehicle_catalog', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('vehicle_catalog_master_definition_id_fkey'), 'vehicle_catalog', 'vehicle_model_definitions', ['master_definition_id'], ['id']) + op.drop_constraint(None, 'users', schema='data', type_='foreignkey') + op.drop_constraint(None, 'users', schema='data', type_='foreignkey') + op.drop_constraint(None, 'users', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('users_current_sales_agent_id_fkey'), 'users', 'users', ['current_sales_agent_id'], ['id']) + op.create_foreign_key(op.f('users_person_id_fkey'), 'users', 'persons', ['person_id'], ['id']) + op.create_foreign_key(op.f('users_referred_by_id_fkey'), 'users', 'users', ['referred_by_id'], ['id']) + op.drop_constraint(None, 'user_stats', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('user_stats_user_id_fkey'), 'user_stats', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey') + op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('user_badges_user_id_fkey'), 'user_badges', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('user_badges_badge_id_fkey'), 'user_badges', 'badges', ['badge_id'], ['id']) + op.drop_constraint(None, 'social_accounts', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('social_accounts_user_id_fkey'), 'social_accounts', 'users', ['user_id'], ['id'], ondelete='CASCADE') + op.drop_constraint(None, 'service_specialties', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('service_specialties_parent_id_fkey'), 'service_specialties', 'service_specialties', ['parent_id'], ['id']) + op.drop_constraint(None, 'service_profiles', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('service_profiles_organization_id_fkey'), 'service_profiles', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey') + op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', 'expertise_tags', ['expertise_id'], ['id']) + op.create_foreign_key(op.f('service_expertises_service_id_fkey'), 'service_expertises', 'service_profiles', ['service_id'], ['id']) + op.drop_constraint(None, 'security_audit_logs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'security_audit_logs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'security_audit_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('security_audit_logs_confirmed_by_id_fkey'), 'security_audit_logs', 'users', ['confirmed_by_id'], ['id']) + op.create_foreign_key(op.f('security_audit_logs_actor_id_fkey'), 'security_audit_logs', 'users', ['actor_id'], ['id']) + op.create_foreign_key(op.f('security_audit_logs_target_id_fkey'), 'security_audit_logs', 'users', ['target_id'], ['id']) + op.drop_constraint(None, 'ratings', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('ratings_author_id_fkey'), 'ratings', 'users', ['author_id'], ['id']) + op.drop_constraint(None, 'points_ledger', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('points_ledger_user_id_fkey'), 'points_ledger', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'persons', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('persons_address_id_fkey'), 'persons', 'addresses', ['address_id'], ['id']) + op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey') + op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('pending_actions_approver_id_fkey'), 'pending_actions', 'users', ['approver_id'], ['id']) + op.create_foreign_key(op.f('pending_actions_requester_id_fkey'), 'pending_actions', 'users', ['requester_id'], ['id']) + op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey') + op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('organizations_address_id_fkey'), 'organizations', 'addresses', ['address_id'], ['id']) + op.create_foreign_key(op.f('organizations_owner_id_fkey'), 'organizations', 'users', ['owner_id'], ['id']) + op.alter_column('organizations', 'org_type', + existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True), + type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'), + existing_nullable=True) + op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey') + op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey') + op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('organization_members_person_id_fkey'), 'organization_members', 'persons', ['person_id'], ['id']) + op.create_foreign_key(op.f('organization_members_organization_id_fkey'), 'organization_members', 'organizations', ['organization_id'], ['id']) + op.create_foreign_key(op.f('organization_members_user_id_fkey'), 'organization_members', 'users', ['user_id'], ['id']) + op.alter_column('organization_members', 'role', + existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True), + type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'), + existing_nullable=True) + op.drop_constraint(None, 'organization_financials', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('organization_financials_organization_id_fkey'), 'organization_financials', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey') + op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', 'organizations', ['org_id'], ['id']) + op.create_foreign_key(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id']) + op.drop_constraint(None, 'org_sales_assignments', schema='data', type_='foreignkey') + op.drop_constraint(None, 'org_sales_assignments', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('org_sales_assignments_agent_user_id_fkey'), 'org_sales_assignments', 'users', ['agent_user_id'], ['id']) + op.create_foreign_key(op.f('org_sales_assignments_organization_id_fkey'), 'org_sales_assignments', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'operational_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('operational_logs_user_id_fkey'), 'operational_logs', 'users', ['user_id'], ['id'], ondelete='SET NULL') + op.drop_constraint(None, 'model_feature_maps', schema='data', type_='foreignkey') + op.drop_constraint(None, 'model_feature_maps', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('model_feature_maps_feature_id_fkey'), 'model_feature_maps', 'feature_definitions', ['feature_id'], ['id']) + op.create_foreign_key(op.f('model_feature_maps_model_id_fkey'), 'model_feature_maps', 'vehicle_model_definitions', ['model_id'], ['id']) + op.drop_constraint(None, 'geo_streets', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id']) + op.drop_constraint(None, 'financial_ledger', schema='data', type_='foreignkey') + op.drop_constraint(None, 'financial_ledger', schema='data', type_='foreignkey') + op.drop_constraint(None, 'financial_ledger', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('financial_ledger_related_agent_id_fkey'), 'financial_ledger', 'users', ['related_agent_id'], ['id']) + op.create_foreign_key(op.f('financial_ledger_user_id_fkey'), 'financial_ledger', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('financial_ledger_person_id_fkey'), 'financial_ledger', 'persons', ['person_id'], ['id']) + op.drop_constraint(None, 'feature_definitions', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('feature_definitions_vehicle_type_id_fkey'), 'feature_definitions', 'vehicle_types', ['vehicle_type_id'], ['id']) + op.drop_constraint(None, 'documents', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('documents_uploaded_by_fkey'), 'documents', 'users', ['uploaded_by'], ['id']) + op.drop_constraint(None, 'credit_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('credit_logs_org_id_fkey'), 'credit_logs', 'organizations', ['org_id'], ['id']) + op.drop_constraint(None, 'branches', schema='data', type_='foreignkey') + op.drop_constraint(None, 'branches', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('branches_address_id_fkey'), 'branches', 'addresses', ['address_id'], ['id']) + op.create_foreign_key(op.f('branches_organization_id_fkey'), 'branches', 'organizations', ['organization_id'], ['id']) + op.drop_constraint(None, 'audit_logs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('audit_logs_user_id_fkey'), 'audit_logs', 'users', ['user_id'], ['id']) + op.drop_constraint(None, 'assets', schema='data', type_='foreignkey') + op.drop_constraint(None, 'assets', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('assets_catalog_id_fkey'), 'assets', 'vehicle_catalog', ['catalog_id'], ['id']) + op.create_foreign_key(op.f('assets_current_organization_id_fkey'), 'assets', 'organizations', ['current_organization_id'], ['id']) + op.drop_constraint(None, 'asset_telemetry', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', 'users', ['user_id'], ['id']) + op.create_foreign_key(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_financials', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_financials_asset_id_fkey'), 'asset_financials', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_events', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_events_asset_id_fkey'), 'asset_events', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_costs_organization_id_fkey'), 'asset_costs', 'organizations', ['organization_id'], ['id']) + op.create_foreign_key(op.f('asset_costs_asset_id_fkey'), 'asset_costs', 'assets', ['asset_id'], ['id']) + op.create_foreign_key(op.f('asset_costs_driver_id_fkey'), 'asset_costs', 'users', ['driver_id'], ['id']) + op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey') + op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', 'branches', ['branch_id'], ['id']) + op.create_foreign_key(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', 'organizations', ['organization_id'], ['id']) + op.create_foreign_key(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', 'assets', ['asset_id'], ['id']) + op.drop_constraint(None, 'addresses', schema='data', type_='foreignkey') + op.create_foreign_key(op.f('addresses_postal_code_id_fkey'), 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id']) + op.drop_index(op.f('ix_data_process_logs_process_name'), table_name='process_logs', schema='data') + op.drop_table('process_logs', schema='data') + # ### end Alembic commands ### diff --git a/backend/requirements.txt b/backend/requirements.txt index 65886c0..889f894 100755 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -23,4 +23,5 @@ itsdangerous fastapi-limiter==0.1.5 pyotp cryptography -GeoAlchemy2>=0.14.0 \ No newline at end of file +GeoAlchemy2>=0.14.0 +google-generativeai \ No newline at end of file