cadrumo.adapters.inbound.notificacion.sancion module

Deterministic regex parser for AEAT sanción / liquidación notification PDFs.

The documents AEAT serves behind a notification’s comparecencia are text-native: their printed figures carry a real text layer, so there is nothing to OCR and nothing to infer. This parser is therefore regex-first and fully deterministic — no language model sits anywhere on this path. The numbers it returns are numbers a taxpayer pays or appeals against, and a probabilistic reader that is usually right is the wrong instrument for a figure that gets filed.

The parser has exactly two outcomes: a complete SancionLiquidacion, or a SancionParseError naming every field it could not resolve. There is deliberately no partial record and no zero-filled record. A reader that returns clean zeros against a populated surface reads as “nothing owed” at every layer above it, which is precisely how a silent under-declaration reaches a filing.

Layout robustness rests on three independent guards rather than on trusting one template:

  • Anchored value shapes. Money must match the AEAT two-decimal comma-tailed shape end to end (is_aeat_printed_money(), the one house grammar, which the IVA compensation wallet reader consults too), never merely contain one. A template that begins printing whole euros surfaces as the shape change it is instead of being silently reinterpreted as a thousands-grouped integer.

  • Conflicting-repeat detection. AEAT repeats labels across page headers and summary blocks. A label repeated with the SAME value is a repeat; a label repeated with DIFFERENT values is genuinely ambiguous and refuses, because no single reading of it is defensible.

  • Printed-line reconciliation. Every figure below is printed on the one document, so they must reconcile with each other. This checks the PARSE, not AEAT’s arithmetic: a divergence means a label was bound to the wrong number.

Reconciliation is layout-independent by construction. AEAT prints the reducciones either flat (each subtracted from the sanción) or sequentially (each applied to the running amount), and both yield the same final payable: S - r_conformidad - r_pronto_pago either way. Only the intermediate labels differ, so binding the payable to Importe a ingresar when printed and to Diferencia otherwise reads both layouts correctly, and any third layout refuses loudly rather than answering confidently.

parse_sancion_document(text, *, certificado_id, document_sha256, effective_date=None, authority=None)[source]

Parse the extracted text of one AEAT sanción / liquidación PDF.

Parameters:
  • text (str) – The document’s extracted text layer, page order preserved and otherwise untransformed. Printed forms must survive verbatim: 3.687,12 stays 3.687,12, because the anchored shape check runs against exactly what AEAT printed.

  • certificado_id (str) – The notification the document was served under.

  • document_sha256 (str) – Digest of the PDF bytes the text was extracted from.

  • effective_date (date | None) – Filing-period coordinate used to resolve the statutory sanction reductions. When the document surface carries no reliable legal coordinate, the current date is used by the direct reader.

  • authority (PinnedAuthorityOperation | None) – Existing generation-pinned facts operation. Omitted callers open one indexed operation at this top-level boundary and still fail closed when the reduction fact is absent or malformed.

Return type:

SancionLiquidacion

Returns:

The complete SancionLiquidacion.

Raises:
  • SancionParseError – When any required label is missing, any printed value fails its anchored shape check, or a label repeats with conflicting values. The error names every failing field.

  • SancionArithmeticError – When the printed lines do not reconcile with each other, which means a label was bound to the wrong number.