aeat.application.invoices._wizard module

Guided, non-blocking manual-entry path for one catalogue Invoice.

aeat app ledger invoice catalogue wizard is the fallback entry point for when automated extraction (ledger evidence extract / vision OCR) is unavailable or insufficient: the operator (an autonomous LLM agent that cannot answer an interactive prompt) supplies every invoice field as CLI options in one call. This module validates each field independently – reusing the same grounded heuristics validate_spanish_tax_id() and the ISO-8601 / canonical-decimal parsers already enforce on the extract/confirm path – and accumulates every failing field into one refusal (no-silent-under-declaration: a malformed field is named, never silently dropped or reported one-at-a-time when several are wrong).

The write itself delegates to create_catalogue_invoice() – the sole sanctioned Invoice writer (composition-service-no-parallel-write-path); this module never persists a row itself. Because Invoice identity is a content-derived hash, a retry that resolves to an already-catalogued identity is a guarded no-op (single-subject-mutation-is-idempotent-guarded): the existing record is returned, not re-written or raised as an error, mirroring the re-import-of-an-unchanged-file semantics import_invoices_from_rows() already implements for the bulk path.

See also

create_invoice_via_wizard()

Public application facade for this guided manual-entry path.

create_catalogue_invoice()

Single catalogue writer used after field validation succeeds.

import_invoices_from_rows()

Spreadsheet-oriented sibling path with matching idempotency semantics.

extract_invoice_draft_from_evidence()

Automated evidence extraction path this non-interactive wizard complements when OCR is unavailable or insufficient.

class InvoiceWizardFieldError(**data)[source]

Bases: BaseModel

One field that failed the wizard’s guided validation.

Mirrors BulkInvoiceImportRowFailure’s field/reason shape so a manual-entry refusal reads consistently with the bulk-import refusal surface, minus the row number a single-invoice wizard has no use for.

Parameters:
field: str
reason: str
class InvoiceWizardResult(**data)[source]

Bases: BaseModel

Outcome of one guided manual-entry invoice creation.

already_existed is True when the derived identity already named a catalogued invoice – the guarded idempotent no-op path (single-subject-mutation-is-idempotent-guarded): invoice is the pre-existing record and nothing was written.

Parameters:
invoice: Invoice
already_existed: bool
create_invoice_via_wizard(*, bucket_id, kind, counterparty_nif, counterparty_name, invoice_number, invoice_date, taxable_base, iva_rate, currency, country_code='ES', notes='', iva_category=None, operation_type=None, repository=None)[source]

Validate every field, then create (or resolve) one catalogue invoice.

Every field is validated independently and every failure is accumulated before raising, so a malformed NIF and a malformed date are BOTH reported in one refusal rather than the first field masking the second (no-silent-under-declaration). This is a step-wise, non-interactive entry point: it never blocks on stdin – every field is supplied up front as a keyword argument, matching the CLI’s all-options-up-front shape.

Parameters:
  • bucket_id (str) – Active profile bucket the invoice is scoped to.

  • kind (InvoiceKind) – Invoice direction (issued / received).

  • counterparty_nif (str) – Raw counterparty NIF/NIE/CIF or EU IVA number.

  • counterparty_name (str) – Raw counterparty display name.

  • invoice_number (str) – Raw AEAT-significant invoice number.

  • invoice_date (str) – Raw ISO-8601 invoice date string.

  • taxable_base (str) – Raw non-negative decimal taxable base string.

  • iva_rate (str | None) – Raw decimal IVA percentage string, or None/blank for a base-only (exempt) invoice.

  • currency (str) – Raw ISO-4217 currency code (defaults are the caller’s concern; this function validates whatever is passed).

  • country_code (str) – Raw ISO-3166 alpha-2 counterparty country code.

  • notes (str) – Free-text notes.

  • iva_category (IvaCategory | None) – Optional intra-community IVA classification.

  • operation_type (IntracomOperationType | None) – Optional Modelo 349 operation-type clave.

  • repository (InvoiceCatalogueRepositoryProtocol | None) – Optional injected catalogue repository (tests).

Return type:

InvoiceWizardResult

Returns:

InvoiceWizardResult naming the resolved invoice and whether it was newly created or already existed under the same derived identity (the guarded idempotent no-op).

Raises:

InvoiceValidationError – naming every failing field in one message when one or more fields are malformed.