cadrumo.domain.iva.lookup module

Lookup helpers for IVA registry data.

lookup_rate() resolves EUMemberState and IvaRateKind queries into IvaRateRecord records projected from governed-fact authority results; rate_table_covers() answers whether the table reaches a date at all; coexisting_tier_rates() and rate_kinds_for_declared_rate() report the tiers a date carries.

resolve_iva_rate(member_state, kind, on_date, *, rate_role=None, operation)[source]

Resolve one dated IVA rate fact and retain the complete authority provenance.

Return type:

ResolvedMappingFact

Parameters:
lookup_rate(member_state, kind, on_date, *, operation)[source]

Return the cadrumo.domain.iva.schema.IvaRateRecord matching the supplied query.

Resolves the ordinary governed-fact variant for the exact member-state, tier, and devengo-date coordinates, then projects it onto the established public record.

Parameters:
  • member_state (EUMemberState) – The EU member state whose rate is requested.

  • kind (IvaRateKind) – The rate tier (general / reduced / …).

  • on_date (date) – The effective date for the lookup.

  • operation (PinnedAuthorityOperation) – Caller-owned pinned authority operation for the complete lookup.

Return type:

IvaRateRecord

Returns:

The matching cadrumo.domain.iva.schema.IvaRateRecord.

Raises:

IvaRateNotFoundError – If no registered rate satisfies the query.

rate_table_covers(member_state, on_date, kind=None, *, operation)[source]

Return whether a tier-defining rate for member_state reaches on_date.

Coverage is PER TIER, and asking “any tier” answers a different question. The registry can hold a zero-tier record for a date while the general tier has none – which is exactly the 2023 state after the RDL 20/2022 food rows landed. A caller resolving a 21 % line on such a date would be told the table covers it, fall through to the legality branch, and be handed the false “was not in force” claim again. Pass kind whenever the caller knows which tier it is asking about; None keeps the broad “can anything classify here” reading the ledger preflight wants.

Separates the two reasons a rate lookup fails, which are not the same fact and must not produce the same message. The registry’s ES coverage begins in 2023 for the RDL 20/2022 food windows and 2024 for the standing tiers, so a 2022 general-rate line fails not because its rate was unlawful – Spain’s 21 % has stood since 2012 – but because the table does not reach back that far. Whether the standing tiers’ own start dates are correct is a separate open question: they assert 2024 for rates in force well before it.

Telling a filer their rate “was not in force” when it plainly was sends them to correct a figure that was right, and invites widening the table with a guessed value. A regulatory value needs its own binding provision cited and corpus-backed, so a truthful refusal is the correct behaviour until those rows are authored.

Reads only TIER-DEFINING records, skipping the coexisting temporary ones, because a date covered solely by a temporary window would misreport as uncovered. That cannot arise today – every temporary window sits inside a year the tier-defining records already span – and it is the safe direction regardless: the worse outcome is a refusal naming the rate rather than the year, not a line silently priced.

Parameters:
  • member_state (EUMemberState) – The member state whose table is queried.

  • on_date (date) – The date to test for coverage.

  • kind (IvaRateKind | None) – Restrict the question to one tier. None asks whether any tier-defining rate covers on_date, which is a different and weaker claim – see above.

  • operation (PinnedAuthorityOperation) – Caller-owned pinned authority operation for the complete coverage query.

Return type:

bool

Returns:

True when a tier-defining rate for kind (or for any tier when kind is None) covers on_date.

rate_table_covers_any_positive_tier(member_state, on_date, *, operation)[source]

Return whether any POSITIVE ordinary tier is priced for member_state on on_date.

The question a caller resolving a positive declared rate must ask. A declared zero always classifies through the zero-tier exemption, so the zero tier’s own coverage says nothing about whether a positive rate could have been priced. Counting it made a 2023 date look covered the moment the RDL 20/2022 food rows landed – restoring the “unsupported rate” message on exactly the dates the coverage wording was written for.

Lives beside the table it reads so both the ledger aggregation and the invoice path ask one authority rather than two predicates that can drift into disagreeing about the same date.

Parameters:
  • member_state (EUMemberState) – The member state whose table is queried.

  • on_date (date) – The date to test for coverage.

  • operation (PinnedAuthorityOperation) – Caller-owned pinned authority operation for the complete coverage query.

Return type:

bool

Returns:

True when a tier-defining rate for the general, reducido or super-reducido tier covers on_date.

coexisting_tier_rates(member_state, kind, on_date, *, operation)[source]

Return the rates coexisting with kind’s ordinary rate on on_date.

Exactly the records lookup_rate() skips: those carrying supersedes_tier_default, which a statute put on PART of a tier’s supplies while the rest stayed on the ordinary rate. lookup_rate() is right to skip them – it answers “what is this tier’s rate” and must answer with one number – but skipping them silently leaves its caller unable to tell a tier with one rate from a tier that momentarily has two.

This is the question that makes that distinction askable, so a caller deriving a number FROM a tier can refuse instead of returning the ordinary rate as though it were unambiguous. A non-empty result means the tier is ambiguous on that date and no goods axis in the bundled AEAT surfaces can separate the two populations.

Parameters:
  • member_state (EUMemberState) – The member state whose rates are searched.

  • kind (IvaRateKind) – The rate tier being interrogated.

  • on_date (date) – The date the coexisting rate must be in force.

  • operation (PinnedAuthorityOperation) – Caller-owned pinned authority operation for the complete query.

Return type:

tuple[IvaRateRecord, ...]

Returns:

The in-force coexisting records, in registry declaration order. Empty when the tier carries only its ordinary rate on that date.

rate_kinds_for_declared_rate(member_state, declared_rate, on_date, *, operation)[source]

Return every tier whose registered rate equals declared_rate on on_date.

The inverse of lookup_rate(), and a genuinely different question. That one asks “what does this tier mean now” and must answer with exactly one rate; this asks “is this declared rate a legitimate one, and for which tier”, which can legitimately have more than one answer – a statute may put a temporary rate on part of a tier’s supplies while the rest stay on the ordinary one, so 2 % and 4 % were both correct super-reducido rates in late 2024 (RDL 4/2024 art. 1).

Callers previously simulated this by iterating the tiers and calling lookup_rate() once each, comparing percentages. That works only while the tier-to-rate mapping is one-to-one per date, and silently stops finding a legitimate rate the moment a statute breaks that – which is how a correctly-declared 2 % row came to be refused as an unsupported rate.

Parameters:
  • member_state (EUMemberState) – The member state whose rates are searched.

  • declared_rate (Decimal) – The rate as a FRACTION (Decimal("0.21") for 21 %), matching how a transaction stores it rather than how the registry does.

  • on_date (date) – The date the rate must have been in force.

  • operation (PinnedAuthorityOperation) – Caller-owned pinned authority operation for the complete query.

Return type:

tuple[IvaRateKind, ...]

Returns:

Matching tiers, ordered by their declaration in the registry. Empty when the rate was not a registered Spanish rate on that date – which is a real refusal, not a lookup failure.