from __future__ import annotations from datetime import date, datetime from pydantic import BaseModel, ConfigDict, field_validator, model_validator from models import ResourceType, ScenarioStatus from services.currency import CurrencyValidationError, normalise_currency class ScenarioBase(BaseModel): name: str description: str | None = None status: ScenarioStatus = ScenarioStatus.DRAFT start_date: date | None = None end_date: date | None = None discount_rate: float | None = None currency: str | None = None primary_resource: ResourceType | None = None model_config = ConfigDict(extra="forbid") @field_validator("currency") @classmethod def normalise_currency(cls, value: str | None) -> str | None: if value is None: return None candidate = value if isinstance(value, str) else str(value) candidate = candidate.strip() if not candidate: return None try: return normalise_currency(candidate) except CurrencyValidationError as exc: raise ValueError(str(exc)) from exc class ScenarioCreate(ScenarioBase): pass class ScenarioUpdate(BaseModel): name: str | None = None description: str | None = None status: ScenarioStatus | None = None start_date: date | None = None end_date: date | None = None discount_rate: float | None = None currency: str | None = None primary_resource: ResourceType | None = None model_config = ConfigDict(extra="forbid") @field_validator("currency") @classmethod def normalise_currency(cls, value: str | None) -> str | None: if value is None: return None candidate = value if isinstance(value, str) else str(value) candidate = candidate.strip() if not candidate: return None try: return normalise_currency(candidate) except CurrencyValidationError as exc: raise ValueError(str(exc)) from exc class ScenarioRead(ScenarioBase): id: int project_id: int created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True) class ScenarioComparisonRequest(BaseModel): scenario_ids: list[int] model_config = ConfigDict(extra="forbid") @model_validator(mode="after") def ensure_minimum_ids(self) -> "ScenarioComparisonRequest": unique_ids: list[int] = list(dict.fromkeys(self.scenario_ids)) if len(unique_ids) < 2: raise ValueError( "At least two unique scenario identifiers are required for comparison.") self.scenario_ids = unique_ids return self class ScenarioComparisonResponse(BaseModel): project_id: int scenarios: list[ScenarioRead] model_config = ConfigDict(from_attributes=True)