cadrumo.domain.calculations.registry.invoice_bindings module

Invoice-shaped registry binding helpers.

class RectificationScope(*values)[source]

Bases: StrEnum

Which rectification rows an invoice or counterpart selector admits.

ONLY_RECTIFICATIONS

Rectification rows alone.

EXCLUDE_RECTIFICATIONS

Every row except rectifications.

ANY

No rectification filter; the default when a selector is silent.

class InvoiceObservation(**data)[source]

Bases: BaseModel

One factual line from the user’s invoice ledger.

The fields are scoped to the facts every IVA modelo needs to classify a transaction. base_amount carries the taxable base; invoice_total_amount carries the gross invoice total for modelos such as M347 whose declaration floor is not the taxable-base amount. intracommunity_clave follows the AEAT clave-de-operacion enum (E, M, H, A, T, S, I, R, D, C) for M349. operation_clave carries M347’s OWN, unrelated clave-de-operacion vocabulary (A-G; see m347_operation_clave()) – the two claves share no values in common and a row must never mix them. iva_regime is open-ended so domestic-IVA modelos can carry their regime classification alongside.

Parameters:

data (Any)

invoice_id: str
source_kind: BindingSourceKind
party_tax_id: TaxIdIdentityToken
country_code: CountryCodeAlpha2
transaction_date: date
base_amount: Decimal
invoice_total_amount: Decimal | None
iva_regime: str | None
intracommunity_clave: str | None
operation_clave: str | None
is_rectification: bool
rectified_year: FilingYear | None
rectified_period: str | None
rectified_base_previous: Decimal | None
class LedgerTransactionProvider(**data)[source]

Bases: InvoiceProviderBase

A counterparty-side ledger transaction aggregate over the invoice grammar.

Parameters:

data (Any)

kind: Literal[BindingSourceKind.LEDGER_TRANSACTION]
class PurchaseInvoiceEvidenceProvider(**data)[source]

Bases: InvoiceProviderBase

Evidence rows for purchase invoices, projected through the invoice grammar.

Parameters:

data (Any)

kind: Literal[BindingSourceKind.PURCHASE_INVOICE_EVIDENCE]
class PayableInvoiceProvider(**data)[source]

Bases: InvoiceProviderBase

An invoice the taxpayer must pay: a purchase, clave A under RD 1065/2007 art. 33.1.

Parameters:

data (Any)

kind: Literal[BindingSourceKind.PAYABLE_INVOICE]
class CollectibleInvoiceProvider(**data)[source]

Bases: InvoiceProviderBase

An invoice the taxpayer will collect: a sale, clave B under RD 1065/2007 art. 33.1.

Parameters:

data (Any)

kind: Literal[BindingSourceKind.COLLECTIBLE_INVOICE]
class M347ThirdPartyOperationProvider(**data)[source]

Bases: InvoiceProviderBase

The combined-direction M347 third-party operation total, grouped by counterparty.

Parameters:

data (Any)

kind: Literal[BindingSourceKind.M347_THIRD_PARTY_OPERATION]
is_m347_declarante_summary_invoice_binding(binding)[source]

Return whether binding is the M347 declarante-summary invoice binding.

The canonical, single-defined predicate over _M347_DECLARANTE_SUMMARY_RECORD, read through the typed _invoice_selector() rather than a raw selector_as_dict(binding).get("record"): a caller outside this module (application/invoices/source_resolver.py) once carried its own copy of both the literal and a .get() read, so a rename of the record field would have silently, permanently misclassified the M347 declarante-summary binding as absent rather than raising.

binding.source is checked first because InvoiceProviderBase validates only invoice-family selectors; a non-invoice binding’s selector shape is a different family’s concept entirely, never this one’s business.

Return type:

bool

Parameters:

binding (BindingDefinition)

m347_operation_clave(source_kind)[source]

Return the M347 clave de operacion determinable from source_kind alone.

Grounded against RD 1065/2007 art. 33.1. Only two of the seven claves are determinable from the invoice direction alone:

  • PAYABLE_INVOICE (an invoice the taxpayer must pay – a purchase) is clave A, adquisiciones de bienes y servicios superiores a 3.005,06 EUR.

  • COLLECTIBLE_INVOICE (an invoice the taxpayer will collect – a sale) is clave B, entregas de bienes y prestaciones de servicios superiores a 3.005,06 EUR.

Claves F/G (mediaci�n de agencia de viajes under RD 1619/2012 disposici�n adicional cuarta) are classified by the resolver caller from a fact this function’s single source_kind argument cannot carry – the invoice’s own travel-agency mediation flag, not its direction. The remaining three claves each still need a fact neither this function nor the resolver caller has: C (cobros por cuenta de terceros) needs a professional-fees-collection classification distinct from ordinary purchase/sale direction; D/E key on the FILER’s own type (entidad p�blica, partido, sindicato, …) rather than on any transaction classification. Returns None for those and for any non-invoice source kind, rather than guessing – a caller distinguishing them needs a fact this function does not have, not a default.

source_kind also accepts a bare str value-equal to a member: the registry’s own TOML-to-enum hydration boundary can still hold the raw value when this is consulted, and comparison below is by equality, never identity, so a value-equal string classifies exactly like its member.

Return type:

str | None

Parameters:

source_kind (BindingSourceKind | str)

validate_invoice_binding(binding)[source]

Validate an invoice-source binding at registry-build time.

Accumulating list[str] validator: validates the selector against InvoiceProviderBase and lifts the invoice fact/op invariants to build time, preserving the underlying pydantic field error. Both this validator and the invoice resolvers run the same inner _validated_invoice_selector(), so the fact/op invariants are genuinely re-checked at resolve time; validate_invoice_binding() is the public raise-style wrapper over that same inner check.

Return type:

list[str]

Parameters:

binding (BindingDefinition)

validate_invoice_family_fact_and_aggregation(binding, selector, *, family_label, strict_scalar_shape)[source]

Shared invoice/counterpart fact + aggregation-op cross-invariant.

The invoice and counterpart families share one selector shape (InvoiceProviderBase) and one fact set (_INVOICE_FACTS); their op/fact cross-checks were near-verbatim copies differing only in the family-name in the unsupported-fact message and in whether the invoice-only scalar-shape guards (non-row fact must not declare row_field/grouping and op 'rows' requires fact 'row_field') run. family_label selects the error wording; strict_scalar_shape toggles the invoice-only guards (the counterpart variant historically omitted them, so the flag preserves that behaviour exactly).

Return type:

None

Parameters:
resolve_invoice_family_scalar_values(revision, *, source_kinds, validate_selector, observations_for_binding)[source]

Resolve scalar bindings on a ModeloRevision for one invoice family into Decimal aggregates.

Shared core for both the invoice and counterpart scalar resolvers; the two differed only in (a) the family membership set, (b) the per-family selector validator, and (c) whether observations are filtered directly (invoice) or matched by source_kind and converted from counterpart observations. Row-producer bindings (fact == "row_field") are skipped here.

Return type:

dict[TypeAliasType, Decimal]

Parameters:
resolve_invoice_family_row_values(revision, *, source_kinds, validate_selector, observations_for_binding, cohort_by_source, m347_threshold_filter)[source]

Resolve row-producer bindings on a ModeloRevision for one invoice family into per-row values.

Shared core for both the invoice and counterpart row resolvers. Bindings sharing the same cohort key share one-based row indexes so that an export record with repeat = "binding_rows" correlates field values across bindings on the same row. The counterpart family adds binding.source to the cohort key (cohort_by_source = True) so a different counterpart source kind does not share rows; the invoice family does not.

M347’s contraparte_clave grouping needs every clave to share ONE row sequence, because the dise�o de registro’s Tipo-2 declarado record is one shared physical sequence regardless of clave (grounded in the tui-architecture modelo 347 contraparte binding inventory reference). That now falls out of cohort_by_source directly rather than needing a grouping-keyed exception: every contraparte_clave binding declares the combined-direction M347_THIRD_PARTY_OPERATION source (see that member’s docstring), so binding.source is already identical across claves and the cohort key naturally coincides. M349’s own two groupings, which still declare distinct payable_invoice / collectible_invoice sources per binding, are unaffected.

Return type:

dict[tuple[TypeAliasType, int], Decimal | str]

Parameters:
resolve_invoice_binding_values(revision, observations, *, effective_date=None)[source]

Resolve scalar invoice-source bindings into Decimal aggregates.

Row-producer bindings (aggregation.op == "rows") are skipped here; they are resolved by resolve_invoice_binding_row_values().

Parameters:
  • revision (ModeloRevision) – The ModeloRevision whose bindings are resolved.

  • observations (Iterable[InvoiceObservation]) – Invoice ledger lines to aggregate over.

  • effective_date (date | None) – Filing-period date required when the revision contains M347 declarante-summary threshold bindings; otherwise unused.

Return type:

dict[TypeAliasType, Decimal]

resolve_invoice_binding_row_values(revision, observations, *, effective_date=None)[source]

Resolve row-producer invoice bindings into per-row indexed values.

Bindings with aggregation.op == "rows" aggregate observations into rows deterministically grouped by selector.grouping. Bindings sharing the same grouping/scope/clave-filter share row indexes, so that an export record with repeat = "binding_rows" can correlate field values across bindings on the same row. Returns a flat mapping keyed by (binding_id, row_index). Row indexes are one-based to match ModeloBindingValue.row_index.

Parameters:
  • revision (ModeloRevision) – The ModeloRevision whose row-producer bindings to resolve.

  • observations (Iterable[InvoiceObservation]) – Typed InvoiceObservation rows the row-producer bindings group, filter, and aggregate into indexed row values.

  • effective_date (date | None) – Filing-period date required when a contraparte_clave row family needs the M347 declaration threshold; otherwise unused.

Return type:

dict[tuple[TypeAliasType, int], Decimal | str]

class InvoiceProviderBase(**data)[source]

Bases: BaseModel

Strict validator for the selector mapping of an invoice-source binding.

Parameters:

data (Any)

fact: _InvoiceFact
claves: tuple[str, ...]
rectification_scope: RectificationScopeField
iva_regime: str | None
row_field: _InvoiceRowField | None
grouping: InvoiceGrouping | None
record: str | None
data_type: ExportFieldDataType | None

Scalar type of the value this row field contributes to the export.

The same fact BindingRowExportSelector.data_type carries; declared here so the selector model admits the key, since a source-family selector is validated whole against its own strict model. Optional while the families adopt it.

invoice_selector(binding)
Return type:

InvoiceProviderBase

Parameters:

binding (BindingDefinition)