Source code for cadrumo.adapters.persistence.profile.submission
"""Governed-persistence repository for submission audit records.Submission audit records keep the local or imported:class:`domain.submission.models.ModeloPresentado` lifecycle: draft id, modelo,period, taxpayer identity, AEAT receipt metadata when observed, and attemptsummaries. They are stored as encrypted byte objects in the primary SQL backendat ``AUDIT`` :class:`~core.classification.policies.SensitivityClass`; noplaintext submission JSON or envelope file lands on disk.This concrete repository is the persistence adapter behind the read-side:class:`domain.submission.protocols.SubmissionRepositoryProtocol`. It lives in thepersistence adapter (not in :mod:`domain.submission`) because its base:class:`~adapters.persistence.storage.envelope.secure_bound_repository.SecureBoundRepository` isSQL/crypto-coupled; the domain package depends only on the structural port.See Also: :class:`domain.submission.models.ModeloPresentado` Payload model encrypted by this repository. :class:`domain.submission.protocols.SubmissionRepositoryProtocol` Domain-facing read port this repository satisfies structurally. :class:`adapters.persistence.storage.sql.secure_objects.SecureObjectRepository` SQL object store underlying the bound repository."""from__future__importannotationsfromcollections.abcimportIteratorfromtypingimportClassVar,overridefrompydanticimportValidationErrorfrom....core.classification.policiesimportSensitivityClassfrom....core.loggingimportget_loggerfrom....domain.submission.modelsimportModeloPresentadofrom..storage.envelope.secure_bound_repositoryimportSecureBoundRepositoryfrom..storage.secure_object_namespacesimportSUBMISSION_RECORDS_NAMESPACE_log=get_logger(__name__)
[docs]classSubmissionRepository(SecureBoundRepository[ModeloPresentado]):"""Encrypted AUDIT repository for :class:`ModeloPresentado` records. The :class:`~adapters.persistence.storage.envelope.secure_bound_repository.SecureBoundRepository` base stores each :class:`ModeloPresentado` in a :class:`~adapters.persistence.storage.envelope.contract.Envelope` row under the AUDIT submission-records namespace. The natural key is the submission id, so the list and iteration APIs expose historical filing attempts rather than any live submission capability. See Also: :class:`domain.submission.protocols.SubmissionRepositoryProtocol` Domain read port this class satisfies. :class:`~adapters.persistence.storage.sql.secure_objects.SecureObjectRepository` SQL object store composed by the bound repository base. """namespace:ClassVar[str]=SUBMISSION_RECORDS_NAMESPACE.namespacesensitivity:ClassVar[SensitivityClass]=SUBMISSION_RECORDS_NAMESPACE.sensitivityschema_version:ClassVar[int]=SUBMISSION_RECORDS_NAMESPACE.schema_version
[docs]deflist_submission_ids(self)->tuple[str,...]:"""Return every submission id persisted in this repository, in lexicographic order."""returntuple(sorted(self.iter_ids()))
[docs]defiter_submissions(self)->Iterator[ModeloPresentado]:"""Yield every persisted submission, in lexicographic id order. Audit-record enumeration is resilient: rows that fail classification or schema-version gates are logged and skipped rather than aborting the iteration. Diagnostic surfaces depend on listing all healthy submissions even when a single row is unreadable. An identity mismatch is NOT in that resilient category and raises. This scan is custom rather than the base repository's, so the identity check ``load`` performs did not reach it: a valid filing attempt B stored under A's row key was yielded here as an ordinary submission, corrupting audit-history identity. Such a row is perfectly READABLE -- it is simply filed under a key it does not describe -- so skipping it would both hide the inconsistency and silently shorten the history a caller is auditing. Returns: Iterator over :class:`ModeloPresentado` records. Raises: SecureObjectRowIdentityError: A row's payload rebuilds a different submission id than the key it is filed under. """from..storage.crypto.encrypted_columnsimportsecure_object_key_digestfrom..storage.errorsimportSecureObjectRowIdentityErrorfrom..storage.sql.secure_object_recordsimportSecureObjectRecordenvelope_cls=self._envelope_cls()records:list[tuple[str,ModeloPresentado]]=[]foriteminself.secure_object_repository.iter_records_with_failures(self.namespace,expected_class=self.sensitivity,max_supported_version=self.schema_version,):ifnotisinstance(item,SecureObjectRecord):_log.warning("iter_submissions: skipping unreadable submission row_id=%s reason=%s",getattr(item,"row_id","unknown"),getattr(item,"reason","unknown"),)continuetry:envelope=envelope_cls.model_validate_json(item.payload)exceptValidationError:_log.warning("iter_submissions: skipping invalid submission payload object_key=%s",item.object_key.hex(),exc_info=True,)continuepayload=envelope.payloadifsecure_object_key_digest(payload.submission_id)!=item.object_key:raiseSecureObjectRowIdentityError(self.namespace,expected_identifier=payload.submission_id,)records.append((payload.submission_id,payload))for_,payloadinsorted(records,key=lambdarecord:record[0]):yieldpayload