243 lines
11 KiB
Python
243 lines
11 KiB
Python
# /opt/docker/dev/service_finder/backend/app/schemas/fleet_finance.py
|
|
"""
|
|
Pydantic sémák a flotta pénzügyi modelljeihez.
|
|
- AssetFinancials: Beszerzés, finanszírozás, értékcsökkenés
|
|
- InsuranceProvider: Biztosítók katalógusa
|
|
- VehicleInsurancePolicy: Jármű biztosítási kötvények
|
|
- VehicleTaxObligation: Jármű adókötelezettségek
|
|
"""
|
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
from typing import Optional, Dict, Any, List
|
|
from uuid import UUID
|
|
from datetime import datetime, date
|
|
|
|
|
|
# =============================================================================
|
|
# AssetFinancials sémák
|
|
# =============================================================================
|
|
|
|
class AssetFinancialsUpdate(BaseModel):
|
|
"""AssetFinancials frissítése - minden mező opcionális."""
|
|
purchase_price_net: Optional[float] = Field(None, ge=0, description="Nettó vételár")
|
|
purchase_price_gross: Optional[float] = Field(None, ge=0, description="Bruttó vételár")
|
|
vat_rate: Optional[float] = Field(None, ge=0, le=100, description="ÁFA kulcs (%)")
|
|
activation_date: Optional[datetime] = Field(None, description="Aktiválás dátuma")
|
|
verified_purchase_date: Optional[datetime] = Field(None, description="Ellenőrzött vásárlási dátum")
|
|
financing_type: Optional[str] = Field(None, max_length=50, description="Finanszírozás típusa (cash, loan, lease)")
|
|
accounting_details: Optional[Dict[str, Any]] = Field(None, description="Számviteli részletek (JSONB)")
|
|
|
|
# Finanszírozás
|
|
down_payment: Optional[float] = Field(None, ge=0, description="Önerő")
|
|
monthly_installment: Optional[float] = Field(None, ge=0, description="Havi törlesztő")
|
|
residual_value: Optional[float] = Field(None, ge=0, description="Maradványérték")
|
|
contract_number: Optional[str] = Field(None, max_length=100, description="Szerződésszám")
|
|
financing_provider: Optional[str] = Field(None, max_length=200, description="Finanszírozó")
|
|
interest_rate: Optional[float] = Field(None, ge=0, le=100, description="Kamatláb (%)")
|
|
total_contract_value: Optional[float] = Field(None, ge=0, description="Teljes szerződéses érték")
|
|
lease_start_date: Optional[date] = Field(None, description="Lízing kezdete")
|
|
lease_end_date: Optional[date] = Field(None, description="Lízing vége")
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class AssetFinancialsResponse(BaseModel):
|
|
"""AssetFinancials teljes válaszmodell."""
|
|
id: int
|
|
asset_id: UUID
|
|
|
|
# Beszerzés
|
|
purchase_price_net: float
|
|
purchase_price_gross: float
|
|
vat_rate: float
|
|
activation_date: Optional[datetime] = None
|
|
verified_purchase_date: Optional[datetime] = None
|
|
financing_type: str
|
|
accounting_details: Dict[str, Any] = Field(default_factory=dict)
|
|
|
|
# Finanszírozás
|
|
down_payment: Optional[float] = None
|
|
monthly_installment: Optional[float] = None
|
|
residual_value: Optional[float] = None
|
|
contract_number: Optional[str] = None
|
|
financing_provider: Optional[str] = None
|
|
interest_rate: Optional[float] = None
|
|
total_contract_value: Optional[float] = None
|
|
lease_start_date: Optional[date] = None
|
|
lease_end_date: Optional[date] = None
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
# =============================================================================
|
|
# InsuranceProvider sémák
|
|
# =============================================================================
|
|
|
|
class InsuranceProviderResponse(BaseModel):
|
|
"""Biztosító teljes válaszmodell."""
|
|
id: int
|
|
name: str
|
|
country_code: Optional[str] = Field(None, max_length=2, description="ISO 3166-1 alpha-2 országkód (pl. 'HU'). Ha None, akkor globális.")
|
|
claim_phone: Optional[str] = None
|
|
claim_url: Optional[str] = None
|
|
services_offered: Dict[str, Any] = Field(default_factory=dict)
|
|
is_active: bool = True
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class InsuranceProviderCreate(BaseModel):
|
|
"""Új biztosító létrehozása."""
|
|
name: str = Field(..., min_length=1, max_length=150, description="Biztosító neve")
|
|
country_code: Optional[str] = Field(None, max_length=2, description="ISO 3166-1 alpha-2 országkód (pl. 'HU'). Ha None, akkor globális.")
|
|
claim_phone: Optional[str] = Field(None, max_length=50, description="Kárbejelentő telefonszám")
|
|
claim_url: Optional[str] = Field(None, max_length=255, description="Kárbejelentő URL")
|
|
services_offered: Optional[Dict[str, Any]] = Field(None, description="Kínált szolgáltatások (JSONB)")
|
|
is_active: bool = Field(default=True, description="Aktív-e")
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class InsuranceProviderUpdate(BaseModel):
|
|
"""Biztosító frissítése - minden mező opcionális."""
|
|
name: Optional[str] = Field(None, min_length=1, max_length=150, description="Biztosító neve")
|
|
country_code: Optional[str] = Field(None, max_length=2, description="ISO 3166-1 alpha-2 országkód (pl. 'HU'). Ha None, akkor globális.")
|
|
claim_phone: Optional[str] = Field(None, max_length=50, description="Kárbejelentő telefonszám")
|
|
claim_url: Optional[str] = Field(None, max_length=255, description="Kárbejelentő URL")
|
|
services_offered: Optional[Dict[str, Any]] = Field(None, description="Kínált szolgáltatások (JSONB)")
|
|
is_active: Optional[bool] = Field(None, description="Aktív-e")
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
# =============================================================================
|
|
# VehicleInsurancePolicy sémák
|
|
# =============================================================================
|
|
|
|
class VehicleInsurancePolicyCreate(BaseModel):
|
|
"""Új biztosítási kötvény létrehozása."""
|
|
provider_id: int = Field(..., description="Biztosító ID (insurance_providers tábla)")
|
|
insurance_type: str = Field(..., max_length=20, description="Biztosítás típusa (KGFB, CASCO)")
|
|
policy_number: str = Field(..., max_length=100, description="Kötvényszám")
|
|
start_date: date = Field(..., description="Biztosítás kezdete")
|
|
expiry_date: date = Field(..., description="Biztosítás lejárata")
|
|
premium_amount: float = Field(..., ge=0, description="Díj összege")
|
|
currency: str = Field(default="HUF", max_length=3, description="Pénznem")
|
|
document_id: Optional[UUID] = Field(None, description="Kapcsolódó dokumentum ID (PDF kötvény)")
|
|
|
|
@field_validator('insurance_type')
|
|
@classmethod
|
|
def validate_insurance_type(cls, v: str) -> str:
|
|
"""insurance_type csak KGFB vagy CASCO lehet."""
|
|
allowed = {"KGFB", "CASCO"}
|
|
cleaned = v.strip().upper()
|
|
if cleaned not in allowed:
|
|
raise ValueError(f'A biztosítás típusa csak {allowed} lehet, kapott: "{v}"')
|
|
return cleaned
|
|
|
|
@field_validator('expiry_date')
|
|
@classmethod
|
|
def validate_expiry_after_start(cls, v: date, info):
|
|
"""expiry_date nem lehet a start_date előtt."""
|
|
values = info.data
|
|
start = values.get('start_date')
|
|
if start and v <= start:
|
|
raise ValueError('A biztosítás lejárati dátuma nem lehet a kezdő dátum előtt vagy azzal egyenlő')
|
|
return v
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class VehicleInsurancePolicyUpdate(BaseModel):
|
|
"""Biztosítási kötvény frissítése - minden mező opcionális."""
|
|
provider_id: Optional[int] = Field(None, description="Biztosító ID")
|
|
insurance_type: Optional[str] = Field(None, max_length=20, description="Biztosítás típusa")
|
|
policy_number: Optional[str] = Field(None, max_length=100, description="Kötvényszám")
|
|
start_date: Optional[date] = Field(None, description="Biztosítás kezdete")
|
|
expiry_date: Optional[date] = Field(None, description="Biztosítás lejárata")
|
|
premium_amount: Optional[float] = Field(None, ge=0, description="Díj összege")
|
|
currency: Optional[str] = Field(None, max_length=3, description="Pénznem")
|
|
document_id: Optional[UUID] = Field(None, description="Kapcsolódó dokumentum ID (PDF kötvény)")
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class VehicleInsurancePolicyResponse(BaseModel):
|
|
"""Biztosítási kötvény teljes válaszmodell."""
|
|
id: UUID
|
|
asset_id: UUID
|
|
provider_id: int
|
|
insurance_type: str
|
|
policy_number: str
|
|
start_date: date
|
|
expiry_date: date
|
|
premium_amount: float
|
|
currency: str
|
|
document_id: Optional[UUID] = None
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
# =============================================================================
|
|
# VehicleTaxObligation sémák
|
|
# =============================================================================
|
|
|
|
class VehicleTaxObligationCreate(BaseModel):
|
|
"""Új adókötelezettség létrehozása."""
|
|
tax_type: str = Field(..., max_length=30, description="Adó típusa (WEIGHT_TAX, COMPANY_CAR_TAX)")
|
|
tax_year: int = Field(..., ge=2000, le=2100, description="Adóév")
|
|
amount: float = Field(..., ge=0, description="Adó összege")
|
|
currency: str = Field(default="HUF", max_length=3, description="Pénznem")
|
|
due_date: Optional[date] = Field(None, description="Fizetési határidő")
|
|
payment_status: str = Field(default="pending", max_length=20, description="Fizetési státusz")
|
|
document_id: Optional[UUID] = Field(None, description="Kapcsolódó dokumentum ID (PDF adóbevallás)")
|
|
|
|
@field_validator('tax_type')
|
|
@classmethod
|
|
def validate_tax_type(cls, v: str) -> str:
|
|
"""tax_type csak WEIGHT_TAX vagy COMPANY_CAR_TAX lehet."""
|
|
allowed = {"WEIGHT_TAX", "COMPANY_CAR_TAX"}
|
|
cleaned = v.strip().upper()
|
|
if cleaned not in allowed:
|
|
raise ValueError(f'Az adó típusa csak {allowed} lehet, kapott: "{v}"')
|
|
return cleaned
|
|
|
|
@field_validator('payment_status')
|
|
@classmethod
|
|
def validate_payment_status(cls, v: str) -> str:
|
|
"""payment_status csak pending, paid, overdue lehet."""
|
|
allowed = {"pending", "paid", "overdue"}
|
|
cleaned = v.strip().lower()
|
|
if cleaned not in allowed:
|
|
raise ValueError(f'A fizetési státusz csak {allowed} lehet, kapott: "{v}"')
|
|
return cleaned
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class VehicleTaxObligationUpdate(BaseModel):
|
|
"""Adókötelezettség frissítése - minden mező opcionális."""
|
|
tax_type: Optional[str] = Field(None, max_length=30, description="Adó típusa")
|
|
tax_year: Optional[int] = Field(None, ge=2000, le=2100, description="Adóév")
|
|
amount: Optional[float] = Field(None, ge=0, description="Adó összege")
|
|
currency: Optional[str] = Field(None, max_length=3, description="Pénznem")
|
|
due_date: Optional[date] = Field(None, description="Fizetési határidő")
|
|
payment_status: Optional[str] = Field(None, max_length=20, description="Fizetési státusz")
|
|
document_id: Optional[UUID] = Field(None, description="Kapcsolódó dokumentum ID (PDF adóbevallás)")
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class VehicleTaxObligationResponse(BaseModel):
|
|
"""Adókötelezettség teljes válaszmodell."""
|
|
id: UUID
|
|
asset_id: UUID
|
|
tax_type: str
|
|
tax_year: int
|
|
amount: float
|
|
currency: str
|
|
due_date: Optional[date] = None
|
|
payment_status: str
|
|
document_id: Optional[UUID] = None
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|