Source code for aeat.domain.justificante._errors

"""Error hierarchy for the justificante parser.

Defines the typed exceptions raised by :mod:`domain.justificante`
when a PDF filing receipt cannot be parsed, when no Código Seguro de
Verificación is present, or when the live AEAT verification round-trip
fails. Every class derives from :class:`PdfModeloImportError` so PDF
filing import callers can catch the whole domain at once.
"""

from __future__ import annotations

from collections.abc import Mapping
from decimal import Decimal

from ...core.errors import AeatError


[docs] class PdfModeloImportError(AeatError): """Domain-level root for PDF filing import failures."""
[docs] class PdfExtractionCoverageMixin: """Shared structured-attribute ``__init__`` for PDF extraction coverage failures. Both the justificante and declaración PDF parsers raise a coverage error that carries the same four structured attributes describing which target fields (field names for justificante, casilla IDs for declaración) could not be extracted cleanly. Mixing this in once keeps the attribute shape and constructor signature identical across both parser error hierarchies instead of each declaring its own copy. Attributes: missing: Tuple of target identifiers that produced no match in the PDF text. malformed: Tuple of target identifiers whose captured value could not be coerced to the target type (e.g. an invalid decimal literal). ambiguous: Tuple of target identifiers that matched more than one region. coverage: Fraction of required targets successfully extracted (``Decimal``). ``None`` when the error is not a coverage failure. """ def __init__( self, message: str | None = None, *, context: Mapping[str, object] | None = None, suggestion: str | None = None, translated_message: str | None = None, missing: tuple[str, ...] = (), malformed: tuple[str, ...] = (), ambiguous: tuple[str, ...] = (), coverage: Decimal | None = None, ) -> None: """Initialise the error with optional structured extraction-coverage context. Args: message: Human-readable error message. context: Optional structured context forwarded to the :class:`core.errors.AeatError` boundary. suggestion: Optional copy-paste recovery hint forwarded to :class:`core.errors.AeatError`. translated_message: Optional locale key rendered at the CLI boundary. missing: Target identifiers that produced no match in the PDF text. malformed: Target identifiers whose captured value could not be coerced. ambiguous: Target identifiers that matched more than one region. coverage: Fraction of required targets successfully extracted, or ``None`` when the error is not a coverage failure. """ super().__init__( message, context=context, suggestion=suggestion, translated_message=translated_message, ) self.missing: tuple[str, ...] = missing self.malformed: tuple[str, ...] = malformed self.ambiguous: tuple[str, ...] = ambiguous self.coverage: Decimal | None = coverage
[docs] class JustificanteError(PdfModeloImportError): """Base class for every justificante-related failure."""
[docs] class JustificanteParseError(PdfExtractionCoverageMixin, JustificanteError): """Raised when a PDF cannot be parsed into a :class:`Justificante`. Mirrors :class:`adapters.inbound.declaracion.DeclaracionParseError`'s structured-attribute shape (via the shared :class:`PdfExtractionCoverageMixin`) so callers can assert on typed attributes rather than parsing the message string. """
[docs] class JustificanteCsvNotFoundError(JustificanteParseError): """Raised when a PDF does not contain a Código Seguro de Verificación."""
[docs] class JustificanteVerificationError(JustificanteError): """Raised when the live CSV verification round-trip fails."""