aeat.domain.calculations.registry._applicability module¶
Registry-grounded modelo-applicability derivation from the taxpayer model.
The overview surfaces (explain / calendar / agenda /
backlog) used to treat every profile as an autónomo en estimación
directa: the DeadlineEngine produces an
obligation for every modelo with a registered deadline window, and no
layer asked which kind of taxpayer this is. A pure landlord was told
Modelo 130 was overdue.
This module is the derivation layer: each modelo’s applicable
verdict is DERIVED from the three-axis
TaxpayerProfile model (entity type,
IRPF income categories, estimation regime) through a registry-grounded
rule table. The autónomo-by-default assumption is removed.
Four verdicts are possible:
ApplicabilityVerdict.APPLICABLE— the taxpayer model triggers this modelo.ApplicabilityVerdict.NOT_APPLICABLE— the taxpayer model positively excludes this modelo (a landlord has no Modelo 130; an S.L. has no Modelo 100).ApplicabilityVerdict.ATTRIBUTION_PASS_THROUGH— the profile is an attribution entity (comunidad de bienes, sociedad civil sin objeto mercantil) and the modelo asked about is a cuota self-assessment (the IRPF Modelo 100 / 130 or the IS Modelo 200 / 202). An attribution entity runs no IS and no IRPF cuota of its own — the régimen de atribución de rentas (LIRPF Title X Section 2) attributes the income to the members, who file the substantive tax. The honest answer to “what is my cuota” is “none — taxed in the members’ returns”. This is structurally distinct from a plainNOT_APPLICABLE: a salaried-only natural person is positively excluded from Modelo 200 because they file a different cuota (Modelo 100); an attribution entity files no cuota at all.ApplicabilityVerdict.INCOMPLETE— the taxpayer model is undeclared (noentity_typeand, for a natural person, no income categories), or the entity form is recognised-but-unsupported. The engine refuses to guess: it never reports a confident wrong obligation, and it never runs an IRPF cuota for a company or an IS cuota for an attribution entity.
The entity-type axis selects the income-tax route: a legal entity routes to the IS path (Modelo 200 / 202), a natural person to the IRPF path (Modelo 100 / 130), and an attribution entity to member pass-through for cuota self-assessments. IVA and payer-fact modelos are then decided by their own declared profile facts (IVA regime, withholding-payer facts, trade thresholds). This is the corporate-entity ADR §4 engine routing contract without treating pass-through income taxation as an exemption from non-income-tax obligations.
Canonical applicability authority — modelo level.
_MODELO_APPLICABILITY_RULES is the single canonical source for
modelo-level applicability. Any question of the form “does this
taxpayer ever owe this modelo?” is answered here. Code that derives
applicability verdicts MUST read from this table; it MUST NOT
re-implement the logic in another module or maintain a parallel copy
of the rules dict.
Relation to ``applicability_conditions`` on ``ModeloDeadlineWindow``.
ModeloDeadlineWindow carries a
applicability_conditions mapping that governs window-level
scheduling — which specific deadline window applies for a profile
within the set of applicable windows (e.g. Modelo 202 uses different
modality windows for the April / October / December instalments, and
some windows filter by entity_size). These conditions are
COMPLEMENTARY to the modelo-level rules, not replacements:
applicability_conditions operates after the modelo-level gate
confirms the modelo applies at all; it never overrides the modelo-level
verdict. Adding a condition to a deadline window does not affect the
ApplicabilityVerdict returned by derive_modelo_applicability().
Every rule carries legal_refs — scoped registry citation keys in
the law-slug:art-N form (e.g. ley-35-2006:art-99) that resolve
against src/aeat/_data/registry/aeat/legal/*.toml — per
.claude/rules/aeat-calculation-grounding.md: applicability is
regulatory data and must be registry-grounded, and every typed-ID
reference must point at an existing registry entity. The seed table
below covers the core modelo set an ordinary taxpayer encounters —
the IRPF Renta and pago-fraccionado modelos (100 / 130 / 131), the
corporate IS modelos (200 / 202), the IVA modelos (303 / 390), the
retención modelos and their annual companions (111 / 190, 115 / 180),
the operaciones modelos (349 / 347), and the attribution-entity
informational Modelo 184. Per-entity / per-regime expansion to the
remaining registered modelos is intentionally deferred, marked at
_SEED_COVERAGE_NOTICE.
- class ApplicabilityVerdict(*values)[source]¶
Bases:
StrEnumWhether a modelo applies to a taxpayer, derived from its model.
- Variables:
APPLICABLE – The declared taxpayer model triggers this modelo.
NOT_APPLICABLE – The declared taxpayer model positively excludes this modelo (e.g. a landlord has no Modelo 130 obligation; a sociedad limitada files no Modelo 100).
ATTRIBUTION_PASS_THROUGH – The profile is an attribution entity and the modelo is a cuota self-assessment (Modelo 100 / 130 / 200 / 202). The entity runs no IS and no IRPF cuota of its own — the régimen de atribución de rentas (LIRPF Title X Section 2) attributes the income to the members, who file the substantive tax. The honest answer to “what is my cuota” is “none — the income is taxed in the members’ returns”. Distinct from
NOT_APPLICABLE, which means the taxpayer files a different cuota.INCOMPLETE – The taxpayer model is not declared in enough detail to decide, or the entity form is recognised-but-unsupported. The engine refuses to guess — the operator must declare their taxpayer type first.
- APPLICABLE¶
- NOT_APPLICABLE¶
- ATTRIBUTION_PASS_THROUGH¶
- INCOMPLETE¶
- class ModeloApplicability(**data)[source]¶
Bases:
BaseModelThe derived applicability of one modelo for one taxpayer profile.
- Variables:
modelo – The AEAT modelo identifier.
verdict – The
ApplicabilityVerdictderived from the taxpayer model.reason – Operator-facing prose explaining the verdict. An
INCOMPLETEverdict carries one of two distinct rationales: the “declare your taxpayer type first” guidance when the taxpayer model is undeclared, or a “no rule derived yet” notice when the modelo has no seed rule (the latter is not a statement about the operator’s profile).legal_refs – Scoped registry citation keys (
law-slug:art-N) grounding the rule, each resolvable against the registrylegal/*.tomltables. Always at least one entry — applicability is regulatory data and must be grounded (.claude/rules/aeat-calculation-grounding.md). For anINCOMPLETEverdict the refs ground the concept being asked about (the LIRPF / LIS taxpayer definitions) so the operator still sees a citation.
- Parameters:
modelo (ModeloId)
verdict (ApplicabilityVerdict)
reason (_OperatorReason)
legal_refs (tuple[LegalRefId, ...])
- modelo: ModeloId¶
- verdict: ApplicabilityVerdict¶
- reason: _OperatorReason¶
- legal_refs: tuple[LegalRefId, ...]¶
- property applicable: bool¶
Return whether the modelo positively applies.
Only
ApplicabilityVerdict.APPLICABLEis a confident yes.NOT_APPLICABLE,ATTRIBUTION_PASS_THROUGHandINCOMPLETEall yieldFalse— the operative views must not surface an obligation the engine cannot positively justify. An attribution entity owes no cuota self-assessment, so a pass-through verdict is not an applicable obligation.
- class ModeloApplicabilityRule(**data)[source]¶
Bases:
BaseModelA single registry-grounded modelo-applicability rule.
A rule answers, for one modelo, the question “does the declared taxpayer model trigger this modelo?”. The predicate is expressed as closed sets over the three taxpayer axes; evaluation never invents legal behaviour beyond what the seed table grounds.
- Variables:
modelo – The AEAT modelo identifier the rule decides.
applicable_entity_types – The
EntityTypevalues the modelo applies to. A taxpayer whoseentity_typeis outside this set getsApplicabilityVerdict.NOT_APPLICABLE.required_income_categories – For a natural person, the IRPF income categories of which at least one must be declared for the modelo to apply. Empty means the modelo does not gate on income category (it applies to every natural person whose
entity_typematches). Non-empty means a natural person without any of these categories getsNOT_APPLICABLE— this is the gate that excludes Modelo 130 for a pure landlord.required_estimation_regimes – The IRPF estimation regimes the modelo applies to. Empty means the modelo does not gate on the estimation regime. Non-empty means a natural person whose
irpf_estimation_regimeis outside the set getsNOT_APPLICABLE. An undeclared regime resolves to the direct-estimation default: estimación directa is the default IRPF method (LIRPF art. 16; RIRPF art. 32 makes módulos opt-in), so an actividad-económica autónomo who has not explicitly elected módulos owes Modelo 130. This is the axis that splits Modelo 130 (estimación directa) from Modelo 131 (estimación objetiva): the two are mutually exclusive on the regime.applicable_fiscal_residencies – The fiscal residency categories the modelo applies to. Empty means the modelo does not gate on fiscal residency. An undeclared residency is kept on the resident-IRPF default path described by
TaxpayerProfile; a declared residency outside this set is a positive exclusion.applicable_iva_regimes – The IVA regimes that positively keep a modelo in scope. Empty means the modelo does not gate on IVA regime. Non-empty means a profile outside those regimes gets
NOT_APPLICABLE. This lets Modelo 303 / 390 be driven by the declared IVA obligation instead of borrowing the natural person’s IRPF income-category axis for legal and attribution entities.required_payer_fact – The
PayerFactthe modelo’s applicability depends on, orNonewhen the modelo does not gate on a payer fact. When set, a profile that positively declares the fact getsAPPLICABLE; a profile that does not getsINCOMPLETE— the underlying boolean has no tri-state, so the engine cannot positively justify aNOT_APPLICABLE(seePayerFact).applicable_reason – Operator-facing prose for the
APPLICABLEverdict.not_applicable_reason – Operator-facing prose for the
NOT_APPLICABLEverdict.cuota_bearing –
Truewhen the modelo is a cuota self-assessment (the IRPF Modelo 100 / 130 or the IS Modelo 200 / 202). A cuota-bearing modelo asked of an attribution entity yields anApplicabilityVerdict.ATTRIBUTION_PASS_THROUGHverdict rather than a plainNOT_APPLICABLE: the entity runs no cuota of its own, the income is taxed in the members’ returns (corporate-entity ADR §2). An informational modelo (Modelo 184) is not cuota-bearing — it stays a plainNOT_APPLICABLEfor the entity types itsapplicable_entity_typesexcludes.legal_refs – Scoped registry citation keys (
law-slug:art-N) grounding the rule, each resolvable against the registrylegal/*.tomltables.
- Parameters:
modelo (ModeloId)
applicable_entity_types (frozenset[EntityType])
required_income_categories (frozenset[IrpfIncomeCategory])
required_estimation_regimes (frozenset[IrpfEstimationRegime])
applicable_fiscal_residencies (frozenset[FiscalResidency])
required_payer_fact (PayerFact | None)
applicable_reason (_OperatorReason)
not_applicable_reason (_OperatorReason)
cuota_bearing (bool)
legal_refs (tuple[LegalRefId, ...])
- modelo: ModeloId¶
- applicable_entity_types: frozenset[EntityType]¶
- required_income_categories: frozenset[IrpfIncomeCategory]¶
- required_estimation_regimes: frozenset[IrpfEstimationRegime]¶
- applicable_fiscal_residencies: frozenset[FiscalResidency]¶
- applicable_iva_regimes: frozenset[IVARegime]¶
- required_payer_fact: PayerFact | None¶
- applicable_reason: _OperatorReason¶
- not_applicable_reason: _OperatorReason¶
- cuota_bearing: bool¶
- legal_refs: tuple[LegalRefId, ...]¶
- evaluate(profile)[source]¶
Derive the
ModeloApplicabilityforprofile.Returns an
INCOMPLETEverdict when the taxpayer model is not declared in enough detail to decide; anATTRIBUTION_PASS_THROUGHverdict when the modelo is a cuota self-assessment asked of an attribution entity; otherwise anAPPLICABLE/NOT_APPLICABLEverdict derived from the entity-type, income-category, estimation-regime, and payer-fact axes.- Parameters:
profile (
TaxpayerProfile) – TheTaxpayerProfileto evaluate against this rule.- Return type:
- iter_modelo_applicability_rules()[source]¶
Return the registry-owned seed
ModeloApplicabilityRuleinstances.The returned tuple is ordered by modelo id for deterministic audits and tests. Callers receive rule objects, not the mutable module-level dictionary, so the registry rule table remains read-only from the public API.
- Return type:
- taxpayer_model_is_declared(profile)[source]¶
Return whether the profile carries a usable taxpayer model.
The taxpayer model is “declared” when the operator has set an
entity_typeand — for a natural person — at least one IRPF income category. Without these, modelo applicability cannot be derived: the engine must reportINCOMPLETErather than assume autónomo. A legal / attribution entity needs no income category; theentity_typealone selects its tax.- Parameters:
profile (
TaxpayerProfile) – TheTaxpayerProfileto inspect.- Return type:
- derive_tax_route(profile)[source]¶
Return the tax branch
profileroutes to — corporate-entity ADR §4.The routing contract: the
entity_typeaxis selects the tax. A legal-entity profile routes to the Impuesto sobre Sociedades (Modelo 200 / 202); a natural person to the IRPF (Modelo 100 / 130 / 303); an attribution entity to the member pass-through. An undeclaredentity_typeyieldsTaxRoute.INCOMPLETE— the engine never runs an IRPF cuota for a company or an IS cuota for an attribution entity, and never defaults a tax for a profile that declared none.- Parameters:
profile (
TaxpayerProfile) – TheTaxpayerProfilewhoseentity_typeaxis selects the tax branch.- Return type:
- Returns:
The
TaxRoutebranch the profile’sentity_typeselects, orTaxRoute.INCOMPLETEwhenentity_typeis undeclared.
- derive_modelo_applicability(profile, modelo, *, today=None)[source]¶
Derive a modelo’s applicability from the taxpayer model.
The verdict is DERIVED from the three-axis
TaxpayerProfilemodel — never assumed. An undeclared taxpayer model yields an explicitApplicabilityVerdict.INCOMPLETEanswer; the engine never reports a confident wrong obligation.A modelo without a seed rule (the seed covers the core persona set only) is also reported
INCOMPLETEso the operator is never told a confident yes/no the registry rules cannot yet justify; the rationale points at the deferred expansion.- Parameters:
profile (
TaxpayerProfile) – The operator’s three-axis taxpayer model.modelo (
str) – The AEAT modelo identifier to decide.today (
date|None) – Reference date for the Beckham window check. Defaults todate.today()whenNone. Pass an explicit date in tests so results are deterministic.
- Return type:
- Returns:
The
ModeloApplicabilityformodeloandprofile.