aeat.application.storage.calc_sheets._records module

Strict records describing workbook plans produced from registry snapshots.

Every record is a frozen pydantic v2 model with extra=”forbid” so that schema drift surfaces as validation failures at the moment the engine assembles the plan rather than as silent payload divergence at the renderer boundary. The records are intentionally narrow: the engine produces them, the Google apply adapter and offline XLSX materializer consume them, and the pull/parity adapters compare incoming workbook cell values back against the same plan.

A1 addressing

Workbook cell addresses are expressed by the SheetCellAddress record which carries the human-readable A1 string plus the structured tab name, row index, and column index. Row and column indices are 1-based to match Sheets/openpyxl convention. The a1 string is recomputed from the tab + row + column at construction time, so callers never hand-roll A1 strings — they always go through this record.

See also

aeat.domain.calculations.registry.RegistrySnapshot

Registry snapshot compiled into these records by the engine.

SheetEvidenceFacet

Evidence facet carried by the plan and rendered by both workbook export paths.

class TabName(*values)[source]

Bases: StrEnum

The tabs the engine emits in every workbook.

The set is fixed so that the pull adapter and the parity oracle have a stable layout to anchor against. New layers (for example a future “Pagos” tab for ingreso/devolución timings) are added by extending this enumeration; freeform tab names are rejected.

ENTRADAS
CALCULOS
PROVENANCE
TARIFFS
DETALLE
EVIDENCIA
GUIDE
class SheetCellAddress(**data)[source]

Bases: BaseModel

A single Sheets cell address, expressed as tab + row + column.

Parameters:
tab: TabName
row: int
column: int
a1: str
classmethod at(tab, row, column)[source]

Construct a SheetCellAddress from tab, row, and column indices.

Derives the a1 string automatically so callers never hand-roll A1 notation.

Parameters:
  • tab (TabName) – TabName enum member identifying the workbook tab.

  • row (int) – 1-based row index.

  • column (int) – 1-based column index.

Returns:

A validated SheetCellAddress instance.

Return type:

SheetCellAddress

qualified()[source]

Return the cross-tab A1 reference (‘Tab Name’!A1).

Return type:

str

class SheetValueCell(**data)[source]

Bases: BaseModel

A literal value the engine writes verbatim to a cell.

Used for operator-input cells (with value=None indicating “blank, awaiting operator entry”), for parameter mirror cells, and for the structural section/header labels.

Parameters:
  • address (SheetCellAddress)

  • value (Decimal | str | bool | None)

  • note (str | None)

  • casilla_id (CasillaId | None)

  • parameter (ParameterId | None)

  • role (Literal['operator_input', 'parameter_value', 'label', 'metadata'])

address: SheetCellAddress
value: Decimal | str | bool | None
note: str | None
casilla_id: CasillaId | None
parameter: ParameterId | None
role: Literal['operator_input', 'parameter_value', 'label', 'metadata']
class SheetFormulaCell(**data)[source]

Bases: BaseModel

A computed cell whose value comes from a Sheets formula.

The formula string is exactly what is sent to the Sheets API, minus the leading “=” sign (the apply adapter prepends it). It must already be A1-resolved.

Parameters:
  • address (SheetCellAddress)

  • formula (str)

  • casilla_id (CasillaId)

  • rounding_scale (int | None)

  • rounding_rule (Literal['money', 'integer', 'none'])

  • note (str | None)

address: SheetCellAddress
formula: str
casilla_id: CasillaId
rounding_scale: int | None
rounding_rule: Literal['money', 'integer', 'none']
note: str | None
class SheetCellConstraint(**data)[source]

Bases: BaseModel

A declarative value constraint surfaced to one Sheets cell.

Mirrors the registry’s CasillaConstraints record into a Sheets setDataValidation rule. The apply adapter renders this as a condition block on the target cell so an operator who types an out-of-range value sees Sheets’s own validation banner reject it in the workbook UI.

The constraint also propagates to the cell’s note so the operator sees the legal grounding (“LIRPF art. 56 — non-negative”) even before they attempt invalid input.

Parameters:
address: SheetCellAddress
sign: Literal['any', 'non_negative', 'non_positive']
min_value: Decimal | None
max_value: Decimal | None
legal_refs: tuple[LegalRefId, ...]
casilla_id: CasillaId
class SheetRowSetColumn(**data)[source]

Bases: BaseModel

One column of a SheetRowSet, mapping a binding id to a header cell.

Parameters:
binding: BindingId
header_address: SheetCellAddress
header_label: str
legal_refs: tuple[LegalRefId, ...]
class SheetRowSet(**data)[source]

Bases: BaseModel

A repeating-row data block in the Detalle tab.

Mirrors the registry’s row-producer binding pattern (bindings declared with aggregation = { op = “rows”, grouping = “…” }). Each row in the workbook represents one operator-supplied detail record (e.g., one perceptor on modelo 190, one VIES counterparty on modelo 349, one foreign asset on modelo 720). Columns are declared per row-producing binding sharing the same grouping.

The engine emits a header row carrying header_label for each column. Operators add row data freely below; the apply adapter leaves the data area unprotected. The pull adapter reads the operator-supplied rows back into structured RowSetEdit records keyed by binding id.

legal_refs and source_refs ground the row-set against AEAT’s diseño-de-registro authority that mandates the per-record fields.

Parameters:
grouping: str
tab: TabName
header_row: int
first_data_row: int
columns: tuple[SheetRowSetColumn, ...]
legal_refs: tuple[LegalRefId, ...]
source_refs: tuple[SourceRefId, ...]
class SheetProtectedRange(**data)[source]

Bases: BaseModel

A contiguous range the apply adapter marks read-only.

Cálculos, Procedencia, and Tarifas are always fully protected. The pull adapter inspects these to decide which cells operators are allowed to mutate.

Parameters:
tab: TabName
start_row: int
end_row: int
start_column: int
end_column: int
description: str
class SheetNumberFormat(**data)[source]

Bases: BaseModel

Display-format directive for a numeric workbook cell.

Parameters:
address: SheetCellAddress
casilla_id: CasillaId
data_type: Literal['money', 'integer', 'percentage']
pattern: str
class SheetSectionHeader(**data)[source]

Bases: BaseModel

Section-header styling directive for a section’s first label cell.

Marks the column-A cell where a casilla section first appears so both transports render it as a bold section header — the official AEAT workbooks group casillas under bold section banners for operator orientation.

Parameters:
address: SheetCellAddress
text: str
class SheetAnchor(**data)[source]

Bases: BaseModel

An explicit labelled start / final anchor on the calculation flow.

start marks the opening of the operator-input region (Entradas); final marks the filing result (resultado / cuota) on Cálculos. Rendered as a labelled cell in both transports so the inputs→resultado flow is unambiguously oriented, mirroring the published workbook layout.

Parameters:
address: SheetCellAddress
kind: Literal['start', 'final']
label: str
class SheetStyledRange(**data)[source]

Bases: BaseModel

A contiguous range tagged with a presentation role.

The engine emits one styled range per role-region (the header band, each section banner, the operator-input column, the computed column, the result cell, wrapped body columns). Both transports resolve role to a concrete fill / font / alignment through the shared _theme palette, so the offline xls and online Sheets render the same look from the same declaration. Later ranges win on overlap, so a narrow accent range (e.g. result) may be emitted after the broad column range it refines.

Parameters:
tab: TabName
start_row: int
end_row: int
start_column: int
end_column: int
role: StyleRole
wrap: bool
class SheetColumnWidth(**data)[source]

Bases: BaseModel

A per-tab column width in approximate character units.

The offline renderer applies it as an openpyxl column_dimensions width; the online renderer converts it to a pixel size (~7 px per character) for updateDimensionProperties. Sized so concept labels and legal-ref columns read without clipping.

Parameters:
tab: TabName
column: int
width: int
class SheetFrozenView(**data)[source]

Bases: BaseModel

Per-tab frozen header rows / leading columns.

Freezes the column-title row (and, where useful, the leading label columns) so the header stays visible while an operator scrolls a long modelo.

Parameters:
tab: TabName
frozen_rows: int
frozen_columns: int
class SheetAutoFilter(**data)[source]

Bases: BaseModel

A per-tab basic-filter range over the header row plus its data rows.

Lets the operator sort / filter the tab by section or concept. Offline maps it to worksheet.auto_filter.ref; online to setBasicFilter.

Parameters:
tab: TabName
start_row: int
end_row: int
start_column: int
end_column: int
class SheetProvenanceRow(**data)[source]

Bases: BaseModel

One row of the Procedencia audit tab.

Each computed casilla emits a row recording the formula id, the rounding rule, the legal references, and the workbook cell that holds the value. Operators reading the workbook can audit every figure back to a registry source.

Parameters:
  • casilla_id (CasillaId)

  • display_number (str)

  • casilla_label (str)

  • formula_id (FormulaId | None)

  • rounding_rule (Literal['money', 'integer', 'none'])

  • legal_refs (tuple[LegalRefId, ...])

  • source_refs (tuple[SourceRefId, ...])

  • target_address (SheetCellAddress)

casilla_id: CasillaId
display_number: str
casilla_label: str
formula_id: FormulaId | None
rounding_rule: Literal['money', 'integer', 'none']
legal_refs: tuple[LegalRefId, ...]
source_refs: tuple[SourceRefId, ...]
target_address: SheetCellAddress
class SheetEvidenceContributorRow(**data)[source]

Bases: BaseModel

One ledger contributor rendered into the workbook evidence surface.

Parameters:
  • casilla_id (CasillaId)

  • transaction_id (str)

  • amount (Decimal)

  • currency (str)

  • taxable_base (Decimal | None)

  • iva_rate (Decimal | None)

  • iva_amount (Decimal | None)

  • counterparty (str | None)

  • attachment_ids (tuple[str, ...])

  • document_link_ids (tuple[str, ...])

  • legal_refs (tuple[LegalRefId, ...])

  • source_refs (tuple[SourceRefId, ...])

casilla_id: CasillaId
transaction_id: str
amount: Decimal
currency: str
taxable_base: Decimal | None
iva_rate: Decimal | None
iva_amount: Decimal | None
counterparty: str | None
attachment_ids: tuple[str, ...]
legal_refs: tuple[LegalRefId, ...]
source_refs: tuple[SourceRefId, ...]
class SheetEvidenceManualEntry(**data)[source]

Bases: BaseModel

One non-ledger fact basis entry rendered into the evidence surface.

Parameters:
  • casilla_id (CasillaId)

  • value (str)

  • kind (str)

  • note (str)

  • legal_refs (tuple[LegalRefId, ...])

  • source_refs (tuple[SourceRefId, ...])

casilla_id: CasillaId
value: str
kind: str
note: str
legal_refs: tuple[LegalRefId, ...]
source_refs: tuple[SourceRefId, ...]
class SheetEvidenceFacet(**data)[source]

Bases: BaseModel

Evidence rows attached to a workbook export plan.

Contributor rows carry ledger-derived transaction facts by casilla; manual entries carry non-ledger fact basis values. The offline serializer writes this facet to both the Evidencia worksheet and the adjacent JSON sidecar.

Parameters:
snapshot_fingerprint: str | None
contributor_rows: tuple[SheetEvidenceContributorRow, ...]
manual_entries: tuple[SheetEvidenceManualEntry, ...]
class SheetTariffTableRow(**data)[source]

Bases: BaseModel

One row of a parameter bracket table mirrored to the Tarifas tab.

Parameters:
  • lower_bound (Annotated[Decimal, BeforeValidator(func=~aeat.domain.calculations.registry._schema_scalars._coerce_decimal, json_schema_input_type=PydanticUndefined)])

  • upper_bound (Annotated[Decimal, BeforeValidator(func=~aeat.domain.calculations.registry._schema_scalars._coerce_decimal, json_schema_input_type=PydanticUndefined)] | None)

  • fixed_addition (Annotated[Decimal, BeforeValidator(func=~aeat.domain.calculations.registry._schema_scalars._coerce_decimal, json_schema_input_type=PydanticUndefined)])

  • marginal_rate (Annotated[Decimal, BeforeValidator(func=~aeat.domain.calculations.registry._schema_scalars._coerce_decimal, json_schema_input_type=PydanticUndefined)])

  • valid_from (date)

  • valid_to (date | None)

lower_bound: DecimalValue
upper_bound: DecimalValue | None
fixed_addition: DecimalValue
marginal_rate: DecimalValue
valid_from: date
valid_to: date | None
class SheetTariffTable(**data)[source]

Bases: BaseModel

A parameter mirrored into the workbook as a lookup table.

Two flavours are supported: scalar dated values and bracket tables (bracket_table parameters). The engine emits one of the two depending on the parameter’s data_type.

Parameters:
  • parameter (ParameterId)

  • label (str)

  • data_type (Literal['decimal', 'money', 'integer', 'ratio', 'bracket_table'])

  • anchor (SheetCellAddress)

  • scalar_value (Annotated[Decimal, BeforeValidator(func=~aeat.domain.calculations.registry._schema_scalars._coerce_decimal, json_schema_input_type=PydanticUndefined)] | None)

  • bracket_rows (tuple[SheetTariffTableRow, ...])

parameter: ParameterId
label: str
data_type: Literal['decimal', 'money', 'integer', 'ratio', 'bracket_table']
anchor: SheetCellAddress
scalar_value: DecimalValue | None
bracket_rows: tuple[SheetTariffTableRow, ...]
class ParameterCell(**data)[source]

Bases: BaseModel

Pointer from a parameter id to its anchor cell in the Tarifas tab.

The translator consults this mapping when an expression references a parameter, so that the emitted Sheets formula reads from the mirrored value instead of inlining a literal.

Parameters:
parameter: ParameterId
anchor: SheetCellAddress
class OperatorInput(**data)[source]

Bases: BaseModel

One pre-populated operator-input value.

Operator inputs are casilla values the caller already knows (for example from the ledger or from a previous filing). They are written as literal values into the Entradas tab; the operator is free to overwrite them in the workbook.

Parameters:
casilla_id: CasillaId
value: Decimal | str | bool | None
class OperatorInputs(**data)[source]

Bases: BaseModel

Caller-supplied seed values for the Entradas tab.

Parameters:

values (tuple[OperatorInput, ...])

values: tuple[OperatorInput, ...]
by_casilla_id()[source]

Return a CasillaId -> OperatorInput lookup mapping.

Returns:

A Mapping keyed by canonical casilla.id. Later duplicates overwrite earlier ones; the registry enforces uniqueness so duplicates are not expected in practice.

Return type:

Mapping[CasillaId, OperatorInput]

class RelationValue(**data)[source]

Bases: BaseModel

One pre-resolved cross-revision relation value.

Relations aggregate values from a different modelo’s filings (typically rolling quarterly filings up into an annual summary). The local side resolves them through resolve_relation_values_from_observations and supplies the result here; the engine mirrors it as a scalar cell in Tarifas so the workbook’s formulas can consume it.

provenance carries the source tier the value came from: local_filing (operator’s own prior filing in SecureObjectRepository), aeat_live (remote AEAT Sede justificante parse), operator_manual (operator entered the value into Sheets directly). The engine stamps the provenance on the workbook so the pull adapter can detect stale prefills. The source_* and ref fields mirror the registry relation so the scalar workbook value remains joinable back to its official source modelo, source casilla, and legal grounding.

Parameters:
  • relation (RelationId)

  • value (Decimal | None)

  • provenance (Literal['local_filing', 'aeat_live', 'operator_manual'])

  • source_modelo (ModeloId | None)

  • source_filing_year (int | None)

  • source_periods (tuple[str, ...])

  • source_casilla_ids (tuple[CasillaId, ...])

  • legal_refs (tuple[LegalRefId, ...])

  • source_refs (tuple[SourceRefId, ...])

  • resolved_at (datetime | None)

  • note (str | None)

relation: RelationId
value: Decimal | None
provenance: Literal['local_filing', 'aeat_live', 'operator_manual']
source_modelo: ModeloId | None
source_filing_year: int | None
source_periods: tuple[str, ...]
source_casilla_ids: tuple[CasillaId, ...]
legal_refs: tuple[LegalRefId, ...]
source_refs: tuple[SourceRefId, ...]
resolved_at: datetime | None
note: str | None
class RelationValues(**data)[source]

Bases: BaseModel

Caller-supplied relation aggregations for the Tarifas tab.

Parameters:

values (tuple[RelationValue, ...])

values: tuple[RelationValue, ...]
by_relation()[source]

Return a RelationIdRelationValue lookup mapping.

Returns:

A Mapping keyed by relation id for fast lookup when the engine resolves cross-revision formula references.

Return type:

Mapping[RelationId, RelationValue]

class SheetGuideContent(**data)[source]

Bases: BaseModel

Plain-text content for the Guía tab.

The guide tab is the human-readable preamble: how to use the workbook, what each tab contains, and where to find the bidirectional sync command. Strings are caller-supplied (the CLI surface resolves them through tr() so locale parity holds).

Parameters:
title: str
paragraphs: tuple[str, ...]
class SheetExportMetadata(**data)[source]

Bases: BaseModel

Stamps the workbook with the registry + engine identities.

Stored both in the workbook’s developer metadata (so the pull adapter can validate compatibility before merging operator edits) and rendered as plain-text in the Guía tab so a human reader can see provenance at a glance.

Parameters:
  • modelo_id (str)

  • revision_id (RevisionId)

  • filing_year (int)

  • period (Period)

  • engine_version (str)

  • registry_sha (str)

  • exported_at (datetime)

modelo_id: str
revision_id: RevisionId
filing_year: int
period: Period
engine_version: str
registry_sha: str
exported_at: datetime
class SheetExportPlan(**data)[source]

Bases: BaseModel

Complete description of the workbook every renderer will write.

The plan is the shared contract between the registry-backed engine, Google Sheets apply adapter, offline XLSX materializer, pull adapter, and parity harness. It includes calculation cells, protected ranges, display facets, registry metadata, relation provenance, row sets, and workbook evidence.

Parameters:
metadata: SheetExportMetadata
value_cells: tuple[SheetValueCell, ...]
formula_cells: tuple[SheetFormulaCell, ...]
tariffs: tuple[SheetTariffTable, ...]
provenance: tuple[SheetProvenanceRow, ...]
protected_ranges: tuple[SheetProtectedRange, ...]
number_formats: tuple[SheetNumberFormat, ...]
section_headers: tuple[SheetSectionHeader, ...]
anchors: tuple[SheetAnchor, ...]
cell_constraints: tuple[SheetCellConstraint, ...]
row_sets: tuple[SheetRowSet, ...]
relation_provenance: RelationValues | None
evidence: SheetEvidenceFacet
font_family: str
styled_ranges: tuple[SheetStyledRange, ...]
column_widths: tuple[SheetColumnWidth, ...]
frozen_views: tuple[SheetFrozenView, ...]
auto_filters: tuple[SheetAutoFilter, ...]
guide: SheetGuideContent
all_addresses()[source]

Return every cell address referenced by value or formula cells.

Useful for collision detection and for building the full write list before sending requests to the Sheets API.

Returns:

objects from value_cells followed by those from formula_cells, in declaration order.

Return type:

tuple[SheetCellAddress, …]