aeat.adapters.outbound.google._calc_sheets_pull module¶
Read operator-edited Sheets cells back into structured records.
Pairs with _calc_sheets_apply. The export
side materialises a
SheetExportPlan as a real Google
Sheets workbook; this module reads the operator’s edits back out, validates the
workbook is still bound to the
RegistrySnapshot the engine
compiled it from, and returns typed records the caller can inspect, compute
from, or assemble into ledger / filing inputs.
Two safety gates fire before any value is read:
Drive ownership marker — the spreadsheet must carry the
appProperties.aeat_vault_app=aeatmarker. Reading values from a spreadsheet that lacks the marker would mix operator content with foreign Drive files and break theaeat-vault/isolation contract.Registry-SHA metadata match — the spreadsheet’s developer metadata must declare
aeat_registry_sha = <snapshot.registry_sha>andaeat_modelo_id/aeat_revision_id/aeat_filing_year/aeat_periodmatching the caller’s snapshot. A mismatch means the workbook was compiled against a different registry slice — casilla identity/layout, formula chains, and bracket tables may have shifted. The pull is refused with a typed error.
The pull adapter does NOT mutate any local state; it returns a
PullResult and leaves applying the
edits to the caller.
See also
pull_operator_edits() reads the
workbook,
compute_from_pull() maps a matching
pull into
RegistryCalculationResult, and
verify_pull_coverage()
compares a pull against its source
SheetExportPlan when the
caller still has that plan.
- class OperatorEdit(**data)[source]¶
Bases:
BaseModelOne operator-edited cell value.
display_numberandlabelare display-only fields added by the pull adapter from the workbook’s column metadata. They are not part of the canonicalOperatorInputcontract; useto_operator_input()to project this shape onto the canonical one.valuemirrors the cell’s raw shape from Google Sheets. The union is intentionally ambiguous between Decimal and numeric-shaped str because the wire JSON representation cannot statically distinguish them (pydantic serialises Decimal as a JSON string). The runtime path incompute_from_pull()is what disambiguates via_coerce_edit_value_to_decimal()for numeric input casillas and_enum_binding_text()for enum bindings.- Parameters:
- casilla_id: CasillaId¶
- display_number: str¶
- label: str¶
- value: Decimal | str | bool | None¶
- to_operator_input()[source]¶
Project onto the canonical
OperatorInputshape.Drops display-only fields.
- Return type:
- class BindingEdit(**data)[source]¶
Bases:
BaseModelOne operator-edited binding cell value (numeric or enum).
Same union-ambiguity reasoning as
value— the wire JSON cannot statically distinguish a CCAA-shape"04"from a numericDecimal("4"). The runtime dispatch incompute_from_pull()is what routes the value: enum bindings go through_enum_binding_text()and numeric bindings go through_coerce_edit_value_to_decimal().- binding: BindingId¶
- value: Decimal | str | None¶
- class RelationEdit(**data)[source]¶
Bases:
BaseModelOne pre-resolved cross-revision relation value mirrored in Tarifas.
The provenance / source_modelo / source_filing_year / source_periods / source_casilla_ids / legal_refs / source_refs / resolved_at fields are recovered from the workbook’s developer metadata (
aeat_relation:<relation>keys written by the apply adapter). They are absent for relations that were edited manually in the workbook without an apply round-trip; in that case the relation is treated asprovenance="operator_manual"by convention.- Parameters:
relation (RelationId)
value (Decimal | None)
provenance (Literal['local_filing', 'aeat_live', 'operator_manual'] | None)
source_modelo (ModeloId | None)
source_filing_year (int | None)
source_casilla_ids (tuple[CasillaId, ...])
legal_refs (tuple[LegalRefId, ...])
source_refs (tuple[SourceRefId, ...])
resolved_at (datetime | None)
- relation: RelationId¶
- value: Decimal | None¶
- provenance: Literal['local_filing', 'aeat_live', 'operator_manual'] | None¶
- 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¶
- class RowSetCellEdit(**data)[source]¶
Bases:
BaseModelOne operator-edited cell from a Detalle tab row-set.
- binding: BindingId¶
- row_index: int¶
- value: Decimal | str | None¶
- class RowSetEdit(**data)[source]¶
Bases:
BaseModelAll operator-supplied detail rows for one row-set grouping.
- Parameters:
grouping (str)
cells (tuple[RowSetCellEdit, ...])
- grouping: str¶
- cells: tuple[RowSetCellEdit, ...]¶
- class PullMetadata(**data)[source]¶
Bases:
BaseModelWorkbook identity metadata recovered from developer metadata.
This is a loose parsing shape:
exported_atisstr | Nonebecause the developer-metadata round-trip may yield a raw ISO string or nothing. Useto_sheet_export_metadata()to project onto the strict canonicalSheetExportMetadatashape when the workbook is known to carry a valid export stamp.- Parameters:
- modelo_id: str¶
- revision_id: RevisionId¶
- filing_year: int¶
- period: str¶
- engine_version: str¶
- registry_sha: str¶
- exported_at: str | None¶
- to_sheet_export_metadata()[source]¶
Project onto a
SheetExportMetadata.Parses
exported_atfrom an ISO string. ReturnsNonewhen the stamp is absent or unparseable rather than raising, so callers can treat it asmetadata_match="missing".- Return type:
- class MetadataMatchState(*values)[source]¶
Bases:
StrEnumRegistry-SHA + stamp alignment result for a pulled Sheets workbook.
- MATCHES¶
- STALE¶
- MISSING¶
- class PullResult(**data)[source]¶
Bases:
BaseModelOutcome of one Google Sheets pull cycle.
Carries the typed edit families read from the workbook, the
PullMetadatastamp recovered from developer metadata, theMetadataMatchStateverdict against the caller’sRegistrySnapshot, and the count of non-blank cells read.metadata_matchmay beSTALEorMISSING; callers must treat that as a refusal boundary before applying edits to local state.- Parameters:
spreadsheet_id (str)
operator_edits (tuple[OperatorEdit, ...])
binding_edits (tuple[BindingEdit, ...])
relation_edits (tuple[RelationEdit, ...])
row_set_edits (tuple[RowSetEdit, ...])
metadata (PullMetadata)
metadata_match (MetadataMatchState)
cells_read (int)
- spreadsheet_id: str¶
- operator_edits: tuple[OperatorEdit, ...]¶
- binding_edits: tuple[BindingEdit, ...]¶
- relation_edits: tuple[RelationEdit, ...]¶
- row_set_edits: tuple[RowSetEdit, ...]¶
- metadata: PullMetadata¶
- metadata_match: MetadataMatchState¶
- cells_read: int¶
- pull_operator_edits(snapshot, *, spreadsheet_id, credentials)[source]¶
Read operator-edited cells back from a workbook into typed records.
This is the readback entrypoint behind
aeat config google sync calc pull. It verifies the Drive ownership marker, reads developer metadata, classifies metadata againstsnapshot, reads operator/binding/relation cells plus Detalle row-set blocks, and returns aPullResult.- Parameters:
snapshot (
RegistrySnapshot) – TheRegistrySnapshotthe workbook was compiled against. Used to derive the layout (cell addresses for every casilla / binding / relation) and to validate the workbook’s developer-metadata stamps.spreadsheet_id (
str) – The Drive file id of the workbook to read. Must already exist and carry theappProperties.aeat_vault_app=aeatownership marker.credentials (
object) – Agoogle.oauth2.credentials.Credentials-shaped object carrying a refresh + access token with at least thedrive.file+spreadsheetsscopes.
- Return type:
- Returns:
A
PullResultcarrying the operator edits, binding edits, relation edits, and the metadata-match verdict. Ametadata_match="stale"result still includes the edits but signals to the caller that the workbook’s identity does not match the supplied snapshot — applying these edits to the local store may corrupt data.- Raises:
OutboundStorageValidationError – When
spreadsheet_idis blank.OutboundStorageError – When Drive or Sheets rejects the request, the target is missing, quota is exhausted, or the workbook fails the app-owned marker gate.
- class PullCoverageDiscrepancy(**data)[source]¶
Bases:
BaseModelOne coverage delta between a plan and pulled workbook records.
The apply adapter writes a richly-shaped workbook (tariffs, constraints, protected ranges, row-sets); the pull adapter materialises a slimmer
PullResultof operator-editable surfaces. A corrupted or hand-edited workbook could have structural cells stripped or row-set columns removed without surfacing as a load error.verify_pull_coverage()enumerates every coverage mismatch as one of these typed records so callers can choose to refuse the merge, log a warning, or surface a diagnostic to the operator.The check is intentionally caller-opt-in: not every consumer of
compute_from_pull()carries the originalSheetExportPlan(e.g. a fresh pull from a workbook the operator authored without a prior apply). Callers that DO have the plan should run the check before consuming the pull.- Parameters:
- kind: Literal['metadata_mismatch', 'row_set_missing', 'row_set_extra', 'binding_count_mismatch', 'relation_count_mismatch']¶
- detail: str¶
- expected: str¶
- observed: str¶
- verify_pull_coverage(plan, pull)[source]¶
Return every coverage discrepancy between
planandpull.Returns an empty tuple of
PullCoverageDiscrepancywhen the two sides agree on the surfaces the pull captures. Non-empty tuples enumerate structural deltas: missing row-set groupings, unexpected groupings, binding count mismatch, relation count mismatch, or registry-metadata drift.Tariffs, cell constraints, and protected ranges are NOT re-validated against the workbook itself (the pull adapter never reads them back); a future extension can compare developer- metadata digests for those surfaces when the apply side stamps them.
- Return type:
- Parameters:
plan (SheetExportPlan)
pull (PullResult)
- compute_from_pull(snapshot, pull)[source]¶
Run the local Decimal runtime against a
PullResult.Maps each edit family back to the runtime contract:
valueflows into runtimeinputs, withDecimal("0")substituted forNoneso the runtime’s “every non-computed casilla has a value” precondition holds.valueis routed by the binding’styped_enumdeclaration: numeric bindings flow intobinding_valuesas Decimals; enum bindings flow intoenum_binding_valuesas plain strings.valueflows intorelation_valuesas Decimals, withDecimal("0")substituted forNone.
Refuses to compute when the workbook’s metadata stamps do not match the supplied snapshot (
pull.metadata_match != "matches"). The caller is responsible for handling stale workbooks before invoking this helper.- Parameters:
snapshot (
RegistrySnapshot) – TheRegistrySnapshotthe workbook was compiled against. Used to derive input casilla identifiers, active relation periods, and the metadata-match gate.pull (
PullResult) – ThePullResultcarrying the operator-edited cells to compute from.
- Return type:
- Returns:
A
RegistryCalculationResultproduced bycalculate_registry_snapshot().- Raises:
OutboundStorageConflictError – When
pulldoes not bind tosnapshotby metadata verdict and registry-SHA stamp.