aeat.domain.iva._invoice_classification module¶
Reusable IVA classification record for ledger-side categorization.
Bridges the substrate’s three IVA classification axes
(IvaCategory, IvaRateKind, IvaFlowDirection)
into one frozen pydantic record that the ledger and downstream
filing surfaces can pass around without re-deriving the mapping.
Every IVA-bearing ledger line — invoice line, payment, ledger entry —
carries one IvaInvoiceClassification. The record captures:
The operation kind (domestic / intra-community / recargo / OSS / etc.).
The applicable rate tier (general / reduced / super-reduced / zero / exempt).
The flow direction (output / input / self-assessed reverse charge).
The derived settlement-side classification (devengada and / or deducible) — pre-computed at construction time so consumers don’t have to call
settlement_sides_for_flow()repeatedly.
Why a separate record instead of fields on
aeat.domain.invoices.Invoice?
Multiple ledger surfaces need the same triple — invoice lines, payment-record IVA splits, expense-report ledger lines, OSS / IOSS observations, recargo de equivalencia entries — and embedding the fields directly on each model would scatter the substrate-bridge logic across the codebase. The record is the canonical reusable construct: build one from substrate primitives once, pass it down the ledger pipeline.
The classify_invoice_line_for_iva() helper accepts an
IvaRate plus the invoice direction (issued / received) and
returns a IvaInvoiceClassification for the standard
domestic-IVA case (the most common autónomo operation). For
reverse-charge, intra-community, OSS / IOSS, and other non-domestic
cases, callers construct the record directly with the appropriate
IvaCategory from the substrate’s classifier output
(classify_iva()).
- class IvaInvoiceClassification(**data)[source]¶
Bases:
BaseModelFrozen pydantic record bundling the IVA classification triple and derived settlement sides.
- Variables:
category – Substrate
IvaCategoryclassifying the operation kind.rate_kind – Substrate
IvaRateKindrate tier;Nonefor operations outside the scope of IVA (NOT_SUBJECT, ERRONEOUS_INVOICE, UNKNOWN).flow_direction – Substrate
IvaFlowDirection— REPERCUTIDO (output), SOPORTADO (input), or INVERSION_SUJETO_PASIVO (self-assessed reverse charge).settlement_sides – Pre-computed frozen set of the
IvaSettlementSidecornerstones the line contributes to. Derived fromflow_directionat construction time viasettlement_sides_for_flow()so consumers don’t recompute it.
- Parameters:
category (IvaCategory)
rate_kind (IvaRateKind | None)
flow_direction (IvaFlowDirection)
settlement_sides (frozenset[IvaSettlementSide])
- category: IvaCategory¶
- rate_kind: IvaRateKind | None¶
- flow_direction: IvaFlowDirection¶
- settlement_sides: frozenset[IvaSettlementSide]¶
- classify_invoice_line_for_iva(*, iva_rate, invoice_kind)[source]¶
Build a classification record for the standard domestic-IVA case.
Covers the most common autónomo operation: a domestic invoice issued to a Spanish customer or received from a Spanish supplier at one of the four IVA rate slots (or EXEMPT). The record’s flow direction is derived from
invoice_kind:InvoiceKind.ISSUED→IvaFlowDirection.REPERCUTIDO(the autónomo charged output IVA on a sale).InvoiceKind.RECEIVED→IvaFlowDirection.SOPORTADO(the autónomo bore input IVA on a purchase).
For reverse-charge, intra-community, export, import, recargo de equivalencia, and OSS / IOSS cases, callers construct
IvaInvoiceClassificationdirectly with the appropriateIvaCategoryfrom the substrate classifier (aeat.domain.iva.classify_iva()).- Parameters:
iva_rate (
IvaRate) – One of the closedIvaRateslots.IvaRate.NOT_SUBJECTis rejected — see module docstring for the rationale.invoice_kind (
InvoiceKind) – Whether the invoice was issued (sale) or received (purchase).
- Return type:
- Returns:
A frozen
IvaInvoiceClassificationwith the derived substrate triple and pre-computed settlement-side set.- Raises:
InvoiceValidationError – If
iva_rateisIvaRate.NOT_SUBJECT, which has no rate-tier classification and cannot be handled by the standard-case helper.
- invoice_line_to_iva_observation(*, invoice_id, issued_at, invoice_kind, iva_rate, base_amount, iva_amount)[source]¶
Build an
IvaLedgerObservationfrom invoice line metadata.The runtime resolver for the substrate’s
ledger_iva_aggregationbinding source kind consumesaeat.domain.calculations.registry.IvaLedgerObservationrecords. This helper turns invoice-line metadata into the observation shape the modelo registry expects, applying the standard-case classification (domestic IVA, REPERCUTIDO for issued invoices, SOPORTADO for received). Reverse-charge and intra-community lines must construct the observation directly.The function is the canonical ledger → modelo bridge for the standard-case IVA flows. Callers iterate the invoice’s lines, call this helper for each, and pass the resulting tuple to
resolve_ledger_iva_aggregation_binding_values()to populate the modelo’s binding values.- Parameters:
invoice_id (
str) – Stable id of the source invoice (becomesledger_idon the observation).issued_at (
date) – Invoice issue date (becomestransaction_date).invoice_kind (
InvoiceKind) – Whether the invoice was issued or received.iva_rate (
IvaRate) – IvaRate slot for the line. NOT_SUBJECT raises (substrate-NULL category needs explicit construction).base_amount (
Decimal) – Taxable base in EUR.iva_amount (
Decimal) – IVA amount in EUR.
- Return type:
- Returns:
An
IvaLedgerObservationwith the full classification triple ready for binding-resolver consumption.- Raises:
InvoiceValidationError – If the classification produces a
Nonerate_kind (e.g. wheniva_rateisNOT_SUBJECT).