aeat.application.modelo._m036_lifecycle module¶
Modelo 036 declarative-recording contracts, storage, and event emission.
Per the accepted Modelo 036/037 foundation decision, the local app never files a
036. AEAT is the authority; the operator files the declaration at sede or in
person, then records that fact locally through aeat app modelo m036
{alta,modificacion,baja}. This module owns the typed application service behind
that surface: it persists encrypted
LIVE_M036_DECLARATION_NAMESPACE rows,
emits the matching modelo.036.declaration.* bucket event, and exposes the
same SecureSnapshotRepository path for list/view
read-back.
The closed event-kind axis comes from
CensoModeloEventKind, whose values are
derived from the registry-owned censo foundation. Modelo 037 remains historical
metadata and is intentionally outside this recording surface.
See also
aeat.domain.calculations.registry._censo_modelosRegistry-owned Modelo 036 active-foundation and Modelo 037 historical routing.
aeat.entrypoints.cli._modelo_m036_cliThin Typer boundary that turns CLI verbs into these application commands.
aeat.domain.buckets.BucketEventTypeDeclares the
CENSO_DECLARATION_ALTA,CENSO_DECLARATION_MODIFICACION, andCENSO_DECLARATION_BAJAaudit events emitted here.
- derive_m036_declaration_id(*, profile_id, event_kind, declared_on, sede_justificante)[source]¶
Content-address the declaration tuple as 64-char lowercase SHA-256 hex.
The address makes a replay of the same operator-declared filing idempotent: a second invocation with identical inputs hashes to the same
declaration_idand the secure-object write becomes a no-op overwrite of the same row.sede_justificanteis folded in unmangled ("-"when omitted) so a same-day same-kind re-declaration that acquires the acuse is recorded as a distinct record, not silently coalesced with the pre-acuse draft.The
event_kindmember is aCensoModeloEventKind, so the digest can only describe one of the registry-backedalta,modificacion, orbajalifecycle events.- Return type:
- Parameters:
profile_id (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=36, pattern=^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$, ascii_only=None)])
event_kind (CensoModeloEventKind)
declared_on (date)
sede_justificante (str | None)
- class M036DeclarationCommand(**data)[source]¶
Bases:
BaseModelOperator request to record an M036 declaration filed at sede.
The operator files the 036 with AEAT through the sede portal (or in person at an oficina). This command records that the declaration happened locally so the downstream stale-cascade + audit-trail logic can react. The command MUST NOT trigger any local filing action.
event_kindis typed asCensoModeloEventKind, preserving the registry foundation’s closed event set at the application boundary.- Parameters:
profile_id (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=36, pattern=^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$, ascii_only=None)])
event_kind (CensoModeloEventKind)
declared_on (date)
sede_justificante (str | None)
note (str | None)
- profile_id: ProfileId¶
- event_kind: CensoModeloEventKind¶
- declared_on: date¶
- sede_justificante: str | None¶
- note: str | None¶
- class M036DeclarationResult(**data)[source]¶
Bases:
BaseModelOutcome of a successful declaration-recording call.
Carries the content-addressed declaration id (SHA-256 over the derived tuple), the canonical event-kind, the declared date, the bucket scope of the record, and the timestamp at which the local record was written. The
bucket_idfield bridges the storage cross-check SecureSnapshotRepository performs when loading and saving records (it refuses payloads whose bucket disagrees with the repository binding), per the M036-declaration-service Path A ADR decision. Downstream consumers (stale-cascade engine, profile-state re-derivation) read these fields to decide what to recompute.The record is the payload model for
SecureSnapshotRepositoryrows stored underLIVE_M036_DECLARATION_NAMESPACE.- Parameters:
declaration_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)])
profile_id (Annotated[str, StringConstraints(strip_whitespace=True, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=36, pattern=^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$, ascii_only=None)])
event_kind (CensoModeloEventKind)
declared_on (date)
sede_justificante (str | None)
note (str | None)
recorded_at (datetime)
- declaration_id: str¶
- bucket_id: BucketId¶
- profile_id: ProfileId¶
- event_kind: CensoModeloEventKind¶
- declared_on: date¶
- sede_justificante: str | None¶
- note: str | None¶
- recorded_at: datetime¶
- list_m036_declarations(*, bucket_id)[source]¶
Return every recorded M036 declaration in the active bucket.
Reads through the same
SecureSnapshotRepositorythe write path persists into (no parallel read path), enumerating the encryptedLIVE_M036_DECLARATION_NAMESPACErows scoped tobucket_idand returning the typedM036DeclarationResultrecords verbatim — every persisted field (declaration_id,event_kind,declared_on,recorded_at,sede_justificante,note) is preserved, never collapsed to a flat mapping. An empty bucket returns an empty tuple, the clean “no declarations recorded yet” signal, not an error.
- read_m036_declaration(declaration_id, *, bucket_id)[source]¶
Return one recorded M036 declaration by id or unambiguous prefix.
Reads through the owning
SecureSnapshotRepository, resolving the full content-addresseddeclaration_idor an unambiguous prefix of it to a single typedM036DeclarationResult. Raises the repository’s not-found error for an unknown id and the ambiguous-prefix error when a prefix matches more than one record, mirroring the established secure-object id-or-prefix resolution.- Return type:
- Parameters:
- record_m036_declaration(command, *, bucket_id)[source]¶
Persist an M036 declaration record and emit its BucketEvent.
Records that the operator filed an M036 declaration at sede. The local app NEVER files; this verb only records the operator’s declaration so downstream profile-state re-derivation and stale-cascade reasoning can react. The content-addressed
declaration_idkeeps a re-declaration with the identical tuple idempotent; the parallelBucketEvent(one ofBucketEventType.CENSO_DECLARATION_ALTA/CENSO_DECLARATION_MODIFICACION/CENSO_DECLARATION_BAJA) carries the audit-trail entry the composition-service rule requires alongside the data write, saved via theBucketEventHistoryRepository.The persisted
M036DeclarationResultis encrypted into the bucket-localLIVE_M036_DECLARATION_NAMESPACErow keyed bym036-declaration:<bucket_id>:<declaration_id>via the standardSecureSnapshotRepositorymachinery (shared with thelist_m036_declarations()/read_m036_declaration()read-back surface through_m036_declaration_repository()).bucket_idis checked against the repository binding at save time, so a cross-bucket payload cannot land silently.See also
CensoModeloEventKindaeat.domain.buckets.BucketEventTypeLIVE_M036_DECLARATION_NAMESPACE- Return type:
- Parameters:
command (M036DeclarationCommand)
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)])