aeat.domain.calculations.registry._invoice_bindings module¶
Invoice-shaped registry binding helpers.
- class InvoiceObservation(**data)[source]¶
Bases:
BaseModelOne factual line from the user’s invoice ledger.
The fields are scoped to the facts every IVA modelo needs to classify a transaction.
base_amountcarries the taxable base;invoice_total_amountcarries the gross invoice total for modelos such as M347 whose declaration floor is not the taxable-base amount.intracommunity_clavefollows the AEAT clave-de-operacion enum (E, M, H, A, T, S, I, R, D, C).iva_regimeis open-ended so domestic-IVA modelos can carry their regime classification alongside.- Parameters:
invoice_id (str)
source_kind (BindingSourceKind)
party_tax_id (str)
country_code (str)
transaction_date (date)
base_amount (Decimal)
invoice_total_amount (Decimal | None)
iva_regime (str | None)
intracommunity_clave (str | None)
is_rectification (bool)
rectified_year (int | None)
rectified_period (str | None)
rectified_base_previous (Decimal | None)
party_legal_name (str | None)
- invoice_id: str¶
- source_kind: BindingSourceKind¶
- party_tax_id: str¶
- country_code: str¶
- transaction_date: date¶
- base_amount: Decimal¶
- invoice_total_amount: Decimal | None¶
- iva_regime: str | None¶
- intracommunity_clave: str | None¶
- is_rectification: bool¶
- rectified_year: int | None¶
- rectified_period: str | None¶
- rectified_base_previous: Decimal | None¶
- party_legal_name: str | None¶
- class InvoiceObservationRequirement(**data)[source]¶
Bases:
BaseModelInvoice-fact slice declared by one or more invoice-source bindings.
Modelo runtimes use this introspection to ask the invoice ledger for the minimal set of observations the bindings need.
- Parameters:
- binding_ids: tuple[BindingId, ...]¶
- claves: tuple[str, ...]¶
- rectification_scope: _RectificationScope¶
- iva_regime: str | None¶
- invoice_binding_requirements(revision)[source]¶
Return invoice ledger slices needed by
revision’s invoice bindings.- Parameters:
revision (
ModeloRevision) – TheModeloRevisionwhose invoice bindings are inspected.- Return type:
- Returns:
Tuple of
InvoiceObservationRequirementrecords describing each distinct invoice-fact slice the revision requires.
- validate_invoice_binding_definition(binding)[source]¶
Validate an invoice-source binding before it reaches runtime.
- Return type:
- Parameters:
binding (DataBindingDefinition)
- validate_invoice_binding(binding)[source]¶
Validate an invoice-source binding at registry-build time.
Accumulating
list[str]validator: validates the selector against_InvoiceSelectorand lifts the invoice fact/op invariants to build time, preserving the underlying pydantic field error. This is thelist[str]companion to the raise-stylevalidate_invoice_binding_definition()(kept as a defence-in-depth resolve-time re-check).- Return type:
- Parameters:
binding (DataBindingDefinition)
- 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 (
_InvoiceSelector) 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/groupingandop 'rows' requires fact 'row_field') run.family_labelselects the error wording;strict_scalar_shapetoggles the invoice-only guards (the counterpart variant historically omitted them, so the flag preserves that behaviour exactly).- Return type:
- Parameters:
binding (DataBindingDefinition)
selector (_InvoiceSelector)
family_label (str)
strict_scalar_shape (bool)
- resolve_invoice_family_scalar_values(revision, *, source_kinds, validate_selector, observations_for_binding)[source]¶
Resolve scalar bindings on a
ModeloRevisionfor 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_kindand converted from counterpart observations. Row-producer bindings (fact == "row_field") are skipped here.- Return type:
- Parameters:
revision (ModeloRevision)
validate_selector (Callable[[DataBindingDefinition], _InvoiceSelector])
observations_for_binding (Callable[[DataBindingDefinition], tuple[InvoiceObservation, ...]])
- resolve_invoice_family_row_values(revision, *, source_kinds, validate_selector, observations_for_binding, cohort_by_source)[source]¶
Resolve row-producer bindings on a
ModeloRevisionfor 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 addsbinding.sourceto the cohort key (cohort_by_source = True) so a different counterpart source kind does not share rows; the invoice family does not.- Return type:
- Parameters:
revision (ModeloRevision)
validate_selector (Callable[[DataBindingDefinition], _InvoiceSelector])
observations_for_binding (Callable[[DataBindingDefinition], tuple[InvoiceObservation, ...]])
cohort_by_source (bool)
- resolve_invoice_binding_values(revision, observations)[source]¶
Resolve scalar invoice-source bindings into Decimal aggregates.
Row-producer bindings (
aggregation.op == "rows") are skipped here; they are resolved byresolve_invoice_binding_row_values().- Parameters:
revision (
ModeloRevision) – TheModeloRevisionwhose bindings are resolved.observations (
Iterable[InvoiceObservation]) – Invoice ledger lines to aggregate over.
- Return type:
- resolve_invoice_binding_row_values(revision, observations)[source]¶
Resolve row-producer invoice bindings into per-row indexed values.
Bindings with
aggregation.op == "rows"aggregate observations into rows deterministically grouped byselector.grouping. Bindings sharing the same grouping/scope/clave-filter share row indexes, so that an export record withrepeat = "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 matchModeloBindingValue.row_index.- Parameters:
revision (
ModeloRevision) – TheModeloRevisionwhose row-producer bindings to resolve.observations (
Iterable[InvoiceObservation]) – TypedInvoiceObservationrows the row-producer bindings group, filter, and aggregate into indexed row values.
- Return type:
- class Modelo349OperadorClaveTotal(**data)[source]¶
Bases:
BaseModelOne clave’s operator count and base-imponible sum, reconstructed from the operador row set.
Groups the per-operador
iva-349-operador-row-*detail (the AEAT Diseño de Registros Tipo-2 “registro de operador” rows) byclave de operaciónand carries that clave’s distinct-operator count and summed base imponible. MirrorsWithholdingClaveBreakdownfor the Modelo 349 intracommunity-operator axis.- clave: str¶
- operator_count: int¶
- base_total: Decimal¶
- class Modelo349OperadorTotalsParity(**data)[source]¶
Bases:
BaseModelTotals-parity verdict between the per-operador row set and the Modelo 349 declarant summary.
Modelo 349’s declarant-summary scalar casillas (
decl.numero-operadores,decl.importe-operaciones) and the per-operador-clave row-producer bindings (iva-349-operador-row-*) are resolved by two structurally INDEPENDENT code paths over the sameInvoiceObservationset:resolve_invoice_binding_values()folds the observations directly into a scalar (_aggregate_invoice_binding()’soperator_count/base_sumfacts), whileresolve_invoice_binding_row_values()groups them into per-(country, party_tax_id, clave)rows (_build_operator_clave_rows()). Nothing in the registry cross-checks that the two paths agree, so a defect in either aggregator — or a manual-entryModelo349OperadorRowset that omits an operator the summary already counted — would silently under- or over-declare one side without detection.This model is the pure comparison result of that cross-check: the sum of every reconstructed operador row’s base imponible against the resolved
decl.importe-operacionesvalue, and the count of distinct(country_code, party_tax_id, clave)operador rows against the resolveddecl.numero-operadoresvalue.is_consistentisTrueonly when the operator-count delta is exactly zero and the base-imponible delta is withintolerance— a divergence on either axis surfaces as a loud, actionable finding (no-silent-under-declaration), never a silent pass.- Parameters:
- by_clave: tuple[Modelo349OperadorClaveTotal, ...]¶
- operator_row_total: int¶
- operator_summary_total: int¶
- operator_delta: int¶
- base_row_total: Decimal¶
- base_summary_total: Decimal¶
- base_delta: Decimal¶
- tolerance: Decimal¶
- is_consistent: bool¶
- compute_modelo_349_operador_totals_parity(revision, observations, *, operator_summary_total, base_summary_total, tolerance=Decimal('0.01'))[source]¶
Cross-check the per-operador row set against the resolved Modelo 349 declarant summary.
- Parameters:
revision (
ModeloRevision) – TheModeloRevisionwhoseiva-349-operador-row-*row-producer bindings are resolved into the operador row set.observations (
Iterable[InvoiceObservation]) – TheInvoiceObservationrows the revision’s invoice-source bindings aggregate (exclude-rectifications scope only feeds the operador row set; rectification observations are a distinct AEAT record type and are excluded from this axis by the registry’s own binding selectors).operator_summary_total (
Decimal) – The resolved value of casilladecl.numero-operadores, typically read fromrevision.casilla_values["decl.numero-operadores"].base_summary_total (
Decimal) – The resolved value of casilladecl.importe-operaciones, typically read fromrevision.casilla_values["decl.importe-operaciones"].tolerance (
Decimal) – Maximum absolute EUR delta on the base-imponible axis that does not surface a divergence. Defaults to one cent, matching the registry’s standard rounding tolerance. The operator-count axis is an exact integer match with no tolerance.
- Return type:
- Returns:
A
Modelo349OperadorTotalsParityverdict.is_consistentisFalsewhenever the reconstructed operator count differs at all, or the reconstructed base imponible diverges frombase_summary_totalby more thantolerance— a dropped or double-counted operador row must surface as a divergence, never silently collapse intois_consistent=True.