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:
43
services/currency.py
Normal file
43
services/currency.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from __future__ import annotations
|
||||
|
||||
"""Utilities for currency normalization within pricing and financial workflows."""
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
|
||||
VALID_CURRENCY_PATTERN = re.compile(r"^[A-Z]{3}$")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CurrencyValidationError(ValueError):
|
||||
"""Raised when a currency code fails validation."""
|
||||
|
||||
code: str
|
||||
|
||||
def __str__(self) -> str: # pragma: no cover - dataclass repr not required in tests
|
||||
return f"Invalid currency code: {self.code!r}"
|
||||
|
||||
|
||||
def normalise_currency(code: str | None) -> str | None:
|
||||
"""Normalise currency codes to uppercase ISO-4217 values."""
|
||||
|
||||
if code is None:
|
||||
return None
|
||||
candidate = code.strip().upper()
|
||||
if not VALID_CURRENCY_PATTERN.match(candidate):
|
||||
raise CurrencyValidationError(candidate)
|
||||
return candidate
|
||||
|
||||
|
||||
def require_currency(code: str | None, default: str | None = None) -> str:
|
||||
"""Return normalised currency code, falling back to default when missing."""
|
||||
|
||||
normalised = normalise_currency(code)
|
||||
if normalised is not None:
|
||||
return normalised
|
||||
if default is None:
|
||||
raise CurrencyValidationError("<missing currency>")
|
||||
fallback = normalise_currency(default)
|
||||
if fallback is None:
|
||||
raise CurrencyValidationError("<invalid default currency>")
|
||||
return fallback
|
||||
Reference in New Issue
Block a user