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:
@@ -6,16 +6,21 @@ from typing import Callable, Sequence
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from config.database import SessionLocal
|
||||
from models import Role, Scenario
|
||||
from models import PricingSettings, Project, Role, Scenario
|
||||
from services.pricing import PricingMetadata
|
||||
from services.repositories import (
|
||||
FinancialInputRepository,
|
||||
PricingSettingsRepository,
|
||||
PricingSettingsSeedResult,
|
||||
ProjectRepository,
|
||||
RoleRepository,
|
||||
ScenarioRepository,
|
||||
SimulationParameterRepository,
|
||||
UserRepository,
|
||||
ensure_admin_user as ensure_admin_user_record,
|
||||
ensure_default_pricing_settings,
|
||||
ensure_default_roles,
|
||||
pricing_settings_to_metadata,
|
||||
)
|
||||
from services.scenario_validation import ScenarioComparisonValidator
|
||||
|
||||
@@ -33,6 +38,7 @@ class UnitOfWork(AbstractContextManager["UnitOfWork"]):
|
||||
self.simulation_parameters: SimulationParameterRepository | None = None
|
||||
self.users: UserRepository | None = None
|
||||
self.roles: RoleRepository | None = None
|
||||
self.pricing_settings: PricingSettingsRepository | None = None
|
||||
|
||||
def __enter__(self) -> "UnitOfWork":
|
||||
self.session = self._session_factory()
|
||||
@@ -43,6 +49,7 @@ class UnitOfWork(AbstractContextManager["UnitOfWork"]):
|
||||
self.session)
|
||||
self.users = UserRepository(self.session)
|
||||
self.roles = RoleRepository(self.session)
|
||||
self.pricing_settings = PricingSettingsRepository(self.session)
|
||||
self._scenario_validator = ScenarioComparisonValidator()
|
||||
return self
|
||||
|
||||
@@ -60,6 +67,7 @@ class UnitOfWork(AbstractContextManager["UnitOfWork"]):
|
||||
self.simulation_parameters = None
|
||||
self.users = None
|
||||
self.roles = None
|
||||
self.pricing_settings = None
|
||||
|
||||
def flush(self) -> None:
|
||||
if not self.session:
|
||||
@@ -116,3 +124,45 @@ class UnitOfWork(AbstractContextManager["UnitOfWork"]):
|
||||
username=username,
|
||||
password=password,
|
||||
)
|
||||
|
||||
def ensure_default_pricing_settings(
|
||||
self,
|
||||
*,
|
||||
metadata: PricingMetadata,
|
||||
slug: str = "default",
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
) -> PricingSettingsSeedResult:
|
||||
if not self.pricing_settings:
|
||||
raise RuntimeError("UnitOfWork session is not initialised")
|
||||
return ensure_default_pricing_settings(
|
||||
self.pricing_settings,
|
||||
metadata=metadata,
|
||||
slug=slug,
|
||||
name=name,
|
||||
description=description,
|
||||
)
|
||||
|
||||
def get_pricing_metadata(
|
||||
self,
|
||||
*,
|
||||
slug: str = "default",
|
||||
) -> PricingMetadata | None:
|
||||
if not self.pricing_settings:
|
||||
raise RuntimeError("UnitOfWork session is not initialised")
|
||||
settings = self.pricing_settings.find_by_slug(
|
||||
slug,
|
||||
include_children=True,
|
||||
)
|
||||
if settings is None:
|
||||
return None
|
||||
return pricing_settings_to_metadata(settings)
|
||||
|
||||
def set_project_pricing_settings(
|
||||
self,
|
||||
project: Project,
|
||||
pricing_settings: PricingSettings | None,
|
||||
) -> Project:
|
||||
if not self.projects:
|
||||
raise RuntimeError("UnitOfWork session is not initialised")
|
||||
return self.projects.set_pricing_settings(project, pricing_settings)
|
||||
|
||||
Reference in New Issue
Block a user