aeat.application.aggregation._retenciones module

Pure aggregation primitives for the retenciones modelo family.

This module groups typed RetencionObservation rows into stable per-perceptor rollups and totals for Modelos 111, 115, 123, 180, 190, and 193. Observations must carry canonical source kinds from BindingSourceKind; bare invoice provenance is rejected in favour of payable_invoice or collectible_invoice.

The live calculation mesh uses these primitives through RetencionesAggregationSourceResolver for the RET-1 Modelo 180/193 distinct-NIF perceptor count. Modelo 190’s distinct perceptor/clave/subclave percepciones count is intentionally handled by WithholdingSourceResolver, not by this rollup family.

class RetencionObservation(**data)[source]

Bases: BaseModel

One typed observation feeding a retenciones aggregator.

The source ledger transaction (source_object_id) is referenced by its canonical source kind ledger_transaction. Bare invoice source bindings are forbidden at the registry domain layer; observations originating from invoice records carry one of payable_invoice / collectible_invoice instead.

Parameters:
source_kind: BindingSourceKind
source_object_id: str
perceptor_nif: str
perceptor_name: str
scheme: RetencionScheme
taxable_base: Decimal
retencion_amount: Decimal
accrued_on: str
class RetencionPerceptorRollup(**data)[source]

Bases: BaseModel

One row in the aggregation: a perceptor’s totals across schemes.

Parameters:
source_kind: BindingSourceKind
perceptor_nif: str
perceptor_name: str
scheme: RetencionScheme
observations_count: int
total_taxable_base: Decimal
total_retencion: Decimal
class RetencionesAggregation(**data)[source]

Bases: BaseModel

Aggregate output for a retenciones modelo + period.

The output is content-addressable: identical input observations in any order produce the same rollup tuple (sorted by perceptor + scheme) and the same totals.

Parameters:
modelo: str
period: InstanceOf[Period]
rollups: tuple[RetencionPerceptorRollup, ...]
total_perceptors: int
total_taxable_base: Decimal
total_retencion: Decimal
aggregate_retenciones_111(observations, *, period)[source]

Aggregate per (perceptor_nif, scheme) into a Modelo 111 payload.

Pure function: identical observation input + period yields identical output. Rollups are sorted by (perceptor_nif, scheme.value) so two equal aggregations serialise to identical bytes.

Returns a RetencionesAggregation.

Return type:

RetencionesAggregation

Parameters:
aggregate_retenciones_115(observations, *, period)[source]

Aggregate Modelo 115 (retenciones sobre arrendamiento urbano).

Only URBAN_RENTAL scheme observations are in scope.

Returns a RetencionesAggregation with per-perceptor rollups and grand totals for Modelo 115.

Return type:

RetencionesAggregation

Parameters:
aggregate_retenciones_123(observations, *, period)[source]

Aggregate Modelo 123 retenciones into a RetencionesAggregation.

Covers rendimientos del capital mobiliario: intereses, dividendos, y otros. In-scope schemes: CAPITAL_INTEREST, CAPITAL_DIVIDEND, CAPITAL_OTHER.

Return type:

RetencionesAggregation

Parameters:
aggregate_retenciones_180(observations, *, period)[source]

Aggregate Modelo 180 (resumen anual de retenciones sobre arrendamiento urbano).

Shares the URBAN_RENTAL scheme catalogue with Modelo 115; the difference is the period scope (full year vs quarter) which the caller supplies. Callers should pass an annual period string (e.g. "2025") and feed in the union of the year’s 115 observations.

Returns a RetencionesAggregation.

Return type:

RetencionesAggregation

Parameters:
aggregate_retenciones_190(observations, *, period)[source]

Aggregate Modelo 190 (resumen anual de retenciones IRPF de Modelo 111).

Shares the 111 scheme catalogue (WORK_INCOME + ECONOMIC_ACTIVITY + PROFESSIONAL + PRIZE) widened over the annual period.

Returns a RetencionesAggregation with per-perceptor rollups and grand totals for the annual summary.

Return type:

RetencionesAggregation

Parameters:
aggregate_retenciones_193(observations, *, period)[source]

Aggregate Modelo 193 retenciones into a RetencionesAggregation.

Resumen anual de retenciones sobre capital mobiliario. Shares the 123 scheme catalogue.

Return type:

RetencionesAggregation

Parameters:
class RetencionesTotalsParity(**data)[source]

Bases: BaseModel

Totals-parity verdict between the dedicated per-perceptor retención store and a resumen-anual summary.

Modelo 193’s (and Modelo 180’s) monetary resumen casillas (decl.base-total, decl.retenciones-total) are computed by the registry as a SUM of the taxpayer’s four Modelo 123 (Modelo 115 for 180) quarterly filings (source = "relation_prefill"), and the distinct-NIF perceptor count (decl.total-perceptores) is bound to aggregate_retenciones_193() / aggregate_retenciones_180() over the dedicated per-perceptor retención store (RetencionesAggregation, RET-1). Both are independently sourced: nothing in the registry cross-checks that the quarterly-relation totals and the per-perceptor store’s totals agree.

This model is the pure comparison result of that cross-check: the aggregation’s total_perceptors / total_taxable_base / total_retencion against the resolved summary casilla values. is_consistent is True only when every delta is within tolerance (the perceptor-count delta is compared as an exact integer match) — a divergence on any axis surfaces as a loud, actionable finding (no-silent-under-declaration), never a silent pass.

Parameters:
  • perceptores_aggregation_total (int)

  • perceptores_summary_total (int)

  • perceptores_delta (int)

  • base_aggregation_total (Decimal)

  • base_summary_total (Decimal)

  • base_delta (Decimal)

  • retenciones_aggregation_total (Decimal)

  • retenciones_summary_total (Decimal)

  • retenciones_delta (Decimal)

  • tolerance (Decimal)

  • is_consistent (bool)

perceptores_aggregation_total: int
perceptores_summary_total: int
perceptores_delta: int
base_aggregation_total: Decimal
base_summary_total: Decimal
base_delta: Decimal
retenciones_aggregation_total: Decimal
retenciones_summary_total: Decimal
retenciones_delta: Decimal
tolerance: Decimal
is_consistent: bool
compute_retenciones_totals_parity(aggregation, *, perceptores_summary_total, base_summary_total, retenciones_summary_total, tolerance=Decimal('0.01'))[source]

Cross-check a RetencionesAggregation against a resumen-anual summary’s casillas.

Parameters:
  • aggregation (RetencionesAggregation) – The real per-perceptor RetencionesAggregation (typically aggregate_retenciones_193() or aggregate_retenciones_180()) built from the dedicated per-perceptor retención store for the filing year.

  • perceptores_summary_total (int) – The resolved value of casilla decl.total-perceptores (already sourced from the SAME aggregation via the retenciones_aggregation binding, so this axis is expected to always match; included for completeness and to catch a stale/desynchronised binding read).

  • base_summary_total (Decimal) – The resolved value of casilla decl.base-total (the relation-prefill sum of the taxpayer’s quarterly filings’ base casilla).

  • retenciones_summary_total (Decimal) – The resolved value of casilla decl.retenciones-total (the relation-prefill sum of the taxpayer’s quarterly filings’ retenciones casilla).

  • tolerance (Decimal) – Maximum absolute EUR delta that does not surface a divergence on the monetary axes. Defaults to one cent, matching the registry’s standard rounding tolerance.

Return type:

RetencionesTotalsParity

Returns:

A RetencionesTotalsParity verdict. is_consistent is False whenever the perceptor count differs at all, or either monetary total diverges from its corresponding summary casilla by more than tolerance — a dropped or double-counted perceptor row, or a quarterly filing missing from the relation-prefill sum, must surface as a divergence, never silently collapse into is_consistent=True.