"""Pydantic schemas for API request/response validation.""" from datetime import datetime from pydantic import BaseModel, Field # ── Auth ── class AdminLogin(BaseModel): email: str password: str class CitizenVerify(BaseModel): commune_slug: str auth_code: str class Token(BaseModel): access_token: str token_type: str = "bearer" role: str commune_slug: str | None = None # ── Commune ── class CommuneCreate(BaseModel): name: str slug: str description: str = "" class CommuneUpdate(BaseModel): name: str | None = None description: str | None = None is_active: bool | None = None vote_deadline: datetime | None = None class CommuneOut(BaseModel): id: int name: str slug: str description: str is_active: bool created_at: datetime vote_deadline: datetime | None = None model_config = {"from_attributes": True} # ── TariffParams ── class TariffParamsUpdate(BaseModel): abop: float | None = None abos: float | None = None recettes: float | None = None pmax: float | None = None vmax: float | None = None data_year: int | None = None class TariffParamsOut(BaseModel): abop: float abos: float recettes: float pmax: float vmax: float data_year: int | None = None data_imported_at: datetime | None = None model_config = {"from_attributes": True} # ── Household ── class HouseholdOut(BaseModel): id: int identifier: str status: str volume_m3: float price_paid_eur: float auth_code: str has_voted: bool model_config = {"from_attributes": True} class HouseholdStats(BaseModel): total: int rs_count: int rp_count: int pro_count: int total_volume: float avg_volume: float median_volume: float voted_count: int data_year: int | None = None data_imported_at: datetime | None = None class ImportPreview(BaseModel): valid_rows: int errors: list[str] sample: list[dict] class ImportResult(BaseModel): created: int errors: list[str] # ── Tariff Compute ── class TariffComputeRequest(BaseModel): commune_slug: str vinf: float = Field(ge=0) a: float = Field(ge=0, le=1) b: float = Field(ge=0, le=1) c: float = Field(ge=0, le=1) d: float = Field(ge=0, le=1) e: float = Field(ge=0, le=1) class ImpactRowOut(BaseModel): volume: float old_price: float new_price_rp: float new_price_rs: float class TariffComputeResponse(BaseModel): p0: float curve_volumes: list[float] curve_prices_m3: list[float] curve_bills_rp: list[float] curve_bills_rs: list[float] impacts: list[ImpactRowOut] # ── Vote ── class VoteCreate(BaseModel): vinf: float = Field(ge=0) a: float = Field(ge=0, le=1) b: float = Field(ge=0, le=1) c: float = Field(ge=0, le=1) d: float = Field(ge=0, le=1) e: float = Field(ge=0, le=1) class VoteOut(BaseModel): id: int household_id: int vinf: float a: float b: float c: float d: float e: float computed_p0: float | None submitted_at: datetime is_active: bool model_config = {"from_attributes": True} class MedianOut(BaseModel): vinf: float a: float b: float c: float d: float e: float computed_p0: float vote_count: int # ── Admin User ── class AdminUserCreate(BaseModel): email: str password: str full_name: str = "" role: str = "commune_admin" commune_slugs: list[str] = [] class AdminUserOut(BaseModel): id: int email: str full_name: str role: str model_config = {"from_attributes": True} # ── Content ── class ContentUpdate(BaseModel): title: str body_markdown: str class ContentOut(BaseModel): slug: str title: str body_markdown: str updated_at: datetime model_config = {"from_attributes": True}