# /opt/docker/dev/service_finder/backend/app/schemas/asset_event.py from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Optional, Dict, Any, List from uuid import UUID from datetime import datetime from enum import Enum class AssetEventTypeEnum(str, Enum): """Digitális Szervizkönyv eseménytípusok.""" SERVICE = "SERVICE" # Szerviz REPAIR = "REPAIR" # Javítás ACCIDENT = "ACCIDENT" # Baleset INSPECTION = "INSPECTION" # Műszaki vizsga TIRE_CHANGE = "TIRE_CHANGE" # Gumi csere MAINTENANCE = "MAINTENANCE" # Karbantartás UPGRADE = "UPGRADE" # Fejlesztés RECALL = "RECALL" # Visszahívás OTHER = "OTHER" # Egyéb class AssetEventStatusEnum(str, Enum): """Esemény státuszok a feldolgozási munkafolyamathoz.""" DRAFT = "DRAFT" MISSING_TECH_DATA = "MISSING_TECH_DATA" COMPLETED = "COMPLETED" class AssetEventCreate(BaseModel): """Digitális Szervizkönyv esemény létrehozásához szükséges adatok.""" event_type: AssetEventTypeEnum = Field(..., description="Esemény típusa") odometer_reading: Optional[int] = Field(None, ge=0, description="Km óra állás az eseménykor") description: str = Field(..., min_length=1, max_length=1000, description="Esemény leírása") event_date: Optional[datetime] = Field(None, description="Esemény dátuma (alapértelmezett: most)") cost_id: Optional[UUID] = Field(None, description="Kapcsolódó költség rekord ID (opcionális)") cost_amount: Optional[float] = Field(None, gt=0, description="Költség összege. Ha > 0, automatikusan létrejön egy AssetCost rekord.") currency: Optional[str] = Field(None, min_length=3, max_length=3, description="Valutakód (pl. HUF, EUR)") status: Optional[AssetEventStatusEnum] = Field(None, description="Esemény státusz (auto-set by backend)") linked_expense_id: Optional[UUID] = Field(None, description="Kapcsolódó AssetCost ID (kétirányú hivatkozáshoz)") model_config = ConfigDict(from_attributes=True) class AssetEventResponse(BaseModel): """Digitális Szervizkönyv esemény teljes válaszmodellje.""" id: UUID asset_id: UUID user_id: Optional[int] = None organization_id: Optional[int] = None event_type: str odometer_reading: Optional[int] = None description: Optional[str] = None cost_id: Optional[UUID] = None cost_amount: Optional[float] = Field(None, description="Auto-created cost amount") currency: Optional[str] = Field(None, description="Currency code (e.g. HUF)") # Új mezők status: str = "DRAFT" linked_expense_id: Optional[UUID] = None event_date: datetime created_at: datetime updated_at: Optional[datetime] = None # Kapcsolódó entitások (opcionális, csak ha eager loadoltuk) user_name: Optional[str] = Field(None, description="Felhasználó neve") organization_name: Optional[str] = Field(None, description="Szervezet neve") model_config = ConfigDict(from_attributes=True) @classmethod def model_validate(cls, obj, **kwargs): """Override to resolve cost_amount and currency from the related AssetCost. GROSS-FIRST: cost_amount resolves from amount_gross (Bruttó) as primary source. """ data = {} if hasattr(obj, '__dict__'): # Copy ORM attributes for field in cls.model_fields: if hasattr(obj, field): data[field] = getattr(obj, field) # Resolve cost_amount and currency from the cost relationship cost = getattr(obj, 'cost', None) if cost is not None: if data.get('cost_amount') is None: # GROSS-FIRST: prefer amount_gross as the source of truth data['cost_amount'] = float(cost.amount_gross) if cost.amount_gross is not None else ( float(cost.amount_net) if cost.amount_net is not None else None ) if data.get('currency') is None: data['currency'] = cost.currency return cls(**data) class AssetEventUpdate(BaseModel): """Digitális Szervizkönyv esemény frissítéséhez szükséges adatok.""" event_type: Optional[AssetEventTypeEnum] = Field(None, description="Esemény típusa") odometer_reading: Optional[int] = Field(None, ge=0, description="Km óra állás az eseménykor") description: Optional[str] = Field(None, min_length=1, max_length=1000, description="Esemény leírása") event_date: Optional[datetime] = Field(None, description="Esemény dátuma") cost_id: Optional[UUID] = Field(None, description="Kapcsolódó költség rekord ID") status: Optional[AssetEventStatusEnum] = Field(None, description="Esemény státusz") linked_expense_id: Optional[UUID] = Field(None, description="Kapcsolódó AssetCost ID") @field_validator('description') @classmethod def validate_description(cls, v): if v is not None and len(v.strip()) == 0: raise ValueError('Description cannot be empty or whitespace only') return v model_config = ConfigDict(from_attributes=True) class AssetEventListResponse(BaseModel): """Digitális Szervizkönyv események listázásának válasza.""" items: List[AssetEventResponse] = Field(default_factory=list) total: int = Field(0, description="Összes esemény száma") page: int = Field(1, description="Aktuális oldal") page_size: int = Field(20, description="Oldalméret") model_config = ConfigDict(from_attributes=True)