aeat.domain.modelos._calculation_revision module

One calculation attempt under a modelo work unit.

A work unit owns many calculation revisions. Each calculate invocation produces a fresh, content-addressed CalculationRevision. The work unit carries pointer fields that disambiguate which revision is the most recent (current) and which one is the filed answer (filed). Without those pointers, multiple drafts under the same work unit have no canonical selection — every consumer (year-aggregation, amendment delta, forward-period carry-forward) needs to know which one is THE revision. Formula provenance for every computed casilla is carried through CasillaObservation entries in the typed observations envelope.

Lifecycle states:

  • BORRADOR — newly calculated; mutable in the sense that re-running calculate creates a new revision rather than editing this one. Multiple borradores can coexist.

  • VERIFICADO_COMPLETOverify ran cleanly: all required casillas resolved, zero blocking findings, source trace persisted. The revision is immutable from this point on; any recalculation produces a fresh borrador instead.

  • PRESENTADO — paired with a ModeloRecord. The revision is the currently-effective filed answer for its (bucket, modelo, year, period) tuple. Exactly one presentado revision per tuple at any time.

  • PRESENTADO_SUPERSEDIDO — a later verified revision was filed against the same tuple. The revision and its filing record remain in the audit trail.

  • DESCARTADO — operator abandoned the revision before filing.

Two CalculationRevisions can never share a calculation_revision_id; the id is the SHA-256 of the inputs + binding overrides + computed casilla values (plus the parent work_unit_id), so structurally identical re-runs produce the same id and re-running calculate with the same data is naturally idempotent.

class CalculationRevisionState(*values)[source]

Bases: StrEnum

Closed enumeration of calculation-revision lifecycle states.

BORRADOR
VERIFICADO_COMPLETO
PRESENTADO
PRESENTADO_SUPERSEDIDO
DESCARTADO
class CalculationRevisionAmendmentKind(*values)[source]

Bases: StrEnum

Closed catalogue of amendment kinds a revision may carry.

Aligned with Spanish tax law’s legally-distinct amendment shapes:

  • COMPLEMENTARIA — corrective filing that adds to the prior filing’s tax due (LGT art. 122.2, ley-58-2003:art-122). Filed when the operator discovers an error that under-reported tax.

  • SUSTITUTIVA — substitute filing that replaces the prior filing entirely (LGT art. 122.1). Used for material restatements.

  • RECTIFICATIVA — autoliquidación rectificativa: the unified amendment mechanism established by LGT art. 120.4 (ley-58-2003:art-120, apartado 4) and developed by RD 117/2024 (which amended the Reglamento de gestión, RD 1065/2007). For the modelos whose tax-specific orden implements it (Modelo 303 from the 2023-y-siguientes revision onward), the rectificativa replaces BOTH the complementaria and the separate solicitud de rectificación: a single amended autoliquidación that may raise OR lower the resultado, carrying its own fichero-BOE indicator and, when it lowers the cuota to a refund, the operator’s devolución account.

COMPLEMENTARIA
SUSTITUTIVA
RECTIFICATIVA
derive_calculation_revision_id(*, work_unit_id, input_values_by_casilla_id, binding_overrides, row_binding_values=None, casilla_values, relation_overrides=None, source_transaction_ids=(), borrador_snapshot_id=None, bindings_sourced_from_borrador=(), detail_rows=())[source]

Return the deterministic SHA-256 id for a calculation attempt.

The id is content-addressed by the parent work unit plus the three payload mappings: input casilla values, scalar binding overrides, and computed casilla outputs. Row-indexed binding values are carried as their own nested map so repeating-record coordinates participate in identity without being flattened into synthetic binding ids. Two structurally identical re-runs produce the same id; the catalogue’s content-addressing invariant then makes a second calculate call idempotent (the existing revision is returned, no duplicate is persisted).

detail_rows carries typed row observations for informational modelos (M184, M232) that declare row-producer bindings. When rows are present they are serialised into the hash so structurally identical re-runs with the same rows produce the same id.

Return type:

str

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

Bases: BaseModel

One resolver-level source-object trace persisted on a calculation revision.

The calculation source mesh (aeat.application.aggregation) resolves each registry binding source through an enrolled resolver and produces a typed CalculationSourceProvenance row per contributing source object. This is the DOMAIN-side, persistence-shaped projection of that provenance: it carries exactly the resolver→source-object→fingerprint trace that lets an audit reader reconstruct which resolver mesh and which upstream source objects produced a revision, and whether those objects have since drifted.

It deliberately does NOT carry legal_refs / source_refs — those are the per-casilla regulatory grounding already carried by CasillaObservation on the same revision; duplicating them here would fragment the grounding across two surfaces.

Variables:
  • source_kind – Free-form resolver source token (e.g. collectible_invoice). Always the token the resolver declared for the contributing source.

  • binding_source – The canonical BindingSourceKind when source_kind names a registry binding source; None for advisory or non-binding provenance rows.

  • source_ref – Stable reference to the contributing source object (e.g. collectible_invoice:{invoice_id}).

  • fingerprint – Data-dependent digest of the contributing source object when the resolver produced one; None when the resolver emits a reference without a content digest.

Parameters:
source_kind: str
binding_source: BindingSourceKind | None
source_ref: str
fingerprint: str | None
class CalculationRevision(**data)[source]

Bases: BaseModel

One calculation attempt attached to a work unit.

Variables:
  • calculation_revision_id – Lowercase 64-char SHA-256 derived from the parent work_unit_id plus the inputs, overrides, and casilla outputs. Content-addressed: structurally identical re-runs produce the same id.

  • work_unit_id – Parent work unit id (also content-addressed).

  • state – Lifecycle state from CalculationRevisionState.

  • input_values_by_casilla_id – Mapping of canonical input casilla values captured at calculation time. The string values are decimal strings or short literals from the registry input contract.

  • binding_overrides – Mapping of operator-supplied binding overrides applied during this calculation. Empty when no binding overrides were used.

  • row_binding_values – Mapping of row-indexed binding values produced by source meshes for repeating export records. Kept separate from binding_overrides so the row coordinate remains structured.

  • relation_overrides – Mapping of relation values applied during this calculation. Kept separate from binding_overrides so BindingId-keyed snapshots never carry RelationId keys.

  • source_transaction_ids – Stable ledger transaction ids that contributed to this revision through bucket-local aggregation. Empty for calculations that did not consume ledger transactions.

  • casilla_values – Mapping of computed casilla values (decimal output). The values that would be exported to AEAT if this revision were filed.

  • created_at – UTC timestamp of revision creation.

  • updated_at – UTC timestamp of the most recent state transition. Equals created_at on a fresh draft.

  • verified_at – UTC timestamp at which the revision transitioned to VERIFICADO_COMPLETO. None for non-verified revisions.

  • verified_by – Actor label captured at verification time. None for non-verified revisions.

  • filed_at – UTC timestamp at which the revision was filed. None for non-filed revisions.

  • filed_by – Actor label captured at filing time. None for non-filed revisions.

  • superseded_at – UTC timestamp at which a later filed revision superseded this one. None unless state is PRESENTADO_SUPERSEDIDO.

  • discarded_at – UTC timestamp captured when the revision is moved to DESCARTADO. None otherwise.

  • discarded_by – Actor label captured when the revision is moved to DESCARTADO. None otherwise.

  • discard_reason – Audit reason captured when the revision is moved to DESCARTADO. None otherwise.

Parameters:
  • calculation_revision_id (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=64, max_length=64, pattern=^[0-9a-f]{64}$, ascii_only=None)])

  • work_unit_id (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=64, max_length=64, pattern=^[0-9a-f]{64}$, ascii_only=None)])

  • state (CalculationRevisionState)

  • input_values_by_casilla_id (Mapping[CasillaId, str])

  • binding_overrides (Mapping[BindingId, str])

  • row_binding_values (Mapping[BindingId, Mapping[str, str]])

  • relation_overrides (Mapping[RelationId, str])

  • source_transaction_ids (tuple[Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=64, max_length=64, pattern=^[0-9a-f]{64}$, ascii_only=None)], ...])

  • borrador_snapshot_id (str | None)

  • bindings_sourced_from_borrador (tuple[BindingId, ...])

  • casilla_values (Mapping[CasillaId, Decimal])

  • observations (tuple[CasillaObservation, ...])

  • unresolved_outcomes (tuple[RegistryCalculationUnresolvedOutcome, ...])

  • ledger_filing_snapshot (LedgerFilingSnapshot | None)

  • ledger_filing_evidence (LedgerFilingEvidence | None)

  • source_provenance (tuple[CalculationSourceRef, ...])

  • detail_rows (tuple[Modelo184MemberRow | Modelo232VinculadaRow | Modelo349OperadorRow | Modelo349RectificacionRow | Modelo347ContraparteRow, ...])

  • created_at (datetime)

  • updated_at (datetime)

  • verified_at (datetime | None)

  • verified_by (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=64, pattern=None, ascii_only=None)] | None)

  • filed_at (datetime | None)

  • filed_by (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=64, pattern=None, ascii_only=None)] | None)

  • superseded_at (datetime | None)

  • discarded_at (datetime | None)

  • discarded_by (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=64, pattern=None, ascii_only=None)] | None)

  • discard_reason (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=500, pattern=None, ascii_only=None)] | None)

  • amendment_kind (CalculationRevisionAmendmentKind | None)

  • amends_filing_record_id (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=64, max_length=64, pattern=^[0-9a-f]{64}$, ascii_only=None)] | None)

  • amendment_reason (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=500, pattern=None, ascii_only=None)] | None)

calculation_revision_id: CalculationRevisionId
work_unit_id: WorkUnitId
state: CalculationRevisionState
input_values_by_casilla_id: Mapping[CasillaId, str]
binding_overrides: Mapping[BindingId, str]
row_binding_values: Mapping[BindingId, Mapping[str, str]]
relation_overrides: Mapping[RelationId, str]
source_transaction_ids: tuple[CalculationRevisionId, ...]
borrador_snapshot_id: str | None
bindings_sourced_from_borrador: tuple[BindingId, ...]
casilla_values: Mapping[CasillaId, Decimal]
observations: tuple[CasillaObservation, ...]
unresolved_outcomes: tuple[RegistryCalculationUnresolvedOutcome, ...]
ledger_filing_snapshot: LedgerFilingSnapshot | None
ledger_filing_evidence: LedgerFilingEvidence | None
source_provenance: tuple[CalculationSourceRef, ...]
detail_rows: tuple[ModeloDetailRow, ...]
created_at: datetime
updated_at: datetime
verified_at: datetime | None
verified_by: ModeloActorLabel | None
filed_at: datetime | None
filed_by: ModeloActorLabel | None
superseded_at: datetime | None
discarded_at: datetime | None
discarded_by: ModeloActorLabel | None
discard_reason: _DiscardReason | None
amendment_kind: CalculationRevisionAmendmentKind | None
amends_filing_record_id: CalculationRevisionId | None
amendment_reason: _DiscardReason | None
class CalculationRevisionCatalogue(**data)[source]

Bases: BaseModel

Immutable catalogue of every calculation revision in storage.

Parameters:

revisions (Mapping[str, CalculationRevision])

revisions: Mapping[str, CalculationRevision]
get(calculation_revision_id)[source]
Return type:

CalculationRevision | None

Parameters:

calculation_revision_id (str)

values()[source]
for_work_unit(work_unit_id)[source]

Return every revision attached to one work unit.

Return type:

tuple[CalculationRevision, ...]

Returns:

Tuple of CalculationRevision records for the given work unit.

Parameters:

work_unit_id (str)

exception LedgerFilingCoverageError(message=None, *, context=None, suggestion=None, translated_message=None)[source]

Bases: ModeloError

Raised when a persisted revision’s snapshot and evidence contributor sets diverge.

A ledger-derived revision bundles a ledger_filing_snapshot (the fingerprinted contributor set) and a ledger_filing_evidence (the typed fact basis). The two are projected from the same source_transaction_ids and MUST cover the same contributors. A divergence on read-back means a contributor row was silently dropped after persistence; this gate surfaces it on load rather than letting the filing artefact ship an unexplainable casilla.

Parameters:
  • message (str | None)

  • context (dict[str, object] | None)

  • suggestion (str | None)

  • translated_message (str | None)

Return type:

None

code: ClassVar[ErrorCode]
assert_revision_snapshot_evidence_coverage(revision)[source]

Cross-check a loaded revision’s snapshot and evidence contributor coverage.

Parameters:

revision (CalculationRevision) – The CalculationRevision loaded from persistence.

Return type:

None

Post-roundtrip validator (per the modelo-export-evidence-parity discipline): when both ledger_filing_snapshot and ledger_filing_evidence are present, their rows contributor (transaction_id) sets MUST be equal. A revision with neither (a non-ledger or borrador revision) passes trivially. Raises LedgerFilingCoverageError naming the divergent contributors.