aeat.application.live._justificante module

Application-live persistence for captured AEAT justificante receipts.

The live justificante pull retrieves the authentic, AEAT-signed justificante de presentación PDF for a filed work unit through the read-only sede surface (capture_justificanteSedeCapture) and persists it as a bucket-scoped, content-addressed secure object. The persisted artefact is the durable, official evidence the local reconciler reads — the operator no longer hand-downloads the receipt.

This service is a stateful SnapshotService sibling of the Modelo 100 borrador service: it keys supersession on the (modelo, filing_year, period) axis so a re-filed period’s fresh capture supersedes the prior ACTIVE one, and it persists each snapshot through a SecureObjectRepository at FINANCIAL sensitivity under aeat.adapters.persistence.storage.LIVE_JUSTIFICANTE_CAPTURE_SNAPSHOT_NAMESPACE, and records each capture as a lifecycle event via BucketEventHistoryRepository.

The captured PDF bytes ride inside the encrypted snapshot Envelope as a base64 str (binary cannot survive the JSON envelope verbatim); the raw-bytes pdf_sha256 is the content address used for snapshot-id derivation and dedup.

See also

aeat.application.live

Public read-only live facade that orchestrates capture and reports JustificanteCaptureOutcome.

aeat.application.live._filed_observation_persistence.enroll_filed_justificante_evidence()

Filed-history path that performs the same metadata registration and current-record evidence stamping from declaration-register artefacts.

aeat.application.overview

Calendar projection that reads JustificanteCaptureSnapshot rows and matching domain justificante metadata as AEAT-side evidence.

aeat.application.live._snapshot_base.SecureSnapshotRepository

Shared encrypted snapshot repository used by this bucket-scoped capture repository.

ModeloRecord

Local filing record stamped with live ExternalEvidence only after the receipt matches the current filing axis.

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

Bases: SnapshotNotFoundError

Raised when a live justificante-capture snapshot lookup misses by id.

Parameters:
  • message (str | None)

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

  • suggestion (str | None)

  • translated_message (str | None)

Return type:

None

code: ClassVar[ErrorCode]
class JustificanteCaptureSnapshot(**data)[source]

Bases: BaseModel

One live-captured AEAT justificante receipt persisted for a bucket.

Bundles the work-unit axis (modelo / filing_year / period), the sede provenance (expediente_id / csv), the content address (pdf_sha256 over the raw bytes), and the receipt itself (pdf_base64). The official source_kind records that the receipt came from an authenticated live capture.

Parameters:
  • snapshot_id (str)

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

  • modelo (str)

  • filing_year (int)

  • period (Period)

  • expediente_id (str)

  • csv (str)

  • pdf_sha256 (str)

  • pdf_base64 (str)

  • source_kind (str)

  • captured_at (datetime)

  • state (SnapshotLifecycleState)

  • superseded_by_snapshot_id (str | None)

  • discarded_at (datetime | None)

  • discarded_by (str)

  • discard_reason (str)

snapshot_id: str
bucket_id: BucketId
modelo: str
filing_year: int
period: Period
expediente_id: str
csv: str
pdf_sha256: str
pdf_base64: str
source_kind: str
captured_at: datetime
state: SnapshotLifecycleState
superseded_by_snapshot_id: str | None
discarded_at: datetime | None
discarded_by: str
discard_reason: str
decoded_pdf_bytes()[source]

Return the raw PDF bytes decoded from pdf_base64.

Return type:

bytes

justificante_capture_snapshot_object_key(bucket_id, snapshot_id)[source]

Return the secure-object key for one bucket’s justificante-capture snapshot.

The key shape is the object-key grammar declared by aeat.adapters.persistence.storage.LIVE_JUSTIFICANTE_CAPTURE_SNAPSHOT_NAMESPACE.

Return type:

str

Parameters:
  • bucket_id (str)

  • snapshot_id (str)

derive_justificante_capture_snapshot_id(*, modelo, filing_year, period, pdf_sha256)[source]

Return the content-addressed id for one justificante capture.

The id is derived from the work-unit axis plus the raw-PDF content address, so re-capturing the identical receipt is idempotent while a re-filed period (a different signed PDF) yields a new id that supersedes the prior ACTIVE snapshot on the same axis.

Return type:

str

Parameters:
resolve_period_expediente(*, declarations, expedientes, modelo, period)[source]

Resolve the capturable expediente for one (modelo, period) filing.

The procedure-tree Expediente carries no period, so for a multi-period modelo (quarterly 1T-4T) it cannot disambiguate which quarter’s receipt to pull. The period-bearing surface is the filed declarations register (Declaracion carries period and expediente_id). This resolver picks the declaration matching the target (modelo, period) (the latest filing for that period when a period was re-filed), then cross-references its expediente_id against the tree to return the capturable expediente. It NEVER returns a different period’s expediente: a missing or unmatched declaration raises rather than falling back to a wrong-quarter receipt.

The within-period tiebreak ranks the accepted (ALTA) declaration ahead of presented_at, matching the two sibling period-resolution surfaces (latest_declarations_by_period and the sede walker’s latest-selection), so a later cancellation / correction row (a non-ALTA estado such as Anulada or Baja) presented after the accepted filing does not win and pull the wrong-state receipt.

Raises:

LiveApplicationInputError – when no declaration matches the requested period, or the matched declaration’s expediente is absent from the tree.

Return type:

Expediente

Parameters:
class JustificanteCaptureSnapshotRepository(*, bucket_id, objects=None)[source]

Bases: object

Secure-DB repository for captured justificante snapshots in one bucket.

Composes the shared SecureSnapshotRepository for the read surface (load / resolve / list / exists), preserving the class identity, JustificanteCaptureSnapshotNotFoundError messages, and the captured_at list ordering. save is kept local because justificante stamps the envelope written_at with the capture time (not now()), a deliberate divergence from the shared base.

The namespace, sensitivity, schema version, and key grammar come from aeat.adapters.persistence.storage.LIVE_JUSTIFICANTE_CAPTURE_SNAPSHOT_NAMESPACE. Each JustificanteCaptureSnapshot is written through an Envelope so the captured PDF, CSV, and expediente metadata stay inside the encrypted SecureObjectRepository bucket store.

Parameters:
property bucket_id: str
exists(snapshot_id)[source]
Return type:

bool

Parameters:

snapshot_id (str)

load(snapshot_id)[source]
Return type:

JustificanteCaptureSnapshot

Parameters:

snapshot_id (str)

list_snapshots()[source]
Return type:

tuple[JustificanteCaptureSnapshot, ...]

resolve(snapshot_id)[source]
Return type:

JustificanteCaptureSnapshot

Parameters:

snapshot_id (str)

save(snapshot)[source]
Return type:

None

Parameters:

snapshot (JustificanteCaptureSnapshot)

class JustificanteCaptureSnapshotService(*, bucket_id, repository=None)[source]

Bases: SnapshotService[JustificanteCaptureSnapshot]

Canonical backend service for bucket-scoped live justificante captures.

Parameters:
capture(*, modelo, filing_year, period, expediente_id, csv, pdf_bytes, pdf_sha256, captured_at)[source]

Persist one captured justificante and return the ACTIVE JustificanteCaptureSnapshot.

Idempotent on the receipt content address: re-capturing the same signed PDF returns the existing snapshot. A re-filed period (a new signed PDF) supersedes the prior ACTIVE snapshot on the (modelo, filing_year, period) axis.

Return type:

JustificanteCaptureSnapshot

Parameters:
list_snapshots(*, filing_year=None, state=SnapshotLifecycleState.ACTIVE)[source]
Return type:

tuple[JustificanteCaptureSnapshot, ...]

Parameters:
show(snapshot_id)[source]
Return type:

JustificanteCaptureSnapshot

Parameters:

snapshot_id (str)

latest_for_work_unit(*, modelo, filing_year, period)[source]
Return type:

JustificanteCaptureSnapshot | None

Parameters:
parse_capture_to_justificante(snapshot)[source]

Parse a persisted capture’s PDF into a strict domain Justificante.

Reads the encrypted snapshot’s bytes in memory and runs the inbound parser. Used to register the captured receipt as official filing evidence and to reconcile against it.

Return type:

Justificante

Parameters:

snapshot (JustificanteCaptureSnapshot)

register_capture_justificante_metadata(*, snapshot)[source]

Persist parsed justificante metadata for a live capture.

This records the official AEAT receipt metadata even when the local app has no current ModeloRecord for the period. It does not stamp or create a local filing row; that remains owned by register_capture_as_filing_evidence().

Returns the persisted Justificante, or None when the captured snapshot cannot be parsed into one.

Return type:

Justificante | None

Parameters:

snapshot (JustificanteCaptureSnapshot)

reconcile_capture(*, work_unit_id, snapshot, actor='operator')[source]

Reconcile a work unit against a persisted live capture.

Reads the captured PDF from secure storage into memory and delegates to the existing local-only reconciler; the reconciler never contacts AEAT and never writes the plaintext receipt to disk. This is the live-sourced equivalent of the operator hand-passing a downloaded justificante via the local reconcile file --file PATH surface.

Return type:

ModeloReconciliationReport

Returns:

A ModeloReconciliationReport for the in-memory receipt comparison.

Parameters:
register_capture_as_filing_evidence(*, snapshot)[source]

Stamp a persisted live capture as official evidence on its filing record.

Loads the work unit’s current filing record first; with one present, parses the captured receipt into a domain Justificante (keyed by the capture’s CSV, which is the gate’s evidence reference), registers it, and updates the filing record to carry AEAT_LIVE_CAPTURE external evidence referencing it. After this, the cross-period clean-state gate’s MISSING_JUSTIFICANTE_VERIFICATION blocker clears for the period, because aeat_live_capture is a justificante-verified evidence kind and the referenced justificante record loads. Emits a MODELO_LIVE_EVIDENCE_STAMPED bucket event recording the action.

Returns the stamped ModeloRecord.

Raises:

LiveApplicationInputError – when no current filing record exists for the captured (modelo, filing_year, period) — the operator must file the period before attaching live-capture evidence to it.

Return type:

ModeloRecord

Parameters:

snapshot (JustificanteCaptureSnapshot)

stamp_capture_evidence_if_filed(snapshot)[source]

Best-effort variant of register_capture_as_filing_evidence().

Returns the stamped ModeloRecord when the captured period has a current filing record, or None when none exists yet (the snapshot is still persisted; the operator can stamp later by filing the period, then re-capturing) or the captured PDF is not parseable into a justificante. Used by the capture orchestrator so a capture of a period not yet filed in-app does not fail. A present-but-conflicting local filing record is not best-effort: identity, period, modelo, and existing-evidence conflicts propagate to the caller.

Return type:

ModeloRecord | None

Parameters:

snapshot (JustificanteCaptureSnapshot)