aeat.application.invoices._bulk_import module¶
Bulk CSV/XLSX transport for creating catalogue Invoice records.
The accountant/gestor batch case: a spreadsheet of invoice rows (counterparty
NIF, invoice number, date, taxable base, IVA rate) is turned into one
Invoice per row. This module is a typed transport
over create_catalogue_invoice() – the sole
sanctioned Invoice writer (composition-service-no-parallel-write-path);
it never persists a row itself.
Each row’s identity is the same content-derived
invoice_id hash the single-invoice
catalogue create verb and the evidence-confirm slice use, so a re-import of
an unchanged file is a guarded no-op per row
(single-subject-mutation-is-idempotent-guarded): an already-catalogued
identical row is reported skipped_duplicate, never re-written and never
raised as an error. A malformed row (missing required field, invalid NIF,
unsupported IVA rate) is collected as a refused row carrying its 1-based
CSV row number and the failing field, and the remaining valid rows are still
applied – partial-success semantics matching the ledger CSV import and bulk
classify pattern (no-silent-under-declaration: a bad row is reported, never
silently dropped).
See also
import_invoices_from_rows()Public application facade for applying validated bulk rows.
create_catalogue_invoice()Single catalogue writer invoked for every accepted row.
create_invoice_via_wizard()Manual single-invoice path with the same writer and idempotent identity.
confirm_invoice_draft_from_evidence()Evidence-confirm path that also delegates the final invoice write to the catalogue writer.
- class BulkInvoiceImportRow(**data)[source]¶
Bases:
BaseModelOne parsed row from a bulk invoice import CSV/XLSX file.
Mirrors the operator fields
aeat app ledger invoice catalogue createaccepts one at a time;taxable_baseandiva_ratesynthesise the single line item exactly asbuild_catalogue_invoice()does for the single-invoice verb, so a bulk row produces an identicalInvoiceshape.- Parameters:
- counterparty_nif: str¶
- counterparty_name: str¶
- invoice_number: str¶
- invoice_date: date¶
- taxable_base: Decimal¶
- iva_rate: Decimal | None¶
- currency: str¶
- country_code: str¶
- notes: str¶
- class BulkInvoiceImportRowFailure(**data)[source]¶
Bases:
BaseModelOne row that could not be parsed or persisted during a bulk import.
- row_number: int¶
- field: str¶
- reason: str¶
- class BulkInvoiceImportResult(**data)[source]¶
Bases:
BaseModelAggregate outcome of one bulk invoice import run.
Uses the same partial-success semantics as the ledger CSV import and bulk classify surfaces: every parseable, non-duplicate row is created; rows that fail validation are collected in
refused; rows whose derivedinvoice_idalready exists in the catalogue are counted inskipped_duplicate(the idempotent-guarded re-import no-op) rather than raised as an error.- Parameters:
- rows: int¶
- created: int¶
- skipped_duplicate: int¶
- refused: tuple[BulkInvoiceImportRowFailure, ...]¶
- created_invoice_ids: tuple[str, ...]¶
- read_bulk_invoice_import_rows(path)[source]¶
Yield
(row_number, raw_row)pairs from a CSV or XLSX bulk-import file.row_numberis 1-based against the file’s own rows (the header is row 1), so a refusal names exactly the row an operator would count by opening the file in a spreadsheet application.
- import_invoices_from_rows(rows, *, bucket_id, kind, repository=None)[source]¶
Create one catalogue
Invoiceper valid row in rows.Every accepted row is handed to
create_catalogue_invoice()– this function never persists a row itself (composition-service-no-parallel-write-path). BecauseInvoiceidentity is a content-derived hash of(kind, invoice_number, issued_at, counterparty_tax_id, currency, grand_total), re-importing the identical file a second time resolves every row to its already-cataloguedinvoice_idand reports it inskipped_duplicate– no second write, no raised error (single-subject-mutation-is-idempotent-guarded). A row whose resolved fields genuinely differ (a corrected amount, a new invoice number) mints a distinct record rather than overwriting one filer’s data with another’s.A malformed row (missing/blank required field, invalid date, unsupported IVA rate percentage, invalid NIF) is collected in
refusedwith its row number and the failing field name; the remaining valid rows still import (partial-success semantics).- Return type:
- Parameters:
bucket_id (str)
kind (InvoiceKind)
repository (InvoiceCatalogueRepositoryProtocol | None)