Files
service-finder/backend/app/schemas/asset_event.py

119 lines
5.5 KiB
Python

# /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)