aeat.application.aggregation._iva_ledger module

Repository-backed IVA observation projection from ledger catalogues.

This module classifies bucket-local TransactionCatalogue rows into typed IvaLedgerObservation records and binding-ready totals. The source-mesh resolver in _modelo_bindings then applies the target ModeloRevision, resolves ledger_iva_aggregation bindings, and surfaces source diagnostics for ledger rows that no declared binding consumes.

When the bucket’s cross-period prorrata register resolves an active general provisional percentage for the filing year, the aggregation result carries IvaLedgerProrrataApportionment. The binding resolver applies that percentage only to deducible IVA cuota bindings; bases and output IVA cuotas stay unapportioned.

The repository-backed entry point constructs a TransactionCatalogueRepository for the active bucket when none is supplied. Pre-classified callers can use IvaLedgerCandidate and aggregate_iva_ledger_candidate_bindings() to run the same validation and registry binding path.

See also

prorrata_register

Per-ejercicio carry home for the provisional percentage consumed by the IVA ledger apportionment.

LedgerIvaAggregationSourceResolver

Source-mesh adapter that calls this projection and records prorrata apportionment provenance.

test_iva_ledger_prorrata_apportionment

Regression coverage proving the active provisional percentage reduces deducible cuotas without reducing bases.

_renta_ledger, _renta_income_ledger, _renta_gasto_ledger

Sibling Renta ledger projections.

class IvaLedgerAggregationIssueReason(*values)[source]

Bases: StrEnum

Machine-readable reasons why a ledger row did not produce IVA observations.

The first five values are shared with RentaLedgerAggregationIssueReason through _shared_issue_reasons so cross-ledger telemetry can group upstream filter rejections under one key. The remaining values are IVA-specific.

UNSUPPORTED_DIRECTION
UNSUPPORTED_CURRENCY
UNCLASSIFIED_BUSINESS_STATE
PERSONAL_TRANSACTION
OUTSIDE_PERIOD
MISSING_TAXABLE_BASE
MISSING_IVA_AMOUNT
MISSING_IVA_RATE
UNSUPPORTED_IVA_RATE
MISSING_EUR_TAX_SUBSTRATE
INVALID_PRORRATA_REFERENCE
UNSUPPORTED_IVA_CATEGORY
MISSING_COUNTERPARTY_EU_MEMBER_STATE
DOMESTIC_COUNTERPARTY_ON_INTRA_COMMUNITY_TRANSACTION
EU_MEMBER_STATE_ON_EXPORT_TRANSACTION
CASH_ACCOUNTING_EXCLUDED_CATEGORY
class IvaLedgerAggregationIssue(**data)[source]

Bases: BaseModel

Traceable exclusion emitted while projecting IVA ledger observations.

Parameters:
transaction_id: str
reason: IvaLedgerAggregationIssueReason
detail: str
class ProrrataLedgerReference(**data)[source]

Bases: BaseModel

Bucket-local ledger row pointer to a legal IVA prorrata reference.

Parameters:
transaction_id: str
transaction_date: date
reference: ProrrataReference
base_amount: Decimal
input_iva_amount: Decimal
class IvaLedgerSectorApportionment(**data)[source]

Bases: BaseModel

Per-sector prorrata apportionment for a sectores-diferenciados bucket.

Under LIVA arts. 9.1.c / 101 a taxpayer with differentiated sectors applies the deduction regime separately per sector. Each declared sector carries its own provisional percentage and its own regime (a sector may run general while another runs especial); the sector-aware binding resolver applies THIS sector’s apportionment to every deducible cuota whose observation carries the matching sector_id.

See also

SectorDefinition

Operator-declared sector this apportionment resolves for.

Parameters:
sector_id: str
percentage: Decimal
regime: ProrrataRegisterRegime
class IvaLedgerProrrataApportionment(**data)[source]

Bases: BaseModel

Prorrata percentage applied to deducible ledger IVA cuotas.

Under regime == GENERAL (LIVA art. 104) the single percentage is applied to every deducible cuota binding. Under regime == ESPECIAL (LIVA art. 106) percentage is the general percentage that applies only to the COMMON-use inputs; exclusively-deductible inputs deduct in full and exclusively-non-deductible inputs deduct nothing, routed per the observation’s input_classification.

When sector_apportionments is non-empty (LIVA arts. 9.1.c / 101), the bucket is sectorized: the top-level percentage / regime describe the COMMON-use apportionment (art. 104.Dos common percentage, for inputs with no prorrata_sector_id), and each IvaLedgerSectorApportionment describes one declared sector. Empty sector_apportionments is the whole-entity register (byte-identical to the pre-sectores behaviour).

See also

ProrrataProvisionalProvenance

Regulated source of the provisional percentage carried on this apportionment.

resolve_iva_ledger_binding_values()

Applies the percentage after registry selector resolution.

Parameters:
percentage: Decimal
provenance: ProrrataProvisionalProvenance
regime: ProrrataRegisterRegime
source_observation_ref: str | None
authorisation_reference: str | None
sector_apportionments: tuple[IvaLedgerSectorApportionment, ...]
class AnnualDeducibleTotalsByRegime(**data)[source]

Bases: BaseModel

The ejercicio’s whole-year deducible IVA cuota under both prorrata regimes.

The settlement input to the LIVA art. 103.Dos.2 +10% mandatory-especial check (build_prorrata_especial_mandatory_advisory): art. 103.Dos.2 makes prorrata especial obligatory when the deducción under the general regime exceeds the deducción under the especial regime by ten percent or more. deduction_under_general is mechanically derivable for any bucket (art. 104 applies one whole-entity percentage), so it is always honest; the especial total (art. 106 per-input classification) is honest only when the register regime is ESPECIAL, or when every deducible soportado row of the ejercicio carries a declared input_classificationunclassified_deducible_count records how many deducible soportado observations are still unclassified, so the caller can decide whether the especial total is honestly computable or the filer must first classify.

See also

compute_annual_deducible_totals_by_regime()

Builds this record from one annual observation aggregation and two apportionment passes.

Parameters:
deduction_under_general: Decimal
deduction_under_especial: Decimal
unclassified_deducible_count: int
regime: ProrrataRegisterRegime
class IvaLedgerInputKind(*values)[source]

Bases: StrEnum

Business role of a pre-classified IVA ledger candidate.

ADJUSTMENT rows may carry negative bases or cuotas because rectification and regularisation entries reverse or correct prior operations. The registry consumes the resulting signed observation; the model keeps the adjustment axis visible at the application boundary where source provenance still exists.

ORDINARY_OPERATION
ADJUSTMENT
class IvaLedgerCandidate(**data)[source]

Bases: BaseModel

One pre-classified ledger line for generic IVA aggregation.

This is the application hand-off shape for IVA facts that cannot be inferred safely from a bank transaction direction plus a rate: exenciones, no-sujetas, recargo de equivalencia, intra-community reverse-charge operations, imports/exports, and explicit adjustments. Upstream classifiers must supply the authoritative IVA category, rate kind, and flow direction before this layer creates a registry-ready IvaLedgerObservation.

Parameters:
ledger_id: _LedgerId
transaction_date: date
category: IvaCategory
exemption_article: IvaExemptionArticle | None
rate_kind: IvaRateKind
flow_direction: IvaFlowDirection
base_amount: Decimal
iva_amount: Decimal
input_kind: IvaLedgerInputKind
prorrata_reference_id: _LedgerId | None
cash_accounting_treatment: IvaCashAccountingTreatment
class IvaLedgerAggregation(**data)[source]

Bases: BaseModel

IVA observations produced from one bucket-local transaction catalogue.

out_of_window_summary is only populated by repository-backed date partitions. Full-catalogue aggregation continues to emit row-level issues because every transaction is already loaded for classification.

Parameters:
period: Period
observations: Sequence[IvaLedgerObservation]
prorrata_references: Sequence[ProrrataLedgerReference]
prorrata_apportionment: IvaLedgerProrrataApportionment | None
issues: Sequence[IvaLedgerAggregationIssue]
out_of_window_summary: OutOfWindowTransactionSummary | None
art_104_tres_excluded_ledger_ids: tuple[str, ...]
aggregate_iva_ledger_observations_from_repositories(*, bucket_id, period, transaction_repository=None, prorrata_register_repository=None)[source]

Load the bucket-local transaction catalogue and project IVA observations.

Returns an IvaLedgerAggregation.

See also

ProrrataRegisterRepository

Repository consulted for the active general-prorrata provisional percentage when no explicit repository is supplied.

Return type:

IvaLedgerAggregation

Parameters:
validate_iva_ledger_observation(candidate)[source]

Validate a pre-classified IVA candidate and return an IvaLedgerObservation.

The validator does not re-classify the operation and does not derive IVA from the base. It only blocks sentinel categories that are not declarable ledger facts; the category, rate, and flow axes must have been resolved upstream from invoice/operation evidence.

Return type:

IvaLedgerObservation

Parameters:

candidate (IvaLedgerCandidate)

validate_iva_ledger_observations(candidates)[source]

Validate every pre-classified IVA candidate in input order.

Returns a tuple of IvaLedgerObservation instances.

Return type:

tuple[IvaLedgerObservation, ...]

Parameters:

candidates (Iterable[IvaLedgerCandidate])

aggregate_iva_ledger_candidates(candidates, *, period)[source]

Project pre-classified IVA candidates into period-scoped observations.

This path complements aggregate_iva_ledger_observations(), which remains the domestic-rate projection from bank transactions. Pre-classified candidates are required for non-domestic IVA and adjustments because those axes cannot be recovered from a transaction amount or direction without guessing.

Returns an IvaLedgerAggregation carrying the accepted observations and any period-exclusion issues.

Return type:

IvaLedgerAggregation

Parameters:
aggregate_iva_ledger_candidate_bindings(revision, candidates, *, period, prorrata_apportionment=None)[source]

Validate pre-classified candidates and resolve registry bindings.

Parameters:
Return type:

dict[TypeAliasType, Decimal]

aggregate_iva_ledger_observations(transactions, *, period, prorrata_apportionment=None)[source]

Project classified ledger transaction tax facts into an IvaLedgerAggregation.

Parameters:
Return type:

IvaLedgerAggregation

resolve_iva_ledger_binding_values(revision, observations, *, prorrata_apportionment=None)[source]

Resolve IVA ledger bindings, applying general-prorrata to deducible cuotas only.

Parameters:
Return type:

dict[TypeAliasType, Decimal]

Under regime == GENERAL the single provisional percentage multiplies every deducible cuota binding (LIVA art. 104). Under regime == ESPECIAL the deducible cuota is routed per the observation’s input_classification (LIVA art. 106.Uno: exclusively-deductible 100%, exclusively-non-deductible 0%, common at the general percentage) by _apply_especial_apportionment(); the general-regime code path is unchanged.

See also

resolve_ledger_iva_aggregation_binding_values()

Registry selector resolver that produces the unapportioned binding values before this wrapper applies prorrata.

ProrrataRegisterEntry

Source record for the active provisional percentage represented by IvaLedgerProrrataApportionment.

compute_annual_deducible_totals_by_regime(*, bucket_id, ejercicio, revision, transaction_repository=None, prorrata_register_repository=None)[source]

Compute the ejercicio’s deducible IVA cuota under both prorrata regimes.

The plumbing for the LIVA art. 103.Dos.2 +10% mandatory-especial settlement check. Aggregates the ejercicio’s annual IVA observations ONCE (aggregate_iva_ledger_observations_from_repositories() over the canonical 0A annual Period), then resolves resolve_iva_ledger_binding_values() TWICE over the same observations — once with a GENERAL-stamped and once with an ESPECIAL-stamped IvaLedgerProrrataApportionment at the register’s resolved percentage — and sums the deducible-cuota binding ids under each. One aggregation, two apportionment passes through the one canonical resolver (one-aggregation-path-pull-equals-calculate); no second aggregation implementation is introduced.

Returns None when no register apportionment resolves for the ejercicio (prorrata inapplicable), when the register is sectorized (LIVA arts. 9.1.c / 101 — the art-103.Dos.2 comparison composes per sector, a named v1 deferral), or when the revision declares no deducible cuota bindings. A negative deducible total (an adjustment-heavy degenerate case the art-103.Dos.2 comparison is undefined over) also returns None so the check stays silent rather than crashing on a non-comparable input.

Parameters:
Return type:

AnnualDeducibleTotalsByRegime | None

See also

AnnualDeducibleTotalsByRegime

The frozen record returned.

build_prorrata_especial_mandatory_advisory()

Consumes the two totals to build the +10% advisory.

validate_iva_ledger_counterparty_category(transaction)[source]

Return the D5 counterparty/category gate IvaLedgerAggregationIssue for a ledger transaction.

Return type:

IvaLedgerAggregationIssue | None

Parameters:

transaction (Transaction)

iva_ledger_missing_fact_reasons(transaction)[source]

Return missing IVA fact reasons for a transaction without projecting it.

Each element is an IvaLedgerAggregationIssueReason describing one absent required tax fact.

Return type:

tuple[IvaLedgerAggregationIssueReason, ...]

Parameters:

transaction (Transaction)