Module adcp.reporting.receipts.capture
Immutable receipt dirty inputs; projection activation belongs to B2.4.
Functions
def decode_receipt_boundary(value: dict[str, Any]) ‑> ReportingReceiptBoundary-
Expand source code
def decode_receipt_boundary(value: dict[str, Any]) -> ReportingReceiptBoundary: result = None try: if type(value) is dict and type(value.get("version")) is int and value["version"] == 1: result = ReportingReceiptBoundary( ReportingDeliveryPrincipal(value["account_id"], value["consumer_id"]), value["sequence"], value["account_sequence"], value["reporting_receipt_id"], datetime.fromisoformat(value["as_of"]), _core_adapter().validate_python(value["core"]), tuple(decode_record(r) for r in value["reconciliation"]), ) except (ValueError, TypeError, KeyError, ValidationError): # Raise the closed history error below without exposing decoder exception context. pass if result is None or result.to_storage() != value: raise ReportingReceiptError("RECEIPT_HISTORY_CORRUPT") return result
Classes
class ReportingReceiptBoundary (caller: ReportingDeliveryPrincipal,
sequence: int,
account_sequence: int,
reporting_receipt_id: str,
as_of: datetime,
core: ReportingStatusSnapshot,
reconciliation: tuple[ReportingDeliveryRecord, ...])-
Expand source code
@dataclass(frozen=True) class ReportingReceiptBoundary: caller: ReportingDeliveryPrincipal sequence: int account_sequence: int reporting_receipt_id: str as_of: datetime core: ReportingStatusSnapshot = field(repr=False) reconciliation: tuple[ReportingDeliveryRecord, ...] = field(repr=False) def __post_init__(self) -> None: receipts = tuple( r for r in self.reconciliation if isinstance(r, (ReportingRevisionReceiptRecord, ReportingAdjustmentReceiptRecord)) and r.reporting_receipt_id == self.reporting_receipt_id ) if ( type(self.sequence) is not int or self.sequence < 1 or type(self.account_sequence) is not int or self.account_sequence < self.sequence or self.core.account_id != self.caller.account_id or self.core.as_of != self.as_of or self.core.consumer_ids != (self.caller.consumer_id,) or any(s.consumer_id != self.caller.consumer_id for s in self.core.statuses) or any( i.consumer_id not in {None, self.caller.consumer_id} for i in self.core.lifecycles ) or any(principal(r) != self.caller for r in self.reconciliation) or len(receipts) != 1 or receipts[0].received_at != self.as_of ): raise ReportingReceiptError("RECEIPT_HISTORY_CORRUPT") object.__setattr__(self, "as_of", aware_utc(self.as_of)) def to_storage(self) -> dict[str, Any]: return { "version": 1, "admission_epoch": 0, "account_id": self.caller.account_id, "consumer_id": self.caller.consumer_id, "sequence": self.sequence, "account_sequence": self.account_sequence, "reporting_receipt_id": self.reporting_receipt_id, "as_of": self.as_of.isoformat(), "core": _core_adapter().dump_python(self.core, mode="json"), "reconciliation": [payload(r) for r in self.reconciliation], }ReportingReceiptBoundary(caller: 'ReportingDeliveryPrincipal', sequence: 'int', account_sequence: 'int', reporting_receipt_id: 'str', as_of: 'datetime', core: 'ReportingStatusSnapshot', reconciliation: 'tuple[ReportingDeliveryRecord, …]')
Instance variables
var account_sequence : intvar as_of : datetime.datetimevar caller : ReportingDeliveryPrincipalvar core : ReportingStatusSnapshotvar reconciliation : tuple[ReportingDestinationBinding | ReportingObligationDeliveryRecord | ReportingMaterializationAttempt | ReportingMaterializationRecord | ReportingMaterializationCheck | ReportingRevisionReceiptRecord | ReportingAdjustmentReceiptRecord, ...]var reporting_receipt_id : strvar sequence : int
Methods
def to_storage(self) ‑> dict[str, typing.Any]-
Expand source code
def to_storage(self) -> dict[str, Any]: return { "version": 1, "admission_epoch": 0, "account_id": self.caller.account_id, "consumer_id": self.caller.consumer_id, "sequence": self.sequence, "account_sequence": self.account_sequence, "reporting_receipt_id": self.reporting_receipt_id, "as_of": self.as_of.isoformat(), "core": _core_adapter().dump_python(self.core, mode="json"), "reconciliation": [payload(r) for r in self.reconciliation], }