Files
calminer/services/currency.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

44 lines
1.3 KiB
Python

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