aeat.domain.deadlines._models module

Pydantic v2 strict models for the aeat.domain.deadlines subpackage.

Every type that crosses a public boundary lives here as a strict, frozen pydantic.BaseModel (or enum.StrEnum for closed enumerations). No dataclasses; no bare dict[str, Any].

Consumed by aeat.domain.deadlines.DeadlineEngine and re-exported from aeat.domain.deadlines.

class IVARegime(*values)[source]

Bases: StrEnum

The IVA regime a taxpayer files under.

Registry deadline applicability can reference this value. The closed set tracks the IVA regimes the project supports.

Variables:
  • GENERAL – Régimen general (Ley 37/1992 LIVA).

  • SIMPLIFICADO – Régimen simplificado (módulos), coordinated with IRPF estimación objetiva.

  • RECARGO_EQUIVALENCIA – Recargo de equivalencia for retail traders.

  • REAGP – Régimen especial de la agricultura, ganadería y pesca.

  • EXENTO – IVA-exempt activity.

  • NO_APLICA – Internal projection sentinel for profiles that are not enrolled in IVA.

GENERAL
SIMPLIFICADO
RECARGO_EQUIVALENCIA
REAGP
EXENTO
NO_APLICA
class EntityType(*values)[source]

Bases: StrEnum

The taxpayer’s entity type — the most consequential taxpayer axis.

Entity type selects the tax (IRPF vs Impuesto sobre Sociedades vs régimen de atribución de rentas), and the tax selects the modelos, the calendar, and the rate schedule. Grounded in Ley 35/2006 LIRPF (BOE-A-2006-20764), Ley 27/2014 LIS (BOE-A-2014-12328), and LIRPF Title X Section 2 (régimen de atribución de rentas).

Variables:
  • NATURAL_PERSON – Persona física — an IRPF taxpayer (contribuyente del IRPF).

  • LEGAL_ENTITY – A legal entity with personalidad jurídica — a contribuyente del Impuesto sobre Sociedades.

  • ATTRIBUTION_ENTITY – An entity without legal personality (comunidad de bienes, sociedad civil sin objeto mercantil, herencia yacente) under the régimen de atribución de rentas; income is taxed in the hands of each member.

NATURAL_PERSON
LEGAL_ENTITY
ATTRIBUTION_ENTITY
class LegalEntityForm(*values)[source]

Bases: StrEnum

The recognised legal form of an Impuesto sobre Sociedades entity.

Only meaningful when EntityType is LEGAL_ENTITY; the sub-form drives the IS rate schedule (LIS Art. 29). Grounded in the AEAT distinction between sociedades civiles and comunidades de bienes and the project registry legal/is.toml.

Variables:
  • SL – Sociedad de responsabilidad limitada (S.L. / S.R.L.).

  • SA – Sociedad anónima (S.A.).

  • SAL – Sociedad Anónima Laboral (Ley 44/2015 Art. 1). Majority of share capital held by worker-shareholders. Eligible for reserva especial dotación under Ley 44/2015 Art. 14.

  • SLL – Sociedad Limitada Laboral (Ley 44/2015 Art. 1). Same régimen as SAL but limited-liability form. Eligible for the same reserva especial under Ley 44/2015 Art. 14.

  • COOPERATIVA – Sociedad cooperativa — IS with a reduced rate.

  • SOCIEDAD_CIVIL_MERCANTIL – Sociedad civil con personalidad jurídica y objeto mercantil — an IS contribuyente since 2016.

  • SIN_FINES_LUCRATIVOS – Asociación / fundación / entidad sin fines lucrativos — IS contribuyente, partially exempt.

  • OTHER – Any other recognised legal form.

SL
SA
SAL
SLL
COOPERATIVA
SOCIEDAD_CIVIL_MERCANTIL
SIN_FINES_LUCRATIVOS
OTHER
class IrpfIncomeCategory(*values)[source]

Bases: StrEnum

An IRPF income category (rendimiento) a natural person declares.

For a natural person the quarterly / informational modelo obligations derive from the income category, not from being a natural person as such. Grounded in Ley 35/2006 LIRPF (BOE-A-2006-20764).

Variables:
  • ACTIVIDAD_ECONOMICA – Rendimientos de actividades económicas (autónomo / empresario / profesional) — LIRPF Arts. 27-32. The only category that triggers Modelo 130 / 131.

  • TRABAJO – Rendimientos del trabajo (employment) — LIRPF Arts. 17-20.

  • CAPITAL_INMOBILIARIO – Rendimientos del capital inmobiliario (immovable property / rental) — LIRPF Arts. 22-24.

  • CAPITAL_MOBILIARIO – Rendimientos del capital mobiliario (dividends, interest) — LIRPF Arts. 25-26.

  • GANANCIAS_PATRIMONIALES – Ganancias y pérdidas patrimoniales (capital gains) — LIRPF Arts. 33-39.

  • PENSION – Pensión — a rendimiento del trabajo for IRPF purposes (LIRPF Art. 17.2.a), modelled separately so a pensioner profile is explicit.

ACTIVIDAD_ECONOMICA
TRABAJO
CAPITAL_INMOBILIARIO
CAPITAL_MOBILIARIO
GANANCIAS_PATRIMONIALES
PENSION
class IrpfEstimationRegime(*values)[source]

Bases: StrEnum

The IRPF method for determining net economic-activity income.

A closed regime choice for a natural person with rendimientos de actividades económicas (LIRPF Arts. 16, 28-31; RIRPF RD 439/2007). The regime selects Modelo 130 vs Modelo 131 and the deductible-expense computation.

Variables:
  • DIRECTA_NORMAL – Estimación directa normal — full accounting; pago fraccionado on Modelo 130.

  • DIRECTA_SIMPLIFICADA – Estimación directa simplificada — applies below the INCN threshold; pago fraccionado on Modelo 130.

  • OBJETIVA – Estimación objetiva (módulos) — net income from signos, índices y módulos; pago fraccionado on Modelo 131.

DIRECTA_NORMAL
DIRECTA_SIMPLIFICADA
OBJETIVA
class IrpfSpecialRegime(*values)[source]

Bases: StrEnum

IRPF special-regime category for natural persons.

Most taxpayers file under the general IRPF regime. The IMPATRIADO value represents the régimen especial aplicable a los trabajadores desplazados a territorio español (LIRPF Art. 93, “Ley Beckham”), introduced by Ley 62/2003 and extended by Ley 26/2014. Under this regime the taxpayer files Modelo 151 (not Modelo 100) and is taxed at the flat IRNR rate on Spanish-source income.

Grounded in LIRPF Ley 35/2006 Art. 93 (BOE-A-2006-20764) and RIRPF RD 439/2007 Arts. 113-120 (BOE-A-2007-6820).

Variables:
  • GENERAL – Standard IRPF — files Modelo 100, subject to the progressive tarifa general / del ahorro.

  • IMPATRIADO – Régimen especial impatriados (Art. 93 LIRPF) — files Modelo 151, taxed at the flat IRNR rate. The regime has a six-year window triggered by the opt-in election date (special_regime_start_date on the profile).

GENERAL
IMPATRIADO
class ObligationStatus(*values)[source]

Bases: StrEnum

Status of a single ModeloDeadline against a reference date.

UPCOMING and DUE_SOON are differentiated by the AEAT_DEADLINE_DUE_SOON_DAYS setting (default 14 days). FILED and NOT_APPLICABLE are reserved for downstream consumers — the engine never produces them.

Variables:
  • UPCOMING – Window opens in the future or is open but more than due_soon_days ahead of close.

  • DUE_SOON – Window closes within due_soon_days of the reference date.

  • DUE_TODAY – Reference date is the close date.

  • OVERDUE – Reference date is past the close date.

  • FILED – Downstream marker for filings already submitted.

  • NOT_APPLICABLE – Downstream marker for obligations the profile no longer triggers.

UPCOMING
DUE_SOON
DUE_TODAY
OVERDUE
FILED
NOT_APPLICABLE
class ModeloEnrollment(**data)[source]

Bases: BaseModel

AEAT enrollment facts used by registry filing schedules.

Parameters:
  • large_company (bool)

  • public_administration_budget_gt_6000000 (bool)

large_company: bool
public_administration_budget_gt_6000000: bool
class RefundAccount(**data)[source]

Bases: BaseModel

The cuenta-devolución refund account AEAT pays a Modelo 303 refund into.

Groups the IBAN with the foreign-bank block used for a non-SEPA account. Every field is sensitive financial identity data: per the sensitive-financial-data-secure-storage-only invariant it lives only in the encrypted secure-object store (sensitivity="financial" on the profile schema), is read transiently into memory at export time, and is never written to plaintext, logs, or a side store.

The IBAN is validated structurally at this boundary — country code, check digits, BBAN length, and the ISO 13616 mod-97 residue — so a malformed IBAN is rejected on input rather than deferred to fichero-write time.

Variables:
  • iban – The refund account IBAN (canonical, whitespace- and hyphen-stripped, upper-cased). None when no refund account is on file.

  • swift_bic – SWIFT-BIC of the bank for a non-SEPA account.

  • bank_name – Bank name for a non-SEPA (Resto Países) account.

  • bank_address – Bank address for a non-SEPA account.

  • bank_city – Bank city for a non-SEPA account.

  • bank_country_code – ISO 3166-1 alpha-2 country code of the bank for a non-SEPA account.

  • sepa_marca – The derived Marca SEPA token ("1" Cuenta España / "2" UE SEPA / "3" Resto Países). Derived from the account country at export, not an operator input.

Parameters:
  • iban (str | None)

  • swift_bic (str)

  • bank_name (str)

  • bank_address (str)

  • bank_city (str)

  • bank_country_code (str)

  • sepa_marca (str)

iban: str | None
swift_bic: str
bank_name: str
bank_address: str
bank_city: str
bank_country_code: str
sepa_marca: str
class ModeloIVAProfile(**data)[source]

Bases: BaseModel

IVA facts used by registry filing schedules.

Variables:
  • roi_enrolled – Registered on the Registro de Operadores Intracomunitarios (ROI / VIES).

  • oss_enrolled – Enrolled in the OSS / IOSS one-stop-shop regime.

  • group_member_enrolled – Enrolled as a member entity in the IVA group-of-entities special regime; this is the Modelo 322 role.

  • group_dominant_entity_enrolled – Enrolled as the dominant entity of an IVA group-of-entities regime; this is the Modelo 353 role.

  • intracommunity_operations_exceed_50000_eur – Modelo 349 cadence threshold.

  • sii_enrolled – Enrolled in the SII (Suministro Inmediato de Información) — the near-real-time IVA ledger-submission system created by RD 596/2016. Mandatory for the monthly IVA collective; voluntary for everyone else. This records SII membership only; Modelo 303 monthly cadence is driven by monthly-liquidation facts such as REDEME or large-company status, not by voluntary SII alone.

  • redeme_enrolled – Registered in REDEME (Registro de Devolución Mensual del IVA) — one of the mandatory-SII triggers.

  • refund_account – The encrypted cuenta-devolución refund account AEAT pays a Modelo 303 refund into. None when no refund account is on file; a refund disposition with no refund account is refused at export rather than emitting an empty DID block.

Parameters:
  • roi_enrolled (bool)

  • oss_enrolled (bool)

  • group_member_enrolled (bool)

  • group_dominant_entity_enrolled (bool)

  • intracommunity_operations_exceed_50000_eur (bool)

  • sii_enrolled (bool)

  • redeme_enrolled (bool)

  • refund_account (RefundAccount | None)

roi_enrolled: bool
oss_enrolled: bool
group_member_enrolled: bool
group_dominant_entity_enrolled: bool
intracommunity_operations_exceed_50000_eur: bool
sii_enrolled: bool
redeme_enrolled: bool
refund_account: RefundAccount | None
class CrossPeriodGroupMemberRoster(**data)[source]

Bases: BaseModel

Expected member roster for a grouped cross-period dependency.

The roster is profile state, not a calculation artefact: grouped aggregate modelos such as Modelo 353 must know the complete member population before they can prove that every required upstream member filing was reconciled and accepted.

Parameters:
source_modelo: str
filing_year: int
period: Period
member_nifs: tuple[str, ...]
is_ue_eee_country_code(country_code)[source]

Return True when country_code is in the EU + EEA country set.

Return type:

bool

Parameters:

country_code (str | None)

irnr_representante_fiscal_required(country_code)[source]

Return True when an IRNR fiscal residence country requires representante fiscal.

Return type:

bool

Parameters:

country_code (str | None)

class TaxpayerProfile(**data)[source]

Bases: BaseModel

The profile of a Spanish taxpayer for filing-deadline computation.

Carries the structured three-axis taxpayer model — entity type, tax regime, and special enrolments — alongside the flat filing facts the deadline engine consumes today.

Variables:
  • tax_id – NIF / NIE / CIF. Stored verbatim, no normalisation.

  • entity_type – The taxpayer’s entity type (natural person, legal entity, or attribution entity). None when the operator has not yet declared it.

  • legal_entity_form – The recognised legal form when entity_type is LEGAL_ENTITY; None otherwise.

  • irpf_income_categories – The IRPF income categories a natural person declares (rendimientos). Empty when undeclared or when the taxpayer is not a natural person.

  • irpf_estimation_regime – The IRPF estimation regime for economic-activity income. None when undeclared.

  • iva_regime – The IVA regime the taxpayer files under.

  • has_employees – Whether the taxpayer pays salaries with retención.

  • pays_professionals_with_retencion – Whether the taxpayer pays professional fees subject to retención.

  • professional_income_withholding_ge_70pct – Whether at least 70% of the taxpayer’s prior-year professional income was already subject to withholding.

  • art109_activity_income_withholding_ge_70pct – Whether the Art. 109 RIRPF 70% income-coverage exception is met for covered professional, agricultural, livestock, or forestry activity income. For activity-start cases this is the current payment period coverage fact rather than a prior-year fact.

  • pays_rent_with_retencion – Whether the taxpayer pays alquiler de local with retención.

  • pays_capital_income_with_retencion – Whether the taxpayer pays capital-income rents subject to withholding.

  • member_of_large_multinational_group – Whether the entity is the reporting parent of a multinational group above the country-by-country reporting threshold (Modelo 231).

  • eu_business_seeking_spanish_vat_refund – Whether the taxpayer is an EU-established business, not established in Spanish VAT territory, requesting a refund of Spanish input VAT (Modelo 361).

  • reports_client_securities_insurance_annuities – Whether the entity is a financial or insurance intermediary that must report client securities, insurance and annuities (Modelo 189).

  • does_intracomunitario – Whether the taxpayer conducts operaciones intracomunitarias.

  • third_party_transactions_above_347_threshold – Whether the profile exceeded the applicable third-party transaction threshold during the prior year.

  • bienes_extranjero_above_threshold – Whether the taxpayer holds bienes en el extranjero above the legal threshold.

  • monedas_virtuales_extranjero_above_threshold – Whether the taxpayer holds virtual currencies abroad above the Modelo 721 threshold.

  • iva – IVA-specific filing facts that can change filing cadence.

  • cross_period_group_member_rosters – Expected group-member rosters keyed by upstream modelo, filing year, and period. These rosters let cross-period aggregate modelos prove complete member fan-in before verification, filing, or export.

  • enrollment – AEAT enrollment facts that can change filing cadence.

  • notes – Free-form notes for the user. Never consumed by the engine.

  • irpf_special_regime – The IRPF special regime in effect for this taxpayer. None when undeclared (treated as GENERAL by engine consumers). IMPATRIADO activates the Ley Beckham path (LIRPF Art. 93): the CLI refuses Modelo 100 in favour of Modelo 151 and the obligation engine suppresses Modelo 100 deadlines.

  • special_regime_start_date – The date of the opt-in election for the special regime. Required to compute the six-year window for IMPATRIADO (RIRPF Art. 116). None when undeclared or when irpf_special_regime is GENERAL.

  • fiscal_residency – Fiscal residency category. None treated as RESIDENT_IRPF by engine consumers. NON_RESIDENT_IRNR routes the taxpayer to IRNR (TRLIRNR RDLeg 5/2004 Art. 2): the engine suppresses IRPF-resident deadlines and will activate IRNR obligations (Modelos 210/216/247) when their registry entries are wired.

  • country_of_fiscal_residence – ISO 3166-1 alpha-2 code of the

  • when (country of fiscal residence. Required)

  • is (fiscal_residency is NON_RESIDENT_IRNR; None)

  • residents. (valid only for IRPF)

  • ley_49_2002_special_regime_option_declared – Whether the entity has declared the Modelo 036 option for the Title II Ley 49/2002 special fiscal regime. None means undeclared.

  • ley_49_2002_special_regime_option_date – Date declared for that option on Modelo 036. None means undeclared.

  • ley_49_2002_special_regime_renunciation_declared – Whether the entity has declared renunciation of the Title II Ley 49/2002 special regime. None means undeclared.

  • ley_49_2002_special_regime_renunciation_date – Date declared for that renunciation on Modelo 036. None means undeclared.

Parameters:
  • tax_id (str)

  • entity_type (EntityType | None)

  • legal_entity_form (LegalEntityForm | None)

  • irpf_income_categories (frozenset[IrpfIncomeCategory])

  • irpf_estimation_regime (IrpfEstimationRegime | None)

  • iva_regime (IVARegime)

  • has_employees (bool)

  • pays_professionals_with_retencion (bool)

  • professional_income_withholding_ge_70pct (bool)

  • art109_activity_income_withholding_ge_70pct (bool)

  • pays_rent_with_retencion (bool)

  • pays_capital_income_with_retencion (bool)

  • objective_estimation_prior_year_gross_income_eur (Decimal | None)

  • objective_estimation_prior_year_invoice_gross_income_eur (Decimal | None)

  • objective_estimation_prior_year_agri_livestock_forest_gross_eur (Decimal | None)

  • objective_estimation_prior_year_purchases_eur (Decimal | None)

  • objective_estimation_modulos_iae_epigraph (str)

  • objective_estimation_modulos_module_1_units (Decimal | None)

  • objective_estimation_modulos_module_2_units (Decimal | None)

  • objective_estimation_modulos_module_3_units (Decimal | None)

  • objective_estimation_modulos_module_4_units (Decimal | None)

  • objective_estimation_modulos_module_5_units (Decimal | None)

  • objective_estimation_modulos_module_6_units (Decimal | None)

  • objective_estimation_modulos_module_7_units (Decimal | None)

  • does_intracomunitario (bool)

  • third_party_transactions_above_347_threshold (bool)

  • bienes_extranjero_above_threshold (bool)

  • monedas_virtuales_extranjero_above_threshold (bool)

  • iva (ModeloIVAProfile)

  • cross_period_group_member_rosters (tuple[CrossPeriodGroupMemberRoster, ...])

  • enrollment (ModeloEnrollment)

  • fiscal_address_cadastral_reference (str)

  • fiscal_address_is_habitual_vivienda (bool)

  • activity_start_date (date | None)

  • activity_end_date (date | None)

  • incn_prior_12_months (Decimal | None)

  • new_entity_first_two_profit_periods (bool | None)

  • ley_49_2002_special_regime_option_declared (bool | None)

  • ley_49_2002_special_regime_option_date (date | None)

  • ley_49_2002_special_regime_renunciation_declared (bool | None)

  • ley_49_2002_special_regime_renunciation_date (date | None)

  • tributacion_estado_porcentaje (Decimal | None)

  • establecimiento_type (str)

  • elected_withholding_pct (str)

  • vivienda_office_total_m2 (Decimal | None)

  • vivienda_office_office_m2 (Decimal | None)

  • iae_epigraph (str)

  • notes (str)

  • irpf_special_regime (IrpfSpecialRegime | None)

  • special_regime_start_date (date | None)

  • fiscal_residency (FiscalResidency | None)

  • country_of_fiscal_residence (str | None)

  • representante_fiscal_nif (str | None)

  • representante_fiscal_nombre (str | None)

  • sal_socios_trabajadores_count (int | None)

  • sal_reserva_especial_dotada (Decimal | None)

  • sal_capital_social (Decimal | None)

  • irpf_pagadores_count (int | None)

  • irpf_pagadores_secondary_income (Decimal | None)

  • irpf_pagadores_total_work_income (Decimal | None)

  • days_in_spain (dict[int, int])

tax_id: str
entity_type: EntityType | None
legal_entity_form: LegalEntityForm | None
irpf_income_categories: frozenset[IrpfIncomeCategory]
irpf_estimation_regime: IrpfEstimationRegime | None
iva_regime: IVARegime
has_employees: bool
pays_professionals_with_retencion: bool
professional_income_withholding_ge_70pct: bool
art109_activity_income_withholding_ge_70pct: bool
pays_rent_with_retencion: bool
pays_capital_income_with_retencion: bool
objective_estimation_prior_year_gross_income_eur: Decimal | None
objective_estimation_prior_year_invoice_gross_income_eur: Decimal | None
objective_estimation_prior_year_agri_livestock_forest_gross_eur: Decimal | None
objective_estimation_prior_year_purchases_eur: Decimal | None
objective_estimation_modulos_iae_epigraph: str
objective_estimation_modulos_module_1_units: Decimal | None
objective_estimation_modulos_module_2_units: Decimal | None
objective_estimation_modulos_module_3_units: Decimal | None
objective_estimation_modulos_module_4_units: Decimal | None
objective_estimation_modulos_module_5_units: Decimal | None
objective_estimation_modulos_module_6_units: Decimal | None
objective_estimation_modulos_module_7_units: Decimal | None
does_intracomunitario: bool
third_party_transactions_above_347_threshold: bool
bienes_extranjero_above_threshold: bool
monedas_virtuales_extranjero_above_threshold: bool
iva: ModeloIVAProfile
cross_period_group_member_rosters: tuple[CrossPeriodGroupMemberRoster, ...]
enrollment: ModeloEnrollment
fiscal_address_cadastral_reference: str
fiscal_address_is_habitual_vivienda: bool
activity_start_date: date | None
activity_end_date: date | None
incn_prior_12_months: Decimal | None
new_entity_first_two_profit_periods: bool | None
ley_49_2002_special_regime_option_declared: bool | None
ley_49_2002_special_regime_option_date: date | None
ley_49_2002_special_regime_renunciation_declared: bool | None
ley_49_2002_special_regime_renunciation_date: date | None
tributacion_estado_porcentaje: Decimal | None
establecimiento_type: str
elected_withholding_pct: str
vivienda_office_total_m2: Decimal | None
vivienda_office_office_m2: Decimal | None
iae_epigraph: str
notes: str
irpf_special_regime: IrpfSpecialRegime | None
special_regime_start_date: date | None
fiscal_residency: FiscalResidency | None
country_of_fiscal_residence: str | None
representante_fiscal_nif: str | None

NIF/NIE of the fiscal representative in Spain.

Required when fiscal_residency is NON_RESIDENT_IRNR and the country is outside the EU/EEA (Art. 47 LGT + Art. 10 TRLIRNR RDLeg 5/2004).

representante_fiscal_nombre: str | None

Full name of the fiscal representative in Spain.

Required together with representante_fiscal_nif for the same cases.

sal_socios_trabajadores_count: int | None
sal_reserva_especial_dotada: Decimal | None
sal_capital_social: Decimal | None
irpf_pagadores_count: int | None

Number of pagadores (income payers) the taxpayer received income from.

When >= 2 and irpf_pagadores_secondary_income > 1500, filing Modelo 100 is mandatory under Art. 96.3 LIRPF regardless of the total income threshold. None when not declared (treated as “not known”).

irpf_pagadores_secondary_income: Decimal | None

Sum of income received from the 2nd and subsequent pagadores.

Art. 96.3 LIRPF: when irpf_pagadores_count >= 2 and this value exceeds €1,500, the work-income filing-exemption limit drops from the general €22,000 to the per-year reduced limit. Only meaningful when irpf_pagadores_count >= 2; None when not declared.

irpf_pagadores_total_work_income: Decimal | None

Total rendimientos íntegros del trabajo for the year (all pagadores).

Art. 96.2.a)/96.3 LIRPF: a Modelo 100 filing obligation arises when this total exceeds the applicable exemption limit — the general €22,000, or the per-year reduced limit (€15,876 for 2024 onward) when the multiple-pagadores condition is met. None when not declared, in which case a triggered multiple-pagadores condition surfaces a conservative advisory.

days_in_spain: dict[int, int]

Days of physical presence in Spain per calendar year.

Maps year (e.g. 2024) to number of days. Used to assess proximity to the Art. 9 LIRPF habitual residence threshold (183 days). The advisory RESIDENCY_BOUNDARY_NEAR is triggered when any declared year falls in the 150-215 day range – close enough to the threshold that the operator should verify the actual count carefully.

Recorded via --days-in-spain YYYY=NDAYS on the profile.

beckham_window_active(today)[source]

Return True if the Beckham window (Art. 93 LIRPF) is active on today.

The window covers the year of election and the following five calendar years — six years total (RIRPF Art. 116.1). Year-7 and beyond return False; the taxpayer reverts to the general IRPF regime. Returns False for any non-IMPATRIADO profile regardless of date.

Parameters:

today (date) – Reference date for the window check (caller supplies date.today() in production; tests supply a fixed date).

Return type:

bool

Returns:

True only when irpf_special_regime is IMPATRIADO and start_date.year <= today.year <= start_date.year + 5.

property ue_eee_status: bool

True when country_of_fiscal_residence is in the EU + EEA (post-Brexit).

GB is excluded from 2021-01-01 (Brexit transition end). Returns False when country_of_fiscal_residence is None (i.e., for IRPF-resident profiles).

property residency_boundary_near: bool

True when any declared year’s presence count falls in the 150-215 day window.

Art. 9 LIRPF: habitual residence in Spain is presumed when the taxpayer is present for more than 183 days in a calendar year. Days 150-215 form a boundary zone where the actual residency determination requires careful verification – either because the taxpayer may cross the threshold (150-182) or because they already exceed it but by a modest margin (184-215) that could be disputed.

Returns False when days_in_spain is empty.

resolve_multiple_pagadores_reduced_limit(filing_year)[source]

Return the Art. 96.3 LIRPF reduced work-income exemption limit for filing_year.

The reduced limit is dated (14.000 € up to 2022, 15.000 € for 2023, 15.876 € for 2024 onward); the authoritative per-year schedule lives in WORK_INCOME_MULTIPLE_PAGADORES_REDUCED_LIMIT_EUR_BY_YEAR. A year before the earliest tabulated entry resolves to the earliest known amount; a year after the latest entry resolves to the latest known amount (forward-compatible until a new law revalues it); None resolves to the latest known amount so a year-agnostic operator surface uses the current figure.

Parameters:

filing_year (int | None) – The year the work income was obtained, or None.

Return type:

Decimal

Returns:

The reduced exemption limit in euros as a Decimal.

evaluate_multiple_pagadores_obligation(pagadores_count, secondary_income, total_work_income=None, filing_year=None)[source]

Return True when Art. 96.3 LIRPF mandates Modelo 100 filing.

Art. 96.2.a) LIRPF (Ley 35/2006) exempts a natural person from filing when their rendimientos íntegros del trabajo do not exceed the general 22.000 € limit. Art. 96.3 LIRPF LOWERS that limit to a reduced, dated amount (15.876 € for 2024 onward) when the work income comes from more than one pagador AND the aggregate from the 2nd-and-subsequent pagadores strictly exceeds 1.500 €. The multiple-pagadores situation never obliges a filing by itself — it only drops the exemption limit — so the obligation arises only when total work income exceeds the applicable reduced limit.

Parameters:
  • pagadores_count (int | None) – Number of pagadores the taxpayer received work income from during the year. None means undeclared.

  • secondary_income (Decimal | None) – Sum of income from the 2nd and subsequent pagadores. None means undeclared.

  • total_work_income (Decimal | None) – Total rendimientos íntegros del trabajo for the year. None means undeclared; the obligation then cannot be ruled out, so the rule surfaces conservatively rather than granting a false clear (no-silent-under-declaration).

  • filing_year (int | None) – The year the income was obtained, selecting the dated reduced limit. None uses the latest known reduced limit.

Return type:

bool

Returns:

True when the reduced-limit regime is active (count >= 2 AND secondary_income > 1,500) and either total work income is undeclared or it strictly exceeds the per-year reduced limit; False in every other case, including when count or secondary income is undeclared.

class RecargoBand(**data)[source]

Bases: BaseModel

One Ley 58/2003 art-27 recargo band loaded from the registry TOML.

The bracket table at registry/aeat/legal/ley-58-2003-recargo-bands.toml carries the surcharge schedule for self-assessments filed after the deadline without prior AEAT notice. Each row materialises into one RecargoBand; the Recovery value attached to an OVERDUE ModeloDeadline references the resolved band by id.

Variables:
  • id – Stable identifier (completed_months_0, after_12_months, …). Used by the CLI for per-band rendering.

  • min_completed_months – Inclusive lower bound on the completed-months window this band covers. Art. 27.2 LGT counts only COMPLETED months of delay; a fractional month does not count.

  • max_completed_months – Inclusive upper bound, or None for the open-ended after_12_months band.

  • surcharge_pct – Recargo percentage applied on the cuota.

  • interest_applies – True only for the after-12-months band; the CLI renders the interest hint when set.

  • legal_ref – Stable corpus reference (ley-58-2003:art-27.2).

Parameters:
  • id (str)

  • min_completed_months (int)

  • max_completed_months (int | None)

  • surcharge_pct (Decimal)

  • interest_applies (bool)

  • legal_ref (str)

id: str
min_completed_months: int
max_completed_months: int | None
surcharge_pct: Decimal
interest_applies: bool
legal_ref: str
class Recovery(**data)[source]

Bases: BaseModel

Operator-facing recovery payload attached to an OVERDUE obligation.

Surfaces the resolved Ley 58/2003 art-27 recargo band plus a runnable next-action command the operator can copy. The CLI’s calendar renderer surfaces recovery\\t<band_id>\\t<surcharge_pct>%\\t<next_command> underneath each OVERDUE entry.

Variables:
  • still_filable – True for every band – art-27 self-assessments remain admissible past the original deadline; the surcharge is the only consequence. The flag exists so a future band for absolutely-time-barred filings can be added without reshaping the model.

  • recargo_band – The RecargoBand resolved from the completed-months window (Art. 27.2 LGT).

  • legal_ref – Same as recargo_band.legal_ref; carried at the top level so renderers do not dereference.

  • next_command – Literal shell command the operator can copy to calculate the late filing.

Parameters:
still_filable: bool
recargo_band: RecargoBand
legal_ref: str
next_command: str
class ModeloDeadline(**data)[source]

Bases: BaseModel

A single filing obligation in a Schedule.

Variables:
  • modelo – The modelo string identifier; carried as a plain str on this record so JSON round-tripping is loss-free for downstream consumers.

  • period – The period covered as a typed Period (e.g. Period.from_year_and_code(2026, "1T")).

  • opens_on – The first day the AEAT filing window accepts the modelo for this period.

  • closes_on – The last day the AEAT filing window accepts the modelo for this period.

  • payment_cutoff_on – The cutoff for direct-debit payment, if applicable. None when there is no payment leg.

  • status – The ObligationStatus against the reference today used by DeadlineEngine.compute().

  • applies_because – Human-readable explanation of why the profile is obliged to file this modelo, resolved from the registry deadline applicability rule.

  • boe_references – Tuple of opaque BOE / Manual práctico citation keys. Stable identifiers, never URLs.

  • recovery – Resolved Recovery payload when status is OVERDUE; None for every other status. Populated by the deadline engine using the days-late window and the registry’s recargo bracket table.

Parameters:
  • modelo (str)

  • period (Annotated[Period, BeforeValidator(func=~aeat.domain.deadlines._models._parse_modelo_deadline_period, json_schema_input_type=PydanticUndefined)])

  • opens_on (date)

  • closes_on (date)

  • payment_cutoff_on (date | None)

  • status (ObligationStatus)

  • applies_because (str)

  • boe_references (tuple[str, ...])

  • recovery (Recovery | None)

modelo: str
period: Annotated[Period, BeforeValidator(_parse_modelo_deadline_period)]
opens_on: date
closes_on: date
payment_cutoff_on: date | None
status: ObligationStatus
applies_because: str
boe_references: tuple[str, ...]
recovery: Recovery | None
class Schedule(**data)[source]

Bases: BaseModel

The full filing schedule for a taxpayer profile for a given year.

Variables:
  • profile – The TaxpayerProfile the schedule was computed for.

  • year – The target year.

  • obligations – Tuple of ModeloDeadline ordered by (closes_on, modelo, period).

  • generated_at – UTC timestamp of when DeadlineEngine.compute() built this schedule. The only non-deterministic field.

Parameters:
profile: TaxpayerProfile
year: int
obligations: tuple[ModeloDeadline, ...]
generated_at: datetime