from datetime import date, datetime from decimal import Decimal from pydantic import BaseModel, ConfigDict, model_validator from app.models.expense import ServiceType class FuelEntryBase(BaseModel): entry_date: date odometer: int liters: Decimal price_per_liter: Decimal total_cost: Decimal | None = None station: str | None = None fuel_brand: str | None = None is_full_tank: bool = True notes: str | None = None @model_validator(mode="after") def fill_total_cost(self) -> "FuelEntryBase": if self.total_cost is None: self.total_cost = self.liters * self.price_per_liter return self class FuelEntryCreate(FuelEntryBase): car_id: int class FuelEntryUpdate(BaseModel): entry_date: date | None = None odometer: int | None = None liters: Decimal | None = None price_per_liter: Decimal | None = None total_cost: Decimal | None = None station: str | None = None fuel_brand: str | None = None is_full_tank: bool | None = None notes: str | None = None class FuelEntryRead(FuelEntryBase): id: int car_id: int total_cost: Decimal created_at: datetime model_config = ConfigDict(from_attributes=True) class ServiceEntryBase(BaseModel): entry_date: date odometer: int | None = None service_type: ServiceType title: str category: str | None = None vendor: str | None = None total_cost: Decimal next_due_date: date | None = None next_due_odometer: int | None = None notes: str | None = None class ServiceEntryCreate(ServiceEntryBase): car_id: int class ServiceEntryUpdate(BaseModel): entry_date: date | None = None odometer: int | None = None service_type: ServiceType | None = None title: str | None = None category: str | None = None vendor: str | None = None total_cost: Decimal | None = None next_due_date: date | None = None next_due_odometer: int | None = None notes: str | None = None class ServiceEntryRead(ServiceEntryBase): id: int car_id: int created_at: datetime model_config = ConfigDict(from_attributes=True) class OwnershipStats(BaseModel): car_id: int date_from: date date_to: date fuel_cost: Decimal service_cost: Decimal total_cost: Decimal liters: Decimal distance_km: int avg_consumption_l_per_100km: float | None cost_per_km: float | None fuel_entries_count: int service_entries_count: int class OdometerPrediction(BaseModel): car_id: int samples: int current_odometer: int | None predicted_today: int | None predicted_30_days: int | None avg_km_per_day: float | None avg_km_per_month: float | None current_price_per_liter: float | None = None predicted_price_per_liter_30_days: float | None = None avg_price_per_liter: float | None = None price_samples: int = 0 price_confidence: float = 0 confidence: float insight: str