Source code for cadrumo.application.live.justificante_ports

"""Application ports for live justificante capture.

The capture workflow names only the values it needs from Sede and from local
storage.  Adapter and entrypoint code implement these ports; this module owns
no transport, browser, parser, or secure-store construction.
"""

from __future__ import annotations

from collections.abc import Awaitable, Callable, Sequence
from dataclasses import dataclass
from datetime import datetime
from typing import Protocol

from ...core.period import Period
from ...domain.justificante.schema import Justificante
from ...domain.modelos.filing_record import ModeloRecordCatalogue
from .filed_observation_ports import FiledFilingReconciliationPort


[docs] @dataclass(frozen=True, slots=True) class JustificanteDeclaration: """Period-bearing declaration data used to select an expediente.""" modelo: str period: Period expediente_id: str estado: str presented_at: datetime
[docs] @dataclass(frozen=True, slots=True) class JustificanteExpediente: """Minimal Sede procedure-tree entry needed to fetch a receipt.""" expediente_id: str
[docs] @dataclass(frozen=True, slots=True) class CapturedJustificante: """Authenticated receipt bytes and Sede references returned by a live read.""" expediente_id: str csv: str pdf_bytes: bytes pdf_sha256: str
[docs] class JustificanteSnapshotPersistencePort(Protocol): """Bucket-bound encrypted persistence for capture snapshots.""" @property def bucket_id(self) -> str: """Return the bucket identity that owns these snapshots.""" ...
[docs] def exists(self, snapshot_id: str) -> bool: """Return whether a snapshot identifier is persisted.""" ...
[docs] def load(self, snapshot_id: str) -> object: """Load one persisted snapshot by identifier.""" ...
[docs] def list_snapshots(self) -> Sequence[object]: """Return the persisted snapshots visible to this bucket.""" ...
[docs] def resolve(self, snapshot_id: str) -> object: """Resolve one snapshot identifier to its persisted record.""" ...
[docs] def save(self, snapshot: object) -> None: """Persist one capture snapshot through the encrypted store.""" ...
[docs] class JustificanteMetadataPort(Protocol): """Durable metadata registration for a parsed receipt."""
[docs] def save(self, payload: Justificante) -> None: """Persist parsed receipt metadata.""" ...
[docs] class JustificanteFilingPort(Protocol): """Load and save the local filing catalogue."""
[docs] def load(self) -> ModeloRecordCatalogue: """Load the local filing catalogue.""" ...
[docs] def save(self, catalogue: ModeloRecordCatalogue) -> None: """Persist the local filing catalogue.""" ...
[docs] @dataclass(frozen=True, slots=True) class JustificanteRegistrationPorts: """Application-owned local persistence dependencies for receipt enrolment.""" parse_pdf: Callable[[bytes], Justificante] metadata: JustificanteMetadataPort filing: JustificanteFilingPort filing_reconciliation: FiledFilingReconciliationPort
[docs] class JustificanteLiveReadPort(Protocol): """Read the declaration register, procedure tree, and selected receipt."""
[docs] async def declarations_and_expedientes( self, *, modelo: str, year: int, ) -> tuple[Sequence[JustificanteDeclaration], Sequence[JustificanteExpediente]]: """Read declarations and their matching procedure-tree entries.""" ...
[docs] async def capture(self, *, expediente_id: str) -> CapturedJustificante: """Capture one authenticated receipt for an expediente.""" ...
[docs] class JustificanteAuthenticityVerifierPort(Protocol): """Read-only CSV cotejo operation."""
[docs] def verify( self, csv: str, *, browser: object | None = None, browser_session_factory: Callable[[], object] | None = None, ) -> Awaitable[bool]: """Verify a receipt CSV through the live cotejo operation.""" ...