cadrumo.domain.bienes_inversion.register module

Capital-goods IVA deduction-regularización register and annual/disposal computes.

Models the LIVA arts. 107-110 regularización de deducciones por bienes de inversión: a durable, cross-year BienesInversionIvaRegister, one BienInversionIvaRecord per capital good, the pure art-109 RegularizacionAnualResult computed for each supplied definitive prorrata percentage, and the pure art-110 RegularizacionTransmisionResult computed for a good disposed of during its regularisation window.

The register is a taxpayer-fact store (owned goods, acquisition year, cuota soportada, initial definitive prorrata percentage), sibling to domain.iva_compensation. The regulatory figures it consumes – the art-107 windows, the art-107.Uno de-minimis gate, and the art-109 divisors – are NOT constants here: they are declared per revision in the registry and arrive as a resolved BienesInversionRegularizacionParameters that the application boundary supplies. Every computation below therefore requires that bundle and none of them can run on an ungrounded figure.

Register-wide projection returns RegistroRegularizacionResult for the ordinary annual art-109 path: each art-108-eligible in-window good (not yet disposed of) is either computed into the proposed Modelo 303 casilla 43 / Modelo 390 regularización value when the current-year definitive prorrata fact is available, or reported as pending that separate input. A good recorded as disposed of in the projected year routes instead through compute_registro_transmisiones(), which folds the art-110 single (“única”) regularización for every remaining window year into the same casilla-43 total; art-110 carries no pending state — the disposal regime and acquisition-year facts are already on the record, so every disposed good is always computed. This domain module does not read the secure-object store or derive prorrata; application and persistence layers supply those facts.

See also

application.bienes_inversion

Profile-scoped service that declares and lists the persisted register.

adapters.persistence.profile.bienes_inversion

FINANCIAL secure-object repository that stores the register singleton.

application.calculations

Source resolver and advisory projection surfaces for the bienes_inversion_regularizacion calculation source.

domain.iva

Legal prorrata substrate that supplies the separate definitive percentage input; usage ratios are not a substitute.

exception BienInversionRecordError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Raised when a bien-de-inversión register record is structurally invalid.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
exception BienInversionValidationError(message=None, *, context=None, translated_message=None)[source]

Bases: BienInversionRecordError

Raised when a bien-de-inversión record fails Pydantic validation.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
BIENES_INVERSION_SCHEMA_VERSION

Forward-compatible schema version stamped onto every record in this module.

class BienInversionDisposal(**data)[source]

Bases: BaseModel

Optional art-110 disposal event carried on a register record.

Variables:
Parameters:

data (Any)

year: int
regime: _BienInversionDisposalRegime
class BienInversionIvaRecord(**data)[source]

Bases: BaseModel

One capital good tracked for LIVA arts. 107-110 IVA regularización.

Strict, frozen, no extra fields. Carries the taxpayer facts the art-109 annual compute needs (acquisition year, cuota soportada, initial-year definitive prorrata percentage, and the registry-selected asset-kind window) plus the art-108 concept-eligibility flag.

Variables:
  • identifier – Stable natural key chosen by the operator.

  • description – Free-text human description.

  • acquisition_year – Calendar year the good was acquired / put into use.

  • cuota_soportada – Total input IVA (cuota repercutida) borne on the acquisition. Strictly positive.

  • prorrata_inicial_pct – Definitive deduction percentage (0-100) that prevailed in the acquisition year — the baseline art-109 compares each later year’s definitive percentage against.

  • kind – BienInversionKind — the registry-selected capital-goods regularisation window.

  • art108_elegible – Whether the good qualifies as a bien de inversión under LIVA art. 108 (value at/above the escaso-valor threshold, normally used over a year as an instrument of work). False marks a good the operator recorded but which is excluded from regularisation.

  • disposal – Optional BienInversionDisposal (art-110). When present, the good is routed through the art-110 single (“única”) regularización (compute_registro_transmisiones()) in its disposal year instead of the ordinary annual art-109 comparison.

  • schema_version – Forward-compatible schema version. "1".

Parameters:

data (Any)

identifier: str
description: str
acquisition_year: int
cuota_soportada: Decimal
prorrata_inicial_pct: Percentage
kind: _BienInversionKind
art108_elegible: bool
acquisition_ledger_id: str
prorrata_sector_id: str | None
disposal: BienInversionDisposal | None
schema_version: str
property deduccion_efectuada: Decimal

Deduction actually made in the acquisition year (cuota × prorrata inicial).

is_within_regularization_window(regularization_year, *, parameters)[source]

Whether regularization_year is one of the art-107 following window years.

The window is the registry-declared count of calendar years following acquisition under the applicable art. 107 category. The acquisition year itself is excluded: that is the year the original deduction was made, not a regularisation year.

Return type:

bool

Parameters:
remaining_regularization_years(disposal_year, *, parameters)[source]

Count of art-110 “años que resten” from disposal_year to window end.

Art. 110.Uno: “se efectuará una regularización única por el tiempo de dicho período que quede por transcurrir”, counting the disposal year itself and every later year through the last window year (inclusive). A disposal in the acquisition year itself counts the full window (the deduction was never regularised, so every following window year remains to transcur).

Return type:

int

Parameters:
class RegularizacionDireccion(*values)[source]

Bases: StrEnum

Direction of an art-109 annual regularisation quotient.

INGRESO — the acquisition-year deduction exceeded what the current year’s percentage would allow: an ingreso complementario (repay). DEDUCCION — the current year allows more: a deducción complementaria (claim more). NINGUNA — the over-10-point gate did not fire, or the good is out of window.

INGRESO
DEDUCCION
NINGUNA
class RegularizacionAnualResult(**data)[source]

Bases: BaseModel

Outcome of the art-109 single-good annual regularización compute.

Variables:
  • aplica – Whether the art-107 over-10-point gate fired (a regularisation is due).

  • diferencia_puntos – Absolute percentage-point difference between the current year’s definitive percentage and the acquisition-year one.

  • divisor – Art-109 divisor selected by the registry-declared asset category.

  • importe – The regularisation quotient (deducción efectuada − deducción que procedería) ÷ divisor, rounded to cents. Positive = ingreso complementario, negative = deducción complementaria; 0.00 when the gate did not fire.

  • direccion – RegularizacionDireccion describing importe’s sign.

Parameters:

data (Any)

aplica: bool
diferencia_puntos: Decimal
divisor: Decimal
importe: Decimal
direccion: RegularizacionDireccion
compute_regularizacion_anual(*, cuota_soportada, prorrata_inicial_pct, prorrata_anio_pct, kind, parameters)[source]

Compute the LIVA art-109 annual regularización for one capital good.

Implements the art-109 procedure verbatim:

1.º the deduction that would apply if the cuota were borne in the year

considered — cuota_soportada × prorrata_anio_pct;

2.º subtract it from the deduction actually made in the acquisition year —

cuota_soportada × prorrata_inicial_pct;

3.º divide the (positive or negative) difference by 5, or by 10 for land and

buildings; the quotient is the ingreso / deducción complementaria.

The art-107.Uno de-minimis gate applies: the regularisation is practised only when the absolute difference between the two definitive percentages exceeds the threshold the resolved bundle declares. Both the threshold and whether it is exceeded strictly are registry data, so neither appears here. When the gate does not fire, importe is 0.00 and direccion is RegularizacionDireccion.NINGUNA.

Both percentages are supplied as inputs; deriving the current-year definitive percentage (LIVA arts. 102-106) is a separate registry/materialisation concern and this function stays independent of it.

Parameters:
Return type:

RegularizacionAnualResult

Returns:

A RegularizacionAnualResult.

Raises:

BienInversionValidationError – On a non-positive cuota or an out-of-range percentage.

class RegularizacionTransmisionResult(**data)[source]

Bases: BaseModel

Outcome of the art-110 single-final (“única”) disposal regularización.

Variables:
  • regime – BienInversionDisposalRegime applied.

  • anos_restantes – Count of window years — the disposal year plus every later year through window expiry — the single regularización covers (art. 110.Uno “el tiempo de dicho período que quede por transcurrir”).

  • divisor – Art-109 divisor selected by the registry-declared asset category, carried into the art-110 single computation per art. 110.Uno’s cross-reference to the art-109 procedure.

  • importe_sin_limite – The signed quotient before the regla-1ª cap, i.e. (deducción efectuada − deducción imputada) × años_restantes ÷ divisor.

  • importe – importe_sin_limite after applying the regla-1ª cap — a negative (DEDUCCION / additional-deduction) result never exceeds -cuota_devengada_entrega in magnitude, when supplied; equals importe_sin_limite unqualified for regla 2ª (no cap applies there) and for a non-negative regla-1ª result.

  • direccion – RegularizacionDireccion describing importe’s sign.

  • capped – Whether the regla-1ª cap reduced importe_sin_limite’s magnitude.

Parameters:

data (Any)

regime: _BienInversionDisposalRegime
anos_restantes: int
divisor: Decimal
importe_sin_limite: Decimal
importe: Decimal
direccion: RegularizacionDireccion
capped: bool
compute_regularizacion_transmision(*, cuota_soportada, prorrata_inicial_pct, anos_restantes, kind, regime, parameters, cuota_devengada_entrega=None)[source]

Compute the LIVA art-110 single (“única”) disposal regularización.

Art. 110.Uno: on a disposal (entrega) during the regularisation window, a SINGLE regularización is practised for the window time remaining (the disposal year plus every later window year), applying the art-109 procedure once over that whole remaining span rather than year by year:

Regla 1.ª (entrega sujeta y no exenta — or an exempt/non-subject entrega that itself originates a deduction right, e.g. exports / intra-EU supplies, per the art. 110.Uno final paragraph): the good is deemed used 100% in deduction-generating operations for every remaining year, which typically yields a negative (additional-deduction) quotient since the imputed 100% usually exceeds the acquisition-year percentage. Art. 110.Uno caps the MAGNITUDE of that additional deduction at the cuota devengada on the disposal itself (“no será deducible la diferencia … y el importe de la cuota devengada por la entrega del bien”) — applied via cuota_devengada_entrega when supplied.

Regla 2.ª (entrega exenta o no sujeta, without its own deduction right — the ordinary case): the good is deemed used 0% for every remaining year. No cap applies (the result is a repayment of previously-taken deduction, never an additional one).

Both reglas apply the SAME art-109 quotient — (deducción efectuada − deducción imputada) ÷ divisor — but multiply the per-year difference by anos_restantes before dividing, since art. 110.Uno folds every remaining window year into one regularización rather than repeating art-109 per year. Unlike compute_regularizacion_anual(), art. 110 carries no diferencia-de-puntos gate: a disposal always triggers the single regularización regardless of how close the imputed percentage is to the acquisition-year one (the disposal itself, not a percentage drift, is what obliges it).

Parameters:
Return type:

RegularizacionTransmisionResult

Returns:

A RegularizacionTransmisionResult.

Raises:

BienInversionValidationError – On a non-positive cuota, an out-of-range percentage, a non-positive anos_restantes, or a negative cuota_devengada_entrega.

class BienesInversionIvaRegister(**data)[source]

Bases: BaseModel

Encrypted JSON document holding the per-good IVA regularización register.

Variables:
  • schema_version – Forward-compatible schema version. "1".

  • records – Tuple of BienInversionIvaRecord rows.

Parameters:

data (Any)

schema_version: str
records: tuple[BienInversionIvaRecord, ...]
in_window_records(regularization_year, *, parameters)[source]

Return each art-108-eligible BienInversionIvaRecord in-window for the year.

A good disposed of AT OR BEFORE regularization_year is excluded: art. 110.Uno’s single (“única”) regularización supersedes the ordinary annual art-109 comparison from the disposal year onward — see disposed_records() and compute_registro_transmisiones() for the disposal path.

Return type:

tuple[BienInversionIvaRecord, ...]

Parameters:
disposed_records(disposal_year, *, parameters)[source]

Return each art-108-eligible good whose art-110 disposal falls in disposal_year.

Only a disposal that still leaves window time to regularise is included (BienInversionIvaRecord.remaining_regularization_years() strictly positive); a disposal recorded outside the window has nothing left to regularise under art. 110.

Return type:

tuple[BienInversionIvaRecord, ...]

Parameters:
class RegistroRegularizacionRow(**data)[source]

Bases: BaseModel

One good’s contribution to the annual register-wide regularización.

Variables:
  • identifier – The record identifier.

  • kind – BienInversionKind of the good.

  • prorrata_anio_pct – The definitive percentage supplied for the year, or None when the caller could not supply it (the good is reported but not yet computed because the prorrata-definitiva input is absent).

  • result – The RegularizacionAnualResult, or None when prorrata_anio_pct was absent.

Parameters:

data (Any)

identifier: str
kind: _BienInversionKind
prorrata_sector_id: str | None
prorrata_anio_pct: Decimal | None
result: RegularizacionAnualResult | None
class BienesInversionSectorContribution(**data)[source]

Bases: BaseModel

Immutable one-asset regularisation contribution owned by its register sector.

Parameters:

data (Any)

asset_id: str
prorrata_sector_id: str | None
amount: Decimal

Bases: BaseModel

Canonical reciprocal edge between one investment IVA fact and one asset.

Parameters:

data (Any)

ledger_id: str
transaction_date: date
deduction_fact_kind: IvaDeductionFactKind
investment_asset_id: str
prorrata_sector_id: str | None
class RegistroRegularizacionResult(**data)[source]

Bases: BaseModel

Register-wide art-109 regularización projection for one year.

Variables:
  • regularizacion_year – The year the projection covers.

  • rows – Per-good RegistroRegularizacionRow entries for every in-window, art-108-eligible good.

  • proposed_casilla_43 – The signed sum of every computed importe (art-109 step 3), the value proposed for Modelo 303 casilla 43 / the Modelo 390 regularización field. Positive = net ingreso, negative = net deducción complementaria. Rows without a supplied percentage contribute nothing.

  • computed_count – Number of goods whose regularización was actually computed (a percentage was supplied and the gate fired).

  • pending_percentage_count – Number of in-window goods for which no current-year definitive percentage was supplied.

  • parameters_provenance – The registry declaration whose figures produced this projection. Carried on the result so an oracle or replay can refuse a result computed under figures other than the ones it was handed; without it, giving a producer and its oracle the same wrong bundle would be self-consistent and prove nothing.

Parameters:

data (Any)

regularizacion_year: int
rows: tuple[RegistroRegularizacionRow, ...]
proposed_casilla_43: Decimal
computed_count: int
pending_percentage_count: int
sector_contributions: tuple[BienesInversionSectorContribution, ...]
parameters_provenance: BienesInversionParameterProvenance
compute_registro_regularizacion(register, *, regularizacion_year, prorrata_definitiva_by_identifier, parameters)[source]

Project the register onto its annual art-109 regularización for a year.

Iterates every art-108-eligible, in-window good; for each good whose current-year definitive percentage is supplied in prorrata_definitiva_by_identifier, runs compute_regularizacion_anual() and folds the signed importe into the proposed casilla-43 total. Goods without a supplied percentage are reported as pending rather than silently dropped.

Parameters:
Return type:

RegistroRegularizacionResult

Returns:

A RegistroRegularizacionResult.

class RegistroTransmisionRow(**data)[source]

Bases: BaseModel

One disposed good’s contribution to the art-110 single regularización.

Variables:
Parameters:

data (Any)

identifier: str
kind: _BienInversionKind
prorrata_sector_id: str | None
disposal_year: int
result: RegularizacionTransmisionResult
class RegistroTransmisionesResult(**data)[source]

Bases: BaseModel

Register-wide art-110 single-regularización projection for one disposal year.

Variables:
  • disposal_year – The year every included disposal occurred in.

  • rows – Per-good RegistroTransmisionRow entries for every art-108-eligible good disposed of in disposal_year with window time remaining.

  • proposed_casilla_43 – The signed sum of every row’s importe — the value proposed for Modelo 303 casilla 43 / the Modelo 390 regularización field for the disposals in this year. Positive = net ingreso, negative = net deducción complementaria.

  • computed_count – Number of disposed goods included in the projection.

  • parameters_provenance – The registry declaration whose figures produced this projection; see RegistroRegularizacionResult.

Parameters:

data (Any)

disposal_year: int
rows: tuple[RegistroTransmisionRow, ...]
proposed_casilla_43: Decimal
computed_count: int
sector_contributions: tuple[BienesInversionSectorContribution, ...]
parameters_provenance: BienesInversionParameterProvenance
compute_registro_transmisiones(register, *, disposal_year, parameters, cuota_devengada_entrega_by_identifier=None)[source]

Project the register onto its art-110 single (“única”) regularización for a year.

Iterates every art-108-eligible good recorded as disposed of in disposal_year with window time remaining (BienesInversionIvaRegister.disposed_records()); for each, computes compute_regularizacion_transmision() over the remaining window years and folds the signed importe into the proposed casilla-43 total.

Unlike compute_registro_regularizacion(), a disposal has no pending state analogous to a missing current-year prorrata-definitiva input: every disposal fact the register carries (acquisition-year percentage, cuota soportada, disposal regime) is already on the record, so every disposed good is always computed.

Parameters:
Return type:

RegistroTransmisionesResult

Returns:

A RegistroTransmisionesResult.

validate_investment_asset_reciprocity(*, observations, register, ledger_profile_id, asset_profile_id, filing_year)[source]

Validate the one-to-one, same-profile/year/sector acquisition contract.

Return type:

None

Parameters: