cadrumo.application.aggregation.renta_ledger module

Repository-backed Modelo 100 Renta expense aggregation.

This is the annual first-slice expense projection behind the ledger_renta_gastos_estimacion_directa_aggregation source. It loads both a TransactionCatalogue and a InvoiceCatalogue from the application-owned catalogue read capabilities, uses purchase-invoice evidence to validate deductible-expense facts, and returns binding-ready RentaDeductibleExpenseObservation records.

The source-mesh resolver in modelo_bindings applies the target ModeloRevision, resolves registry bindings, and reports source issues or unrouted expenses on its CalculationSourceResolution. The M130 quarterly gasto projection is intentionally separate in renta_gasto_ledger.

Related: iva_ledger and renta_income_ledger for sibling ledger projections.

class RentaLedgerAggregationIssueReason(*values)[source]

Bases: StrEnum

Machine-readable reasons why a ledger row did not produce an observation.

The five upstream filter rejections (UNSUPPORTED_DIRECTION, UNSUPPORTED_CURRENCY, UNCLASSIFIED_BUSINESS_STATE, PERSONAL_TRANSACTION, OUTSIDE_PERIOD) are shared with IvaLedgerAggregationIssueReason through _shared_issue_reasons. UNSUPPORTED_PERIOD is a Renta-only refusal raised against quarter-level requests; the remaining values describe Renta-specific deductibility checks.

UNSUPPORTED_PERIOD
UNSUPPORTED_DIRECTION
UNSUPPORTED_CURRENCY
UNCLASSIFIED_BUSINESS_STATE
ACTIVITY_MARKED_PENDING_ANNUAL_REVIEW

An actividad-marked expense the quarterly M130 accepts but the annual declaration holds for review.

Narrower than UNCLASSIFIED_BUSINESS_STATE: the row carries an explicit actividad_economica IRPF category, so it is not unclassified – it is awaiting the business-classification review the filing-grade annual projection requires. Naming it separately tells the operator that the same row already fed a pago fraccionado and what action clears it.

PERSONAL_TRANSACTION
MISSING_CATEGORY
UNKNOWN_CATEGORY
MISSING_CATEGORY_PROFILE
OUTSIDE_PERIOD
MISSING_PURCHASE_INVOICE_EVIDENCE
UNSUPPORTED_PURCHASE_INVOICE_EVIDENCE_KIND
PURCHASE_INVOICE_EVIDENCE_BUCKET_MISMATCH
PARTIAL_OR_MULTI_TRANSACTION_PURCHASE_INVOICE_EVIDENCE
AMOUNT_MISMATCH
INVALID_LEDGER_FACT
INELIGIBLE_DEDUCTIBILITY
REGION_UNDECLARED_FOR_OVERRIDE
class RentaLedgerAggregationIssue(**data)[source]

Bases: BaseModel

Traceable exclusion emitted while aggregating ledger rows.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict]

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

transaction_id: TransactionId
purchase_invoice_evidence_id: str | None
category_id: str | None
reason: RentaLedgerAggregationIssueReason
detail: IssueDetail
class RentaLedgerExpenseAggregation(**data)[source]

Bases: LedgerAggregationResultBase[RentaDeductibleExpenseObservation, RentaLedgerAggregationIssue]

First-slice Renta observations plus binding-ready casilla totals.

Carries no out_of_window_summary: this annual first-slice aggregation has no repository-backed date partition, unlike the base’s four other known subclasses – deliberately not declared here (see LedgerAggregationResultBase).

Parameters:
profile_year: FilingYear
property casilla_values: Mapping[CasillaId, Decimal]

Return the frozen mapping of binding-ready casilla totals.

model_config: ClassVar[ConfigDict]

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

resolve_iva_deduction_ratio(*, bucket_id, ejercicio, profile_record=None, prorrata_register_repository, profile_decode_context=None, operation=None)[source]

Resolve the activity’s IVA-deduction fraction for RentaDeductibilityContext.iva_deduction_ratio.

The selected registry ratio policy supplies the exempt-regime result and percentage-unit conversion; the prorrata register supplies the period value for all other regimes. An absent or unresolved register value falls through to None.

Returns None – the historic base-only fallback – when neither fact resolves a ratio (no profile, an unparseable regime, no register entry, or an unresolved percentage). Never fabricates a percentage.

Parameters:
  • bucket_id (str) – Stable bucket identifier used to load the profile and register.

  • ejercicio (int) – Filing year to resolve the register entry for.

  • profile_record (UserProfileRecord | None) – Optional UserProfileRecord override for testing; when None the record is loaded from the bucket.

  • profile_decode_context (ProfileDecodeContext | None) – Optional decode context from the caller-held authority operation used when the record is loaded.

  • prorrata_register_repository (ProrrataRegisterRepositoryProtocol) – Canonical repository for the bucket’s prorrata register. The caller owns its store selection so a non-active bucket cannot be shadowed by a process-global default.

  • operation (PinnedAuthorityOperation | None) – Existing generation-pinned authority operation. When omitted, one indexed operation is opened at this composition boundary.

Return type:

Decimal | None

aggregate_renta_ledger_expenses_from_repositories(*, bucket_id, period, ports, profile_year=None, usage_ratios=None, activity_key='default', modelo='100', profile_record=None, region_category_overrides=None, prorrata_register_repository, profile_decode_context=None, operation=None)[source]

Load persisted catalogues and aggregate first-slice Renta expenses.

Derives the ordinary-residence comunidad autonoma from the bucket’s active profile (tax_residence.ccaa) and threads it into the aggregation so a territorial-regime deductibility override selects by residence; the axis is fail-closed (an undeclared or unparseable region resolves to the state year profile) and byte-identical while the override layer is empty. Pass profile_record to supply the UserProfileRecord directly (the residence is otherwise loaded from the bucket), and region_category_overrides to supply the per-CCAA override layer forwarded to aggregate_renta_ledger_expenses() (defaulting to the empty registry-provisioned layer, resolve_region_category_profiles()).

Also derives the activity’s IVA-deduction ratio (resolve_iva_deduction_ratio()) from the bucket’s iva.regime profile fact and its ProrrataRegister, so the non-recoverable share of input IVA joins the IRPF-deductible cost basis (PGC NRV 12.ª) for an exempt or prorrata-rationed activity. prorrata_register_repository supplies the canonical register store explicitly.

Returns a RentaLedgerExpenseAggregation.

Return type:

RentaLedgerExpenseAggregation

Parameters:
aggregate_renta_ledger_expenses(transactions, invoices, *, bucket_id, period, profile_year=None, usage_ratios=None, activity_key='default', modelo='100', residence_ccaa=None, region_category_overrides=None, iva_deduction_ratio=None, profile_record=None, profile_decode_context=None, operation=None)[source]

Aggregate classified ledger transactions into Renta expense observations.

Parameters:
  • transactions (TransactionCatalogue) – The TransactionCatalogue supplying active ledger entries.

  • invoices (InvoiceCatalogue) – The InvoiceCatalogue used for invoice-linked deductibility checks.

  • bucket_id (str) – Activity bucket identifier for scoping the aggregation.

  • period (Period) – Filing period as a typed Period instance.

  • profile_year (int | None) – Optional category-profile year override; defaults to the period.filing_year when None.

  • usage_ratios (Mapping[SpendingCategory, Decimal] | None) – Optional per-SpendingCategory business-use ratio overrides applied before deductibility calculation.

  • activity_key (str) – Activity identifier carried through to the produced observations’ provenance; defaults to "default".

  • modelo (str) – Modelo identifier ("100" IRPF or "130" pagos fraccionados) selecting the per-modelo deductibility rules.

  • residence_ccaa (CCAA | None) – Optional ordinary residence comunidad autonoma, used only to select a territorial-regime deductibility override; inert while the override layer is empty and general expense deductibility is state law.

  • region_category_overrides (Mapping[CCAA, Mapping[SpendingCategory, CategoryProfile]] | None) – Optional per-CCAA category-profile override layer; defaults to resolve_region_category_profiles() (empty) so every fact falls through to the state year profile.

  • iva_deduction_ratio (Decimal | None) – Optional activity-wide IVA-deduction fraction (LIVA arts. 94/104), threaded onto RentaDeductibilityContext so the non-recoverable share of a fact’s input IVA joins its IRPF-deductible cost basis. None (the default) preserves the historic base-only behaviour.

  • profile_record (UserProfileRecord | None) – Optional UserProfileRecord override; when None the record is loaded from the bucket. Supplies the LIRPF art. 30.2.5.a insured-person counts that split the seguro de enfermedad cap across its 500 and 1.500 euro limbs.

  • profile_decode_context (ProfileDecodeContext | None) – Optional decode context from the caller-held authority operation when profile_record is supplied directly.

  • operation (PinnedAuthorityOperation | None) – Existing generation-pinned authority operation. When omitted, one indexed operation is opened at this composition boundary.

Return type:

RentaLedgerExpenseAggregation

Returns a RentaLedgerExpenseAggregation containing the accepted observations, exclusion issues, and binding-ready casilla totals.