"""Currency normalization service: convert foreign amounts to EUR.Provides :class:`ExchangeRateProvider` — the protocol an exchange-ratebackend must implement — and :class:`CurrencyNormalizationService`, whichapplies a provider-supplied rate to produce a :class:`NormalizedAmount`(from ``._models``). When no provider is configured or no rate isavailable the service returns a ``NormalizedAmount`` with``status = CurrencyNormalizationStatus.MISSING_RATE`` so callers cansurface a human-readable warning rather than silently propagating a zeroamount into a filing (modelo = an AEAT tax form)."""from__future__importannotationsfromdatetimeimportdatefromdecimalimportDecimalfromtypingimportProtocolfrom...core.external_constantsimportDEFAULT_CURRENCYfrom._modelsimport(CurrencyNormalizationStatus,MonetaryAmount,NormalizedAmount,)
[docs]classExchangeRateProvider(Protocol):"""Protocol for fetching exchange rates."""
[docs]defget_eur_rate(self,currency:str,rate_date:date)->Decimal|None:"""Get the exchange rate to EUR for a given currency and date. Returns the rate such that original_amount * rate = eur_amount. Returns None if no rate is available. """...
[docs]classCurrencyNormalizationService:"""Service to normalize foreign currencies to EUR."""def__init__(self,rate_provider:ExchangeRateProvider|None=None)->None:self._rate_provider=rate_provider
[docs]defnormalize(self,amount:MonetaryAmount,rate_date:date)->NormalizedAmount:"""Normalize an amount to EUR using the rate for the given date. Returns: A :class:`NormalizedAmount` with the EUR-equivalent and conversion metadata. """ifamount.currency==DEFAULT_CURRENCY:returnNormalizedAmount(original=amount,eur_amount=amount.amount,status=CurrencyNormalizationStatus.NATIVE_EUR,rate=Decimal("1.0"),rate_source="native",rate_date=rate_date,)ifnotself._rate_provider:returnNormalizedAmount(original=amount,eur_amount=Decimal("0.0"),status=CurrencyNormalizationStatus.MISSING_RATE,)rate=self._rate_provider.get_eur_rate(amount.currency,rate_date)ifrateisNone:returnNormalizedAmount(original=amount,eur_amount=Decimal("0.0"),status=CurrencyNormalizationStatus.MISSING_RATE,)eur_amount=amount.amount*ratereturnNormalizedAmount(original=amount,eur_amount=eur_amount.quantize(Decimal("0.01")),status=CurrencyNormalizationStatus.NORMALIZED,rate=rate,rate_source="provider",rate_date=rate_date,)