Source code for aeat.domain.transactions._repository
"""Domain-side transaction-catalogue port surface.This module owns the pure transaction-catalogue persistence vocabulary thatcarries no SQL/crypto coupling: the :class:`ImportSummary` record returned by aledger import, the :func:`transaction_object_key` /:func:`transaction_index_object_key` secure-object key-derivation helpers, andthe :data:`TX_BUCKET_NAMESPACE` / schema-version constants that name thepersisted envelope contract. The concrete encrypted SQL repository lives in thepersistence adapter:class:`~aeat.adapters.persistence.profile.transactions.TransactionCatalogueRepository`,behind the read-side:class:`~aeat.domain.transactions.TransactionCatalogueRepositoryProtocol`; thedomain package depends only on the structural port.The namespace authority is:data:`adapters.persistence.storage.TRANSACTION_CATALOGUE_NAMESPACE`; this modulederives the bucket-local transaction row keys with :func:`transaction_object_key`and the membership-index key with :func:`transaction_index_object_key`."""from__future__importannotationsfrompydanticimportBaseModel,Fieldfrom...coreimportSTRICT_FROZEN_CONFIGfrom...core.identityimportBucketIdfrom._errorsimportLedgerStorageErrorfrom._modelsimportBucketTransactionRef# namespace / schema-version constants naming the persisted-envelope contract;# the concrete repository redeclares them adapter-side._TX_CATALOGUE_VERSION=1TX_BUCKET_NAMESPACE="aeat.domain.transactions.bucket"
[docs]deftransaction_index_object_key(bucket_id:str)->str:"""Return the per-bucket transaction-membership-index secure-object key. The index row shares :data:`adapters.persistence.storage.TRANSACTION_CATALOGUE_NAMESPACE` with the per-transaction rows and bounds reads/deletions to one bucket. """trimmed=bucket_id.strip()ifnottrimmed:raiseLedgerStorageError("bucket_id must not be blank",context={"repository":"transaction_catalogue","operation":"index_object_key"},)returnf"transaction-index:{trimmed}"
[docs]deftransaction_object_key(bucket_id:str,transaction_id:str)->str:"""Return the per-transaction secure-object key within a profile bucket. Each transaction is its own secure-object row. The key qualifies with the bucket id (``transaction:{bucket_id}:{transaction_id}``); cross-bucket aggregation must qualify with ``(bucket_id, tx_id)`` because ``tx_id`` alone is unique only within one bucket. Rows live under :data:`adapters.persistence.storage.TRANSACTION_CATALOGUE_NAMESPACE`. """trimmed=bucket_id.strip()ifnottrimmed:raiseLedgerStorageError("bucket_id must not be blank",context={"repository":"transaction_catalogue","operation":"object_key"},)tx=transaction_id.strip()ifnottx:raiseLedgerStorageError("transaction_id must not be blank",context={"repository":"transaction_catalogue","operation":"object_key"},)returnf"transaction:{trimmed}:{tx}"
[docs]classImportSummary(BaseModel):"""Frozen summary of one ledger import persistence operation. Attributes: imported: Number of new transactions persisted by this call. skipped: Number of input rows already present in the catalogue. A row is a duplicate when its stable import fingerprint (:func:`derive_import_fingerprint`) is already present — the fingerprint is stamped at import and survives both later edits and a re-export in a different file format. errors: Reserved for future per-row error counts; today the repository raises on any error rather than tallying. likely_duplicate_refs: Rows that were imported but share an effective date and amount with an existing transaction while carrying a divergent narrative — a probable, but not confident, cross-format duplicate. The operator is warned so they can review rather than discovering a silent double-count later. catalogue_path: Logical URI of the encrypted database object. """model_config=STRICT_FROZEN_CONFIGimported:int=Field(ge=0)skipped:int=Field(ge=0)errors:int=Field(default=0,ge=0)bucket_id:BucketIdimported_refs:tuple[BucketTransactionRef,...]=()skipped_refs:tuple[BucketTransactionRef,...]=()likely_duplicate_refs:tuple[BucketTransactionRef,...]=()catalogue_path:str