# /opt/docker/dev/service_finder/backend/app/schemas/asset.py from pydantic import BaseModel, ConfigDict, Field, validator from typing import Optional, Dict, Any, List from uuid import UUID from datetime import datetime class AssetCatalogResponse(BaseModel): """ A technikai katalógus (Master Data) teljes adattartalma. """ id: int make: str model: str generation: Optional[str] = None engine_variant: Optional[str] = None year_from: Optional[int] = None year_to: Optional[int] = None vehicle_class: Optional[str] = None fuel_type: Optional[str] = None # Technikai paraméterek az automatizáláshoz power_kw: Optional[int] = None engine_capacity: Optional[int] = None max_weight_kg: Optional[int] = None axle_count: Optional[int] = None euro_class: Optional[str] = None body_type: Optional[str] = None engine_code: Optional[str] = None factory_data: Dict[str, Any] = Field(default_factory=dict) model_config = ConfigDict(from_attributes=True) class AssetResponse(BaseModel): """ A konkrét járműpéldány (Asset) teljes válaszmodellje - Thick Digital Twin. """ # === IDENTIFICATION === id: UUID vin: Optional[str] = Field(None, min_length=1, max_length=50) license_plate: Optional[str] = None name: Optional[str] = None catalog_id: Optional[int] = None # === CLASSIFICATION === vehicle_class: Optional[str] = None brand: Optional[str] = None model: Optional[str] = None trim_level: Optional[str] = None # === TECHNICAL SPECS === fuel_type: Optional[str] = None engine_capacity: Optional[int] = None power_kw: Optional[int] = None torque_nm: Optional[int] = None cylinder_layout: Optional[str] = None transmission_type: Optional[str] = None drive_type: Optional[str] = None euro_classification: Optional[str] = None # === PHYSICAL DIMENSIONS === curb_weight: Optional[int] = None max_weight: Optional[int] = None cargo_volume_x: Optional[float] = None cargo_volume_y: Optional[float] = None door_count: Optional[int] = None seat_count: Optional[int] = None # === EQUIPMENT === roof_type: Optional[str] = None audio_system_type: Optional[str] = None individual_equipment: Dict[str, Any] = Field(default_factory=dict) # === STATUS === current_mileage: int = Field(default=0) condition_score: int = Field(default=100) status: str data_status: Optional[str] = None is_verified: bool verification_method: Optional[str] = None catalog_match_score: Optional[float] = None # === TIMELINE === year_of_manufacture: Optional[int] = None first_registration_date: Optional[datetime] = None created_at: datetime updated_at: Optional[datetime] = None # === SALES MODULE === is_for_sale: bool = Field(default=False) price: Optional[float] = None currency: str = Field(default="EUR") # === ORGANIZATION & LOCATION === current_organization_id: Optional[int] = None branch_id: Optional[UUID] = None relocation_performed: bool = Field(default=False) # === IDENTITY RELATIONSHIPS === owner_organization_id: Optional[int] = None operator_person_id: Optional[int] = None owner_person_id: Optional[int] = None operator_org_id: Optional[int] = None # === CATALOG RELATIONSHIP === catalog: Optional[AssetCatalogResponse] = None # === PROFILE COMPLETION === profile_completion_percentage: int = Field(default=0, ge=0, le=100) model_config = ConfigDict(from_attributes=True) class AssetCreate(BaseModel): """ Jármű létrehozásához szükséges adatok - Thick Digital Twin támogatással. """ # === CORE IDENTIFICATION (Required for status determination) === license_plate: str = Field(..., min_length=2, max_length=20, description="Rendszám") vin: Optional[str] = Field(None, min_length=1, max_length=50, description="VIN szám (opcionális)") # === CLASSIFICATION (Optional, but affects status) === brand: Optional[str] = Field(None, max_length=100, description="Márka (ha nincs catalog_id)") model: Optional[str] = Field(None, max_length=100, description="Modell (ha nincs catalog_id)") vehicle_class: Optional[str] = Field(None, max_length=50, description="Járműosztály") fuel_type: Optional[str] = Field(None, max_length=50, description="Üzemanyag típus") # === TECHNICAL SPECS (Optional) === catalog_id: Optional[int] = Field(None, description="Opcionális katalógus ID (ha ismert a modell)") engine_capacity: Optional[int] = Field(None, ge=0, description="Hengerűrtartalom (cm³)") power_kw: Optional[int] = Field(None, ge=0, description="Teljesítmény (kW)") torque_nm: Optional[int] = Field(None, ge=0, description="Nyomaték (Nm)") cylinder_layout: Optional[str] = Field(None, max_length=50, description="Hengerelrendezés") transmission_type: Optional[str] = Field(None, max_length=50, description="Váltó típus") drive_type: Optional[str] = Field(None, max_length=50, description="Hajtás") euro_classification: Optional[str] = Field(None, max_length=10, description="EURO besorolás") # === PHYSICAL DIMENSIONS (Optional) === curb_weight: Optional[int] = Field(None, ge=0, description="Saját tömeg (kg)") max_weight: Optional[int] = Field(None, ge=0, description="Össztömeg (kg)") cargo_volume_x: Optional[float] = Field(None, ge=0, description="Csomagtartó hossz (cm)") cargo_volume_y: Optional[float] = Field(None, ge=0, description="Csomagtartó szélesség (cm)") door_count: Optional[int] = Field(None, ge=0, description="Ajtók száma") seat_count: Optional[int] = Field(None, ge=0, description="Ülések száma") # === EQUIPMENT (Optional) === trim_level: Optional[str] = Field(None, max_length=100, description="Felszereltségi szint") roof_type: Optional[str] = Field(None, max_length=50, description="Tető típus") audio_system_type: Optional[str] = Field(None, max_length=100, description="Hangrendszer") individual_equipment: Dict[str, Any] = Field(default_factory=dict, description="Egyedi felszerelések") # === TIMELINE (Optional) === year_of_manufacture: Optional[int] = Field(None, ge=1900, le=2100, description="Gyártási év") first_registration_date: Optional[datetime] = Field(None, description="Első forgalomba helyezés dátuma") # === ORGANIZATION (Optional) === organization_id: Optional[int] = Field(None, description="Szervezet ID (alapértelmezett a felhasználó szervezete)") # === STATUS VALIDATION === @validator('status', pre=True, always=True) def determine_status(cls, v, values): """Automatikus státusz meghatározás az adatkomplettség alapján.""" if v is not None: return v # Ellenőrizzük az 5 alapvető mezőt required_fields = ['license_plate', 'brand', 'model', 'vehicle_class', 'fuel_type'] has_all_required = all( values.get(field) is not None and str(values.get(field)).strip() != '' for field in required_fields ) return "active" if has_all_required else "draft" # === COMPUTED FIELD: status === status: Optional[str] = Field(None, description="Automatikusan számított státusz (draft/active)") model_config = ConfigDict(from_attributes=True)