cadrumo.application.ledger.invoice_label_reader module

Read invoice fields from a text-layer transcription by fixed label rules.

The deterministic rung of the text lane. It runs before any model, over the same DocumentTranscription the semantic reader would receive, and recovers only what a printed label assigns: Base imponible: 1.200,00, IVA 21 %: 252,00, Total factura, NIF under a party heading. Labels are matched in Spanish, Catalan and English.

Nothing is inferred. A value no label introduces is not read; a label that introduces two different values is recorded as an ambiguity and left empty; an amount whose thousands separator could be read two ways is left empty with both readings recorded. Every monetary figure is then cross-checked:

  • each rate tier: base * rate / 100 == cuota (and the recargo tier alike);

  • the invoice: base + cuota + recargo + suplidos == total;

  • the retención: base * rate / 100 == amount, and it sits outside the total, so a printed amount payable must equal total - retención.

A figure that does not reconcile is cleared and a DraftDiscrepancyFinding of the same kinds the shared closure check emits is recorded in its place, so a non-closing document never yields a plausible-looking draft.

Envelopes leave this module UNANCHORED with the printed form as their anchor, exactly as the semantic reader’s do; the grounding pass that follows checks every anchor against the transcription.

LABEL_READER_REQUIRED_FIELDS

Fields that must be read for the label reading to stand without a model.

iva_rate is added for a single-rate document; a multi-rate document carries its rates in the per-rate breakdown instead. The customer is not required: a factura simplificada legitimately names none.

class LabelReading(**data)[source]

Bases: BaseModel

What the label rules recovered from one transcription.

Variables:
  • draft – The rule-read draft: values, TEXT_RULES envelopes and the findings the rules raised.

  • read_fields – The draft fields that carry a rule-read value.

Parameters:

data (Any)

draft: InvoiceDraft
read_fields: frozenset[str]
property required_fields: frozenset[str]

The fields this document needs before the rules can stand alone.

A single rate is required only where cuota was charged: a multi-rate document states its rates per tier, and a zero cuota states none.

property missing_required_fields: frozenset[str]

Required fields the rules did not read.

property complete: bool

Whether every required field was read, so no model is needed.

read_invoice_fields_by_labels(transcription, *, operation)[source]

Read every labelled invoice field the transcription prints.

Parameters:
Returns:

the same text always yields the same reading.

Return type:

The rule-read draft and the set of fields it populated. Deterministic

text_layer_reads_completely_by_labels(data, *, text_layer_ports, operation)[source]

Return whether a PDF’s text layer reads completely without a model.

The same predicate the extraction router applies before calling the text model, exposed for callers that must decide ahead of extraction whether a document needs the inference lane at all. A document without a usable text layer answers False.

Return type:

bool

Parameters:
merge_label_reading_with_model_draft(reading, model_draft)[source]

Fill the fields the rules could not read from a model’s draft.

Every field the rules read keeps its rule value and envelope; the model contributes only the rest. The rules’ arithmetic findings are dropped once the model has supplied figures, because the shared closure check re-runs on the merged figures and would otherwise report the same identity twice. Identity findings are kept once per field.

Return type:

InvoiceDraft

Parameters: