Files
calminer/schemas/scenario.py
zwitschi 795a9f99f4 feat: Enhance currency handling and validation across scenarios
- Updated form template to prefill currency input with default value and added help text for clarity.
- Modified integration tests to assert more descriptive error messages for invalid currency codes.
- Introduced new tests for currency normalization and validation in various scenarios, including imports and exports.
- Added comprehensive tests for pricing calculations, ensuring defaults are respected and overrides function correctly.
- Implemented unit tests for pricing settings repository, ensuring CRUD operations and default settings are handled properly.
- Enhanced scenario pricing evaluation tests to validate currency handling and metadata defaults.
- Added simulation tests to ensure Monte Carlo runs are accurate and handle various distribution scenarios.
2025-11-11 18:29:59 +01:00

98 lines
2.8 KiB
Python

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)