cadrumo.application.ledger.invoice_confirmation module¶
Confirming a reviewed invoice draft into a persisted catalogue record.
The non-interactive CONFIRM step that closes the review loop: it re-runs the
on-host extraction through
extract_invoice_draft_from_evidence(),
applies any operator-supplied field overrides (extraction is best-effort, so
every field may be corrected), and delegates the actual write to
create_catalogue_invoice() – the sole sanctioned
Invoice writer (aeat-architecture-boundaries).
This module never writes the InvoiceCatalogue itself.
The confirm runs in three stages, each a function of its own so the guards cannot be reordered by accident:
Prepare. Re-read the document, stamp a direction contradiction as an
ordinary resolvable finding, resolve the review gate’s blockers, and resolve
both parties’ establishment. Build. Resolve every persisted field from the
operator’s statement layered over the reading, through the guards in
confirm_party_identity and the resolvers in
confirmed_field_resolution. Persist. Apply the
idempotency guards, link the evidence, and write the confirmation record.
Idempotent-guarded (aeat-cli-contract). Two distinct identities are checked,
in that order, and the order matters: DOCUMENT identity first – the attachment
address is the SHA-256 of the bytes, so it answers “has this document already
been turned into a record” exactly – then invoice identity, which folds only
the six resolved fields and therefore cannot answer it. A retry resolving every
compared field identically returns the existing invoice unchanged; a re-confirm
of one document that DIFFERS refuses, naming the divergent fields, rather than
minting a second catalogue record that would aggregate twice into Modelo 303,
347 and 390.
Confirming also auto-links the source evidence to the resulting invoice:
link_attachment_invoice() appends the invoice’s id
to the backing Attachment’s
linked_invoice_ids, closing the
provenance loop in both directions. The link is re-asserted on a guarded no-op
confirm too, so a re-confirm never regresses a provenance link that was never
wired for older evidence, and the append itself is idempotent.
See also
extract_invoice_draft_from_evidence()The reading stage this confirm re-runs.
printed_total_discrepancy()The printed-versus-recorded cross-check carried on every result.
InvoiceConfirmationRecordThe durable account of who confirmed what, written by every confirm.
create_catalogue_invoice()Sole sanctioned writer for the resulting catalogue invoice.
- class InvoiceConfirmationResult(**data)[source]¶
Bases:
BaseModelOutcome of confirming a reviewed
InvoiceDraftinto anInvoice.- Variables:
invoice – The persisted (or already-existing, on a guarded no-op)
Invoice.draft – The re-run on-host extraction the confirmation was based on (before overrides were applied), kept so the operator can see what was actually read from the document versus what they overrode.
created –
Truewhen this call minted a new catalogue row;Falsewhen an invoice with the identical derived identity already existed and this call returned it unchanged (the guarded idempotent-retry no-op).total_discrepancy – Set when the document’s printed total disagrees with the derived total now on record – see
PrintedTotalDiscrepancyfor why that is always worth surfacing.Nonewhen they agree or no total was readable. The field rides the RESULT rather than being recomputed by each caller so a consumer cannot silently omit the check.confirmation_id – Derived address of the persisted
InvoiceConfirmationRecordthis confirm wrote – who confirmed, when, which fields they asserted values for with the prior value and origin retained, which findings they answered and how, and the evidence and transcription content addresses it was taken against. The id rather than the record itself: the record is the durable answer and lives in the encrypted store, and a copy riding a transient result is a second account of one decision that can disagree with the first.establishment – Both parties’ IVA territories as this confirm resolved them – the counterparty’s through the evidence ladder, the filer’s own from their profile – beside the classification criteria they were carried into and every territorial question left open.
Noneonly where the resolution was not attempted. A resolved territory rides the RESULT rather than being recomputed per consumer for the same reason the printed-total discrepancy does: a second derivation is a second answer, and the two can disagree about a filing.confirmed_provenance – The draft’s envelopes with every operator-asserted field re-stamped
OPERATOR. Carried BESIDEdraftrather than replacing its envelopes, because a correction is an assertion and not an edit:draft.provenancestays the document’s own account of itself, this is the confirmed view, and the confirmation record holds the pairing of the two.
- Parameters:
data (Any)
- invoice: Invoice¶
- draft: InvoiceDraft¶
- created: bool¶
- total_discrepancy: PrintedTotalDiscrepancy | None¶
- confirmation_id: str | None¶
- confirmed_provenance: tuple[FieldProvenance, ...]¶
- establishment: ConfirmedEstablishment | None¶
- confirm_invoice_draft_from_evidence(*, bucket_id, kind, counterparty_country, evidence_id=None, attachment_id=None, counterparty_tax_id=None, counterparty_name=None, invoice_number=None, invoice_date=None, taxable_base=None, iva_rate=None, currency=None, iva_amount=None, iva_category=None, operation_type=None, operation_date=None, retention_rate=None, retention_amount=None, recargo_amount=None, invoice_class=None, supply_nature=None, series=None, rectifies_invoice_number=None, notes='', resolutions=(), confirmed_by='operator', settings=None, catalogue_creation_ports, invoice_confirmation_ports, counterparty_establishment_repository, evidence_ports, extraction_ports, operation, legends)[source]¶
Re-extract one evidence reference and confirm it into a real
Invoice.Re-runs
extract_invoice_draft_from_evidence()on-host (bytes and text stay in memory only), then layers any operator-supplied override on top of each extracted field – extraction is best-effort, so every field may be corrected before the record is minted. The resulting identity fields are handed tocreate_catalogue_invoice(), the single sanctionedInvoicewriter (aeat-architecture-boundaries); this function never writes the catalogue itself.Idempotent-guarded (
aeat-cli-contract): the persistedinvoice_idis a stable hash of(kind, invoice_number, issued_at, counterparty_tax_id, currency, grand_total)— a confirm carrying identical resolved fields to an already-persisted invoice returns that invoice unchanged (created=False, no new bucket write); a confirm whose resolved fields genuinely differ mints a distinct invoice record rather than overwriting.- Parameters:
bucket_id (
str) – Active ledger bucket the evidence belongs to.kind (
InvoiceKind) – Invoice direction (issuedorreceived). The operator’s statement is the decision. The document is also asked – the reading stage derives which party’s block prints the filer’s own identifier and stamps a suggestion – and a document that settles a direction contradicting this one raises a resolvableDIRECTION_CONTRADICTEDblocker rather than being overridden or silently accepted.counterparty_country (
str) – ISO 3166-1 alpha-2 counterparty country code. Defaults to"ES"; override for a non-Spanish counterparty.evidence_id (
str|None) – Apurchase_invoice_evidencerecord id, orNone.attachment_id (
str|None) – A linked attachment id, orNone. Exactly one of evidence_id / attachment_id must be supplied.counterparty_tax_id (
str|None) – Override for the extracted supplier tax id.counterparty_name (
str|None) – Override (there is no extraction heuristic for the counterparty’s display name yet, so this is normally required).invoice_number (
str|None) – Override for the extracted invoice number.invoice_date (
date|None) – Override for the extracted invoice date.taxable_base (
Decimal|None) – Override for the extracted taxable base.iva_rate (
Decimal|None) – Override for the extracted IVA rate (Noneresolves to the EXEMPT slot, matchingbuild_catalogue_invoice()).currency (
str|None) – ISO-4217 currency code overriding the extracted one. When omitted, the currency printed on the document is used, falling back to euro only when the document shows none.iva_amount (
Decimal|None) – The cuota PRINTED on the document, when it differs from base times rate. A printed figure is evidence and outranks a recomputed one, so supplying it makes the persisted line carry it exactly. The line invariants still apply, so a cuota the base and rate cannot support refuses rather than overriding them.iva_category (
IvaCategory|None) – IVA treatment of the operation. Required for the renta income lane to ground the record.operation_type (
IntracomOperationType|None) – Modelo 349 clave for an entrega intracomunitaria. The category alone cannot distinguish an ordinary supply (clave E) from one following an exempt importation (clave M, or H through a fiscal representative), and no document states which – so the writer demands it and only the operator can answer. Without this the evidence path could confirm no intra-community invoice at all.operation_date (
date|None) – Date the operation was performed, when it differs from the issue date, letting the record reach a declared devengo rank.retention_rate (
Decimal|None) – RIRPF art. 95 withholding fraction, settled OUTSIDE the invoice total.retention_amount (
Decimal|None) – The withheld figure. Accepted alone; required whenever a rate is supplied.recargo_amount (
Decimal|None) – Recargo de equivalencia (LIVA art. 161), which rides INSIDE the invoice total, unlike a retención.supply_nature (
SupplyNature|None) – The operator’s statement of whether the supply is goods or services. Demanded only where the law forks on it – the cross-border and reverse-charge families – so an ordinary domestic invoice never needs one, and supplying it there changes nothing. Until this parameter existed the classifier could REPORT that gap and the operator had no way to answer it, so a cross-border document with no printed statutory citation reached a category of ABSENT with no route forward.invoice_class (
InvoiceClass|None) – Invoice class. A rectificativa also needsrectifies_invoice_number.series (
str|None) – Invoice numbering series, when the issuer uses one.rectifies_invoice_number (
str|None) – Number of the invoice a rectificativa corrects.notes (
str) – Free-text operator notes carried onto the invoice.resolutions (
Sequence[FindingResolution]) – One explicit answer per blocking finding the document raises. A document with findings cannot be confirmed until every one is answered individually; there is no bulk flag, deliberately.confirmed_by (
str) – Who is confirming, recorded in the confirmation provenance record.settings (
Settings|None) – Resolved Settings; load_settings() when omitted.counterparty_establishment_repository (
CounterpartyEstablishmentRepositoryProtocol) – Required remembered counterparty-facts capability for the active bucket.catalogue_creation_ports (
CatalogueCreationPorts) – Required invoice-catalogue repository, event history, and exchange-rate capabilities for the active bucket.invoice_confirmation_ports (
InvoiceConfirmationPorts) – Required attachment-manifest capability for the active bucket. The composition root binds its encrypted implementation; this application service only sees the public attachment protocol.evidence_ports (
LedgerEvidencePorts) – Secure evidence and attachment lookup capabilities for the active bucket.extraction_ports (
InvoiceDraftExtractionPorts) – Application-owned structured, text and vision reader capabilities used to re-extract the document.operation (
PinnedAuthorityOperation) – Caller-owned pinned authority operation retained through extraction, confirmation and catalogue persistence.legends (
tuple[RegimeLegend,...]) – The dated regime declarations resolved fromoperationby the enclosing composition boundary and shared by extraction, grounding and establishment checks.
- Returns:
The persisted (or pre-existing) invoice, the re-run draft it was checked against, and whether this call minted a new record.
- Return type:
- Raises:
PurchaseInvoiceEvidenceInputError – When neither or both of evidence_id / attachment_id are supplied, when evidence_id resolves outside the bytes-bearing evidence-record id space, when the resolved evidence has no usable text layer, or when a required field is
Noneafter overrides (extraction found nothing and the operator supplied no override).InvoiceValidationError – When the resolved fields fail invoice-model validation (e.g. an invalid counterparty tax id or IVA rate).
ConfirmationBlockedError – When the document raises a blocking finding that carries no explicit per-finding resolution.