cadrumo.domain.currency.service module¶
Currency normalization service: convert foreign amounts to EUR.
Provides ExchangeRateProvider — the protocol an exchange-rate
backend must implement — and CurrencyNormalizationService, which
applies a provider-supplied rate to produce a NormalizedAmount
(from ._models). When no provider is configured or no rate is
available the service returns a NormalizedAmount with
status = CurrencyNormalizationStatus.MISSING_RATE so callers can
surface a human-readable warning rather than silently propagating a zero
amount into a filing (modelo = an AEAT tax form).
- class ExchangeRateProvider(*args, **kwargs)[source]¶
Bases:
ProtocolProtocol for fetching exchange rates.
- property rate_source_id: str¶
Stable identifier for the rate authority this provider speaks for.
Stamped onto every converted record so a stored euro figure names the series it came from. Required rather than optional: a provider that cannot say who it is produces conversions nothing can later audit, and a default here would put that anonymity one attribute away.
- class CurrencyNormalizationService(rate_provider=None)[source]¶
Bases:
objectService to normalize foreign currencies to EUR.
- Parameters:
rate_provider (ExchangeRateProvider | None)
- normalize(amount, rate_date)[source]¶
Normalize an amount to EUR using the rate for the given date.
- Return type:
- Returns:
A
NormalizedAmountwith the EUR-equivalent and conversion metadata.- Parameters:
amount (MonetaryAmount)
rate_date (date)
- resolve_fx_conversion_stamp(*, currency, on_date, rate_provider)[source]¶
Return the euro-conversion stamp for a foreign-currency record, or
None.The single authority for the stamping policy: which date the rate is taken at, when a record is left unstamped, and what an unresolvable rate means. The rate SOURCE was already centralised behind
ExchangeRateProvider; this centralises the decision made around it, which had been hand-declared at two application call sites.Conversion happens at the record’s own operation date — the issue or invoice date — because that is the date Spanish law binds the official rate to (Ley 46/1998 art. 36), and because converting once at ingest keeps a stored euro figure stable rather than drifting with every later read.
A euro record is left unstamped: there is nothing to convert, and a
1-valued stamp would assert a conversion that never happened. A foreign record whose rate cannot be resolved is ALSO left unstamped rather than defaulted, and that is the load-bearing half of this policy. Without a stamp the record reports no euro value and is held back from projection, which an operator can see and correct; a fabricated or assumed rate would instead flow silently into a filed euro amount, and nothing downstream could tell it from a real one.- Parameters:
currency (
str) – The record’s currency. Compared case-insensitively against the euro token, so a caller that has not yet normalised it is safe.on_date (
date) – The operation date to take the rate at.rate_provider (
ExchangeRateProvider) – The rate source. Required rather than defaulted: the default ECB provider is an outbound adapter, and this layer must not reach for it.
- Return type:
- Returns:
The
FxConversionStampto apply, orNonewhen the record must be left unstamped — euro, or no resolvable rate. The stamp names the provider’s rate authority, so the record says not only what rate was applied and when, but on whose published series.