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.
This commit is contained in:
@@ -5,6 +5,7 @@ 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):
|
||||
@@ -23,11 +24,15 @@ class ScenarioBase(BaseModel):
|
||||
@classmethod
|
||||
def normalise_currency(cls, value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return value
|
||||
value = value.upper()
|
||||
if len(value) != 3:
|
||||
raise ValueError("Currency code must be a 3-letter ISO value")
|
||||
return value
|
||||
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):
|
||||
@@ -50,11 +55,15 @@ class ScenarioUpdate(BaseModel):
|
||||
@classmethod
|
||||
def normalise_currency(cls, value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return value
|
||||
value = value.upper()
|
||||
if len(value) != 3:
|
||||
raise ValueError("Currency code must be a 3-letter ISO value")
|
||||
return value
|
||||
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):
|
||||
@@ -75,7 +84,8 @@ class ScenarioComparisonRequest(BaseModel):
|
||||
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.")
|
||||
raise ValueError(
|
||||
"At least two unique scenario identifiers are required for comparison.")
|
||||
self.scenario_ids = unique_ids
|
||||
return self
|
||||
|
||||
|
||||
Reference in New Issue
Block a user