"""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 :class:`~domain.deadlines.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
:class:`~domain.deadlines.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:
* :attr:`ApplicabilityVerdict.APPLICABLE` — the taxpayer model
triggers this modelo.
* :attr:`ApplicabilityVerdict.NOT_APPLICABLE` — the taxpayer model
positively excludes this modelo (a landlord has no Modelo 130;
an S.L. has no Modelo 100).
* :attr:`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 plain ``NOT_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.
* :attr:`ApplicabilityVerdict.INCOMPLETE` — the taxpayer model is
undeclared (no ``entity_type`` and, 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.**
:data:`_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 :func:`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
:data:`_SEED_COVERAGE_NOTICE`.
"""
from __future__ import annotations
from datetime import date
from enum import StrEnum
from typing import Annotated
from pydantic import BaseModel, Field, StringConstraints
from ....core import STRICT_FROZEN_CONFIG as _STRICT_FROZEN
from ....core import Modelo
from ...deadlines import FiscalResidency, IVARegime
from ...deadlines.taxpayer_model import (
EntityType,
IrpfEstimationRegime,
IrpfIncomeCategory,
TaxpayerProfile,
)
from ._applicability_labels import PAYER_FACT_INCOMPLETE_LABELS as _PAYER_FACT_INCOMPLETE_LABELS
from ._applicability_modelo202 import (
Modelo202Modality,
Modelo202ModalityVerdict,
derive_modelo_202_modality,
modelo_202_modality_from_inputs,
)
from ._applicability_payer_facts import PayerFact, payer_fact_holds
from ._applicability_routes import TAX_ROUTE_FOR_ENTITY_TYPE as _TAX_ROUTE_FOR_ENTITY_TYPE
from ._applicability_routes import TaxRoute
from ._ids import LegalRefId, ModeloId
type _OperatorReason = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
_SEED_COVERAGE_NOTICE = (
"Seed coverage only — the modelos in this table are the core "
"natural-person and corporate-entity set. Full per-entity / "
"per-regime applicability for every registered modelo is a "
"deferred expansion."
)
"""Explicit marker that the seed rule table is intentionally narrow.
A modelo absent from :data:`_MODELO_APPLICABILITY_RULES` is reported
with :attr:`ApplicabilityVerdict.INCOMPLETE` and a rationale pointing
at the deferred expansion — never a confident guess.
"""
[docs]
class ApplicabilityVerdict(StrEnum):
"""Whether a modelo applies to a taxpayer, derived from its model.
Attributes:
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 = "applicable"
NOT_APPLICABLE = "not_applicable"
ATTRIBUTION_PASS_THROUGH = "attribution_pass_through"
INCOMPLETE = "incomplete"
[docs]
class ModeloApplicability(BaseModel):
"""The derived applicability of one modelo for one taxpayer profile.
Attributes:
modelo: The AEAT modelo identifier.
verdict: The :class:`ApplicabilityVerdict` derived from the
taxpayer model.
reason: Operator-facing prose explaining the verdict. An
``INCOMPLETE`` verdict 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 registry
``legal/*.toml`` tables. Always at least one entry —
applicability is regulatory data and must be grounded
(``.claude/rules/aeat-calculation-grounding.md``). For an
``INCOMPLETE`` verdict the refs ground the *concept* being
asked about (the LIRPF / LIS taxpayer definitions) so the
operator still sees a citation.
"""
model_config = _STRICT_FROZEN
modelo: ModeloId
verdict: ApplicabilityVerdict
reason: _OperatorReason
legal_refs: tuple[LegalRefId, ...] = Field(min_length=1)
@property
def applicable(self) -> bool:
"""Return whether the modelo positively applies.
Only :attr:`ApplicabilityVerdict.APPLICABLE` is a confident
yes. ``NOT_APPLICABLE``, ``ATTRIBUTION_PASS_THROUGH`` and
``INCOMPLETE`` all yield ``False`` — 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.
"""
return self.verdict is ApplicabilityVerdict.APPLICABLE
[docs]
class ModeloApplicabilityRule(BaseModel):
"""A 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.
Attributes:
modelo: The AEAT modelo identifier the rule decides.
applicable_entity_types: The :class:`EntityType` values the
modelo applies to. A taxpayer whose ``entity_type`` is
outside this set gets :attr:`ApplicabilityVerdict.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_type`` matches). Non-empty means a natural
person without any of these categories gets
``NOT_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_regime`` is outside the set gets
``NOT_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 :class:`PayerFact` the modelo's
applicability depends on, or ``None`` when the modelo does
not gate on a payer fact. When set, a profile that
positively declares the fact gets ``APPLICABLE``; a profile
that does not gets ``INCOMPLETE`` — the underlying boolean
has no tri-state, so the engine cannot positively justify a
``NOT_APPLICABLE`` (see :class:`PayerFact`).
applicable_reason: Operator-facing prose for the
``APPLICABLE`` verdict.
not_applicable_reason: Operator-facing prose for the
``NOT_APPLICABLE`` verdict.
cuota_bearing: ``True`` when 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 an :attr:`ApplicabilityVerdict.ATTRIBUTION_PASS_THROUGH`
verdict rather than a plain ``NOT_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 plain ``NOT_APPLICABLE`` for the entity types
its ``applicable_entity_types`` excludes.
legal_refs: Scoped registry citation keys (``law-slug:art-N``)
grounding the rule, each resolvable against the registry
``legal/*.toml`` tables.
"""
model_config = _STRICT_FROZEN
modelo: ModeloId
applicable_entity_types: frozenset[EntityType] = Field(min_length=1)
required_income_categories: frozenset[IrpfIncomeCategory] = frozenset()
required_estimation_regimes: frozenset[IrpfEstimationRegime] = frozenset()
applicable_fiscal_residencies: frozenset[FiscalResidency] = frozenset()
applicable_iva_regimes: frozenset[IVARegime] = frozenset()
required_payer_fact: PayerFact | None = None
applicable_reason: _OperatorReason
not_applicable_reason: _OperatorReason
cuota_bearing: bool = False
legal_refs: tuple[LegalRefId, ...] = Field(min_length=1)
[docs]
def evaluate(self, profile: TaxpayerProfile) -> ModeloApplicability:
"""Derive the :class:`ModeloApplicability` for ``profile``.
Returns an ``INCOMPLETE`` verdict when the taxpayer model is not
declared in enough detail to decide; an
``ATTRIBUTION_PASS_THROUGH`` verdict when the modelo is a cuota
self-assessment asked of an attribution entity; otherwise an
``APPLICABLE`` / ``NOT_APPLICABLE`` verdict derived from the
entity-type, income-category, estimation-regime, and
payer-fact axes.
Args:
profile: The :class:`TaxpayerProfile` to evaluate against this rule.
"""
if profile.entity_type is None:
return _incomplete_applicability(self.modelo)
if profile.entity_type not in self.applicable_entity_types:
# An attribution entity asked about a cuota self-assessment
# gets the honest pass-through answer, not a plain
# exclusion: it runs no IS and no IRPF cuota — the income
# is attributed to and taxed in the members' returns
# (corporate-entity ADR §2). An informational modelo is not
# cuota-bearing and falls through to NOT_APPLICABLE.
if self.cuota_bearing and profile.entity_type is EntityType.ATTRIBUTION_ENTITY:
return ModeloApplicability(
modelo=self.modelo,
verdict=ApplicabilityVerdict.ATTRIBUTION_PASS_THROUGH,
reason=_ATTRIBUTION_PASS_THROUGH_REASON,
legal_refs=_ATTRIBUTION_PASS_THROUGH_LEGAL_REFS,
)
return self._not_applicable()
if (
self.applicable_fiscal_residencies
and profile.fiscal_residency is not None
and profile.fiscal_residency not in self.applicable_fiscal_residencies
):
return self._not_applicable()
if self.applicable_iva_regimes and profile.iva_regime not in self.applicable_iva_regimes:
return self._not_applicable()
# The income-category and estimation-regime axes are
# natural-person facts: a legal entity carries neither (income
# categories and the IRPF estimation regime only describe a
# persona física). A legal or attribution entity that matched
# the entity-type and IVA-regime gates of a modelo applicable to
# it (e.g. Modelo 303 / 390) is not re-gated on those axes.
if profile.entity_type is EntityType.NATURAL_PERSON:
# A natural-person modelo that gates on income category needs
# at least one declared category to match.
if self.required_income_categories:
if not profile.irpf_income_categories:
return _incomplete_applicability(self.modelo)
if profile.irpf_income_categories.isdisjoint(self.required_income_categories):
return self._not_applicable()
# The estimation-regime axis splits Modelo 130 (estimación
# directa) from Modelo 131 (estimación objetiva). A regime
# outside the rule's set is a positive exclusion.
#
# When ``irpf_estimation_regime`` is undeclared, resolve the
# split to the direct-estimation default. Estimación objetiva
# is an explicit módulos election; without that enum value the
# current profile stays on Modelo 130 rather than a retained
# boolean side channel.
if self.required_estimation_regimes:
regime = profile.irpf_estimation_regime or IrpfEstimationRegime.DIRECTA_NORMAL
if regime not in self.required_estimation_regimes:
return self._not_applicable()
# The payer-fact axis (Modelo 111 / 115 / 349 / 347) can only be
# asserted in the positive direction — the underlying boolean has
# no tri-state, so an absent fact yields INCOMPLETE rather than a
# NOT_APPLICABLE the engine cannot positively justify.
if self.required_payer_fact is not None and not payer_fact_holds(profile, self.required_payer_fact):
return _undetermined_applicability(
self.modelo,
payer_fact=self.required_payer_fact,
legal_refs=self.legal_refs,
)
return ModeloApplicability(
modelo=self.modelo,
verdict=ApplicabilityVerdict.APPLICABLE,
reason=self.applicable_reason,
legal_refs=self.legal_refs,
)
def _not_applicable(self) -> ModeloApplicability:
"""Return the ``NOT_APPLICABLE`` applicability for this rule."""
return ModeloApplicability(
modelo=self.modelo,
verdict=ApplicabilityVerdict.NOT_APPLICABLE,
reason=self.not_applicable_reason,
legal_refs=self.legal_refs,
)
# Scoped registry citation keys grounding the "declare your taxpayer
# type first" answer. An undeclared profile cannot be decided, but the
# verdict still carries the LIRPF / LIS articles that frame the question
# the operator must answer. Both keys resolve in the registry legal
# tables (irpf.toml / is.toml).
_INCOMPLETE_LEGAL_REFS: tuple[LegalRefId, ...] = (
"ley-35-2006:art-99", # LIRPF art. 99 — IRPF contribuyente / pagos a cuenta.
"ley-27-2014:art-124", # LIS art. 124 — obligación de declarar del IS.
)
# Scoped registry citation keys grounding the attribution pass-through
# verdict — the régimen de atribución de rentas. LIRPF art. 86 fixes
# the general régimen (income attributed to socios / herederos /
# comuneros / partícipes); LIRPF art. 87 defines which entities fall
# under it (sociedades civiles sin objeto mercantil, comunidades de
# bienes, herencias yacentes). Both keys resolve in the registry legal
# table ``legal/irpf.toml``.
_ATTRIBUTION_PASS_THROUGH_LEGAL_REFS: tuple[LegalRefId, ...] = (
"ley-35-2006:art-86", # LIRPF art. 86 — régimen general de atribución de rentas.
"ley-35-2006:art-87", # LIRPF art. 87 — entidades en régimen de atribución.
)
_ATTRIBUTION_PASS_THROUGH_REASON = (
"Una entidad en régimen de atribución de rentas (comunidad de bienes, "
"sociedad civil sin objeto mercantil) no presenta autoliquidación de "
"cuota propia: no tributa por el Impuesto sobre Sociedades ni por el "
"IRPF. La renta se atribuye a cada socio, comunero o partícipe y "
"tributa en la declaración de cada miembro. La obligación propia de la "
"entidad es informativa (Modelo 184)."
)
"""``ATTRIBUTION_PASS_THROUGH`` rationale.
The honest answer to "what is my cuota" for an attribution entity: it
files no IS and no IRPF cuota of its own (corporate-entity ADR §2).
The substantive tax is each member's; the entity's own obligation is
the informational Modelo 184.
"""
_INCOMPLETE_UNDECLARED_REASON = (
"No se puede determinar la aplicabilidad: el tipo de contribuyente no "
"está declarado. Declare primero el tipo de entidad y, en su caso, las "
"categorías de renta del IRPF con 'aeat config profile edit'."
)
"""``INCOMPLETE`` rationale for an *undeclared taxpayer model*.
Used only when the engine cannot decide because the profile itself is
incomplete: no ``entity_type``, or a natural person with no declared
IRPF income category against a category-gated rule. The guidance to
declare the taxpayer type first is correct here.
"""
_INCOMPLETE_UNRULED_REASON = (
"No se puede determinar la aplicabilidad de este modelo: todavía no se "
"ha derivado una regla de aplicabilidad para él. La cobertura de reglas "
"es deliberadamente reducida (el conjunto inicial de personas) y la "
"expansión por entidad y régimen está pendiente. No es una afirmación "
"sobre su perfil: su tipo de contribuyente puede estar correctamente "
"declarado."
)
"""``INCOMPLETE`` rationale for a *modelo with no seed rule*.
Used when :data:`_MODELO_APPLICABILITY_RULES` carries no rule for the
requested modelo. The profile may be fully declared; this verdict is a
statement about the seed coverage (:data:`_SEED_COVERAGE_NOTICE`), not
about the operator. It must never tell a declared operator to declare
their taxpayer type.
"""
_INCOMPLETE_UNDETERMINED_REASON = (
"No se puede determinar la aplicabilidad de este modelo desde el modelo "
"de contribuyente declarado: depende de un hecho que el perfil no "
"expresa con certeza. El modelo solo se afirma aplicable cuando ese "
"hecho se declara positivamente; en otro caso no se conjetura una "
"obligación."
)
_IMPATRIADO_M720_LEGAL_REFS: tuple[LegalRefId, ...] = (
"ley-35-2006:art-93", # LIRPF Art. 93 — régimen especial impatriados.
"ley-7-2012:da-1", # Ley 7/2012 DA 1ª — obligación Modelo 720.
"orden-hap-72-2013:art-1", # Orden HAP/72/2013 — aprobación Modelo 720.
)
"""Legal refs grounding the IRPF Art. 93 impatriado Modelo 720 exemption.
An impatriado under LIRPF Art. 93 is taxed as a non-resident (IRNR) for
the duration of the special regime. Modelo 720 (bienes en el extranjero)
is an obligation reserved for IRPF residents; it does not extend to
non-residents or to IRPF taxpayers who have opted into the IRNR-rate
regime. The general Art. 93 key resolves in the registry table
``legal/irpf-impatriados.toml``; the two Modelo 720 keys resolve in the
table ``legal/modelo-720.toml``.
"""
_IMPATRIADO_M720_EXEMPT_REASON = (
"Modelo 720 no aplica: el contribuyente tiene activado el régimen "
"especial para trabajadores desplazados a territorio español (LIRPF "
"Art. 93). En este régimen el contribuyente tributa conforme al IRNR "
"y no tiene la consideración de contribuyente residente del IRPF a "
"efectos de la obligación de declarar bienes y derechos en el "
"extranjero. La obligación del Modelo 720 corresponde exclusivamente "
"a los residentes fiscales contribuyentes del IRPF (DA 18ª Ley "
"58/2003 LGT introducida por la Ley 7/2012 DA 1ª)."
)
"""``NOT_APPLICABLE`` rationale for the impatriado Art. 93 M720 exemption.
Surfaced when ``profile.irpf_special_regime is IrpfSpecialRegime.IMPATRIADO``
and ``modelo == "720"``. The pre-check in :func:`derive_modelo_applicability`
fires before the :data:`_MODELO_APPLICABILITY_RULES` lookup to guarantee the
exemption is enforced even when ``bienes_extranjero_above_threshold`` is
``True``.
"""
_IMPATRIADO_M151_ROUTE_LEGAL_REFS: tuple[LegalRefId, ...] = (
"ley-35-2006:art-93", # LIRPF Art. 93 — impatriados opt into IRNR taxation.
"rd-439-2007:art-115", # RIRPF Art. 115 — duration of the special regime.
"rd-439-2007:art-116", # RIRPF Art. 116 — option exercise / start-date selector.
"orden-eha-2887-2008:modelo-151", # Form order for the Modelo 151 declaration.
)
"""Legal refs grounding the Art. 93 Modelo 151 route and M100 suppression."""
_IMPATRIADO_M100_SUPPRESSED_REASON = (
"Modelo 100 no aplica: el contribuyente tiene activo el régimen especial "
"de trabajadores, profesionales, emprendedores e inversores desplazados "
"a territorio español (LIRPF Art. 93) dentro de la ventana de seis "
"ejercicios. Durante esa ventana tributa por las reglas del IRNR "
"manteniendo la condición de contribuyente IRPF, y la declaración anual "
"correspondiente es el Modelo 151, no el Modelo 100."
)
"""``NOT_APPLICABLE`` rationale for suppressing M100 during Art. 93."""
_IMPATRIADO_M151_APPLICABLE_REASON = (
"Modelo 151 aplica: el contribuyente tiene activo el régimen especial de "
"impatriados del Art. 93 LIRPF dentro de la ventana de seis ejercicios "
"del año de opción y los cinco siguientes; la declaración anual del "
"régimen se presenta por Modelo 151."
)
"""``APPLICABLE`` rationale for the active Art. 93 Modelo 151 route."""
_IMPATRIADO_M151_NOT_APPLICABLE_REASON = (
"Modelo 151 no aplica: el perfil no tiene activo el régimen especial de "
"impatriados del Art. 93 LIRPF dentro de su ventana de seis ejercicios. "
"Fuera de esa ventana, o sin opción por el régimen, la persona física "
"residente vuelve a la ruta ordinaria del IRPF y al Modelo 100 cuando "
"proceda."
)
"""``NOT_APPLICABLE`` rationale for M151 outside the active Art. 93 window."""
def _incomplete_applicability(
modelo: str,
*,
unruled: bool = False,
) -> ModeloApplicability:
"""Return the explicit ``INCOMPLETE`` applicability for ``modelo``.
The safe default: the engine never assumes autónomo and never
reports a confident wrong obligation. The two ``INCOMPLETE`` causes
are structurally distinct and carry distinct rationale:
Args:
modelo: The AEAT modelo identifier the verdict decides.
unruled: ``True`` when the cause is a *missing seed rule* for the
modelo — the profile may be fully declared. ``False`` (the
default) when the cause is an *undeclared taxpayer model* —
the operator must declare their taxpayer type first.
Returns:
A :class:`ModeloApplicability` with ``INCOMPLETE`` verdict and the
appropriate rationale for the given cause.
"""
reason = _INCOMPLETE_UNRULED_REASON if unruled else _INCOMPLETE_UNDECLARED_REASON
return ModeloApplicability(
modelo=modelo,
verdict=ApplicabilityVerdict.INCOMPLETE,
reason=reason,
legal_refs=_INCOMPLETE_LEGAL_REFS,
)
def _undetermined_applicability(
modelo: str,
*,
payer_fact: PayerFact,
legal_refs: tuple[LegalRefId, ...],
) -> ModeloApplicability:
"""Return the ``INCOMPLETE`` applicability for an *undecidable* fact.
Used when a modelo gates on a :class:`PayerFact` (Modelo
111 / 115 / 349 / 347 / 720 / 721) and the profile does not positively declare
the fact. The taxpayer model itself may be fully declared — the
entity type and regime are known — but the payer fact has no
tri-state, so the engine refuses to guess a ``NOT_APPLICABLE`` it
cannot positively justify. The rationale is distinct from the
*undeclared taxpayer model* one: it never tells a declared operator
to declare their taxpayer type.
Args:
modelo: The AEAT modelo identifier the verdict decides.
payer_fact: The specific profile fact required to positively
establish applicability.
legal_refs: The concrete rule legal refs that ground the
undecidable payer-fact question.
Returns:
A :class:`ModeloApplicability` with ``INCOMPLETE`` verdict and the
undetermined-payer-fact rationale.
"""
return ModeloApplicability(
modelo=modelo,
verdict=ApplicabilityVerdict.INCOMPLETE,
reason=(
f"{_INCOMPLETE_UNDETERMINED_REASON} "
f"Hecho requerido para este modelo: {_PAYER_FACT_INCOMPLETE_LABELS[payer_fact]}."
),
legal_refs=legal_refs,
)
# ---------------------------------------------------------------------
# Seed rule table — core persona coverage (see _SEED_COVERAGE_NOTICE)
# ---------------------------------------------------------------------
#
# Every rule below is grounded against the registry legal tables for the
# taxpayer-type applicability model. Citation keys are scoped registry
# keys (``law-slug:art-N``) that resolve against
# ``src/aeat/_data/registry/aeat/legal/*.toml`` — never URLs, never
# invented slugs. Full per-entity / per-regime coverage of every
# registered modelo is a deferred expansion.
_NATURAL_PERSON: frozenset[EntityType] = frozenset({EntityType.NATURAL_PERSON})
_LEGAL_ENTITY: frozenset[EntityType] = frozenset({EntityType.LEGAL_ENTITY})
_ATTRIBUTION_ENTITY: frozenset[EntityType] = frozenset({EntityType.ATTRIBUTION_ENTITY})
_IVA_OBLIGED_ENTITY_TYPES: frozenset[EntityType] = frozenset(
{EntityType.NATURAL_PERSON, EntityType.LEGAL_ENTITY, EntityType.ATTRIBUTION_ENTITY},
)
_IVA_SELF_ASSESSMENT_REGIMES: frozenset[IVARegime] = frozenset(
{IVARegime.GENERAL, IVARegime.SIMPLIFICADO},
)
_PAYER_FACT_ENTITY_TYPES: frozenset[EntityType] = frozenset(
{EntityType.NATURAL_PERSON, EntityType.LEGAL_ENTITY, EntityType.ATTRIBUTION_ENTITY},
)
_MODELO_APPLICABILITY_RULES: dict[str, ModeloApplicabilityRule] = {
# Modelo 100 — declaración anual de la Renta (IRPF). Applies to every
# natural person who is an IRPF contribuyente, regardless of which
# income category they declare. It does NOT apply to a legal entity:
# an S.L. is a contribuyente del Impuesto sobre Sociedades and files
# Modelo 200, never Modelo 100. Research §1.1, §1.2.
Modelo.M100: ModeloApplicabilityRule(
modelo=Modelo.M100,
applicable_entity_types=_NATURAL_PERSON,
required_income_categories=frozenset(),
applicable_reason=(
"Modelo 100 (declaración de la Renta): una persona física "
"residente es contribuyente del IRPF y presenta la "
"autoliquidación anual de la Renta."
),
applicable_fiscal_residencies=frozenset({FiscalResidency.RESIDENT_IRPF}),
not_applicable_reason=(
"Modelo 100 no aplica: la declaración de la Renta corresponde "
"únicamente a las personas físicas residentes contribuyentes del "
"IRPF. El tipo de contribuyente declarado no es una persona "
"física residente, o bien es un contribuyente NON_RESIDENT_IRNR. "
"Un contribuyente NON_RESIDENT_IRNR tributa por el IRNR y presenta "
"el Modelo 210 por la Sede Electrónica de la AEAT, no el Modelo 100."
),
# Modelo 100 is the IRPF cuota self-assessment: an attribution
# entity asked about it gets the pass-through verdict.
cuota_bearing=True,
# LIRPF art. 99 — régimen general de pagos a cuenta del IRPF,
# que identifica al contribuyente del IRPF; art. 17 —
# rendimientos del trabajo, la categoría de renta más común que
# obliga a la persona física a presentar la Renta.
legal_refs=(
"ley-35-2006:art-99",
"ley-35-2006:art-17",
"trlirnr-rdleg-5-2004:art-2",
),
),
# Modelo 130 — pago fraccionado del IRPF, estimación DIRECTA. Triggered
# by the rendimientos de actividades económicas income category (LIRPF
# Arts. 27-32) ONLY when the activity is in estimación directa (normal
# o simplificada). An activity in estimación objetiva (módulos) files
# Modelo 131 instead — the two are mutually exclusive on the regime.
# A natural person whose only income is capital inmobiliario (a pure
# landlord), trabajo, pensión, etc. has no actividad económica and
# therefore no Modelo 130. A legal entity never files Modelo 130.
Modelo.M130: ModeloApplicabilityRule(
modelo=Modelo.M130,
applicable_entity_types=_NATURAL_PERSON,
required_income_categories=frozenset({IrpfIncomeCategory.ACTIVIDAD_ECONOMICA}),
required_estimation_regimes=frozenset(
{
IrpfEstimationRegime.DIRECTA_NORMAL,
IrpfEstimationRegime.DIRECTA_SIMPLIFICADA,
},
),
applicable_fiscal_residencies=frozenset({FiscalResidency.RESIDENT_IRPF}),
applicable_reason=(
"Modelo 130 (pago fraccionado del IRPF): la persona física "
"residente IRPF declara rendimientos de actividades económicas "
"en estimación directa, que generan la obligación del pago "
"fraccionado."
),
not_applicable_reason=(
"Modelo 130 no aplica: el pago fraccionado en estimación "
"directa solo corresponde a la persona física residente IRPF "
"que obtiene rendimientos de actividades económicas determinados "
"por ese método. Una actividad en estimación objetiva presenta "
"el Modelo 131; un contribuyente NON_RESIDENT_IRNR queda en la "
"ruta IRNR."
),
# Modelo 130 is an IRPF pago-fraccionado cuota self-assessment:
# an attribution entity asked about it gets the pass-through
# verdict — it runs no IRPF cuota of its own.
cuota_bearing=True,
# RD 439/2007 art. 110 — pago fraccionado del IRPF en estimación
# directa, importe y cálculo; Orden EHA/672/2007 art. 1 —
# aprobación del Modelo 130; LIRPF art. 99 — pagos fraccionados
# como pagos a cuenta del IRPF.
legal_refs=(
"rd-439-2007:art-110",
"orden-eha-672-2007:art-1",
"ley-35-2006:art-99",
"trlirnr-rdleg-5-2004:art-2",
),
),
# Modelo 131 — pago fraccionado del IRPF, estimación OBJETIVA (módulos).
# Triggered by the rendimientos de actividades económicas income
# category ONLY when the activity is determined under estimación
# objetiva. This is the regime counterpart of Modelo 130: an activity
# in estimación directa files Modelo 130, never Modelo 131. A legal
# entity never files Modelo 131. Research §2.1.
Modelo.M131: ModeloApplicabilityRule(
modelo=Modelo.M131,
applicable_entity_types=_NATURAL_PERSON,
required_income_categories=frozenset({IrpfIncomeCategory.ACTIVIDAD_ECONOMICA}),
required_estimation_regimes=frozenset({IrpfEstimationRegime.OBJETIVA}),
applicable_reason=(
"Modelo 131 (pago fraccionado del IRPF): la persona física "
"declara rendimientos de actividades económicas en estimación "
"objetiva (módulos), que generan la obligación del pago "
"fraccionado por ese método."
),
not_applicable_reason=(
"Modelo 131 no aplica: el pago fraccionado en estimación "
"objetiva solo corresponde a la persona física cuya actividad "
"económica se determina por el método de módulos. Una "
"actividad en estimación directa presenta el Modelo 130."
),
# Modelo 131 is an IRPF pago-fraccionado cuota self-assessment:
# an attribution entity asked about it gets the pass-through
# verdict.
cuota_bearing=True,
# RD 439/2007 art. 110 — pago fraccionado del IRPF, importe y
# cálculo; Orden EHA/672/2007 art. 3 — aprobación del Modelo 131;
# LIRPF art. 99 — pagos fraccionados como pagos a cuenta del IRPF.
legal_refs=(
"rd-439-2007:art-110",
"orden-eha-672-2007:art-3",
"ley-35-2006:art-99",
),
),
# Modelo 111 — autoliquidación de retenciones e ingresos a cuenta del
# IRPF (rendimientos del trabajo / actividades profesionales). It is
# the PAYER's obligation: a taxpayer — a natural person with actividad
# económica, a legal entity, or an attribution entity — who pays
# salaries or withholding-subject professional fees. Whether the
# taxpayer pays such income is a payer fact the three-axis model
# cannot decide on its own; a profile that does not positively
# declare it yields INCOMPLETE rather than a guessed NOT_APPLICABLE.
# Research §1.1.
Modelo.M111: ModeloApplicabilityRule(
modelo=Modelo.M111,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_WITHHELD_INCOME,
applicable_reason=(
"Modelo 111 (retenciones e ingresos a cuenta del IRPF): el "
"contribuyente paga rendimientos del trabajo o de actividades "
"profesionales sujetos a retención y autoliquida las "
"retenciones practicadas."
),
not_applicable_reason=(
"Modelo 111 no aplica: la autoliquidación de retenciones del "
"IRPF solo corresponde a quien paga rendimientos sujetos a "
"retención."
),
# LIRPF art. 99 — obligación de practicar retenciones e ingresos a
# cuenta; RD 439/2007 art. 108 — declaración e ingreso de las
# retenciones (Modelo 111); Orden EHA/586/2011 art. 1 — aprobación
# del Modelo 111.
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-108",
"orden-eha-586-2011:art-1",
),
),
# Modelo 123 - autoliquidacion de retenciones e ingresos a cuenta
# sobre determinados rendimientos del capital mobiliario. This is a
# payer-side withholding obligation, so applicability follows the
# declared capital-income withholding payer fact rather than the
# recipient's IRPF income categories.
Modelo.M123: ModeloApplicabilityRule(
modelo=Modelo.M123,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_CAPITAL_INCOME_WITH_RETENCION,
applicable_reason=(
"Modelo 123 (retenciones sobre determinados rendimientos del "
"capital mobiliario): el contribuyente satisface rendimientos "
"del capital mobiliario o determinadas rentas sujetas a retencion "
"y autoliquida las retenciones practicadas."
),
not_applicable_reason=(
"Modelo 123 no aplica: solo corresponde a quien satisface "
"determinados rendimientos o rentas del capital mobiliario "
"sujetos a retencion."
),
legal_refs=(
"ley-35-2006:art-25",
"ley-35-2006:art-99",
"orden-eha-3435-2007:anexo-ii",
"orden-hac-56-2024:art-1",
"rd-439-2007:art-108",
"rd-439-2007:art-90",
"ley-35-2006:art-101",
),
),
# Modelo 193 - resumen anual de las retenciones declaradas through
# Modelo 123 for determinados rendimientos del capital mobiliario.
# Annual companion; gated on the same payer-side capital-income
# withholding fact as Modelo 123.
Modelo.M193: ModeloApplicabilityRule(
modelo=Modelo.M193,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_CAPITAL_INCOME_WITH_RETENCION,
applicable_reason=(
"Modelo 193 (resumen anual de retenciones sobre capital mobiliario): "
"el contribuyente satisface determinados rendimientos o rentas del "
"capital mobiliario sujetos a retencion y presenta el resumen anual "
"de las retenciones declaradas."
),
not_applicable_reason=(
"Modelo 193 no aplica: el resumen anual solo corresponde a quien "
"satisface determinados rendimientos o rentas del capital mobiliario "
"sujetos a retencion."
),
legal_refs=(
"ley-35-2006:art-25",
"ley-35-2006:art-99",
"orden-eha-3377-2011:art-1",
"rd-439-2007:art-108",
"rd-439-2007:art-90",
"ley-35-2006:art-101",
"ley-58-2003:art-93",
),
),
# Modelo 322 - IVA grupo de entidades, modelo individual. Filed by
# taxable persons that are member entities in the special IVA group
# regime. This is role-gated profile state, not a generic SII flag.
Modelo.M322: ModeloApplicabilityRule(
modelo=Modelo.M322,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.IVA_GROUP_MEMBER,
applicable_reason=(
"Modelo 322 (IVA grupo de entidades, modelo individual): el "
"contribuyente esta inscrito como entidad miembro de un grupo "
"de IVA y presenta la autoliquidacion mensual individual."
),
not_applicable_reason=(
"Modelo 322 no aplica: solo corresponde a entidades miembro "
"de un grupo de IVA que hayan optado por el regimen especial "
"del grupo de entidades."
),
legal_refs=(
"orden-eha-3434-2007:art-1",
"orden-eha-3434-2007:art-8",
"rd-1624-1992:art-71",
),
),
# Modelo 353 - IVA grupo de entidades, modelo agregado. Filed by
# the dominant entity of the group and grounded separately from the
# member-level Modelo 322 role.
Modelo.M353: ModeloApplicabilityRule(
modelo=Modelo.M353,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.IVA_GROUP_DOMINANT_ENTITY,
applicable_reason=(
"Modelo 353 (IVA grupo de entidades, modelo agregado): el "
"contribuyente esta inscrito como entidad dominante de un "
"grupo de IVA y presenta la autoliquidacion mensual agregada."
),
not_applicable_reason=(
"Modelo 353 no aplica: solo corresponde a la entidad dominante "
"de un grupo de IVA que agrega las autoliquidaciones "
"individuales de las entidades del grupo."
),
legal_refs=(
"orden-eha-3434-2007:art-2",
"orden-eha-3434-2007:art-8",
"rd-1624-1992:art-71",
),
),
# Modelo 369 — autoliquidación de los regímenes especiales de ventanilla
# única (OSS/IOSS) del IVA. Filed by a taxable person enrolled in the
# one-stop-shop Union / non-Union / import regime whose Member State of
# identification is Spain. Enrolment-gated profile state (iva.oss_enrolled),
# not a generic IVA-regime flag: OSS enrolment is an explicit opt-in.
Modelo.M369: ModeloApplicabilityRule(
modelo=Modelo.M369,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.OSS_ENROLLED,
applicable_reason=(
"Modelo 369 (ventanilla única OSS/IOSS): el contribuyente esta "
"inscrito en un regimen especial de ventanilla unica del IVA con "
"Estado miembro de identificacion España y presenta la "
"autoliquidacion periodica de las operaciones acogidas al regimen."
),
not_applicable_reason=(
"Modelo 369 no aplica: solo corresponde a quien esta inscrito en "
"un regimen especial de ventanilla unica (OSS/IOSS) del IVA con "
"Estado miembro de identificacion España."
),
legal_refs=(
"orden-hac-610-2021:art-1",
"orden-hac-610-2021:art-2",
"ley-37-1992:art-163-octiesdecies",
"ley-37-1992:art-163-unvicies",
"ley-37-1992:art-163-quinvicies",
),
),
# Modelo 194 — resumen anual de retenciones e ingresos a cuenta sobre
# rendimientos del capital mobiliario y transmisión/amortización de activos.
# Payer's obligation, gated on the capital-income withholding payer fact.
Modelo.M194: ModeloApplicabilityRule(
modelo=Modelo.M194,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_CAPITAL_INCOME_WITH_RETENCION,
applicable_reason=(
"Modelo 194 (resumen anual de retenciones sobre capital mobiliario): "
"el contribuyente satisface rendimientos del capital mobiliario o "
"rentas de transmisión/amortización de activos sujetos a retención y "
"presenta el resumen anual de las retenciones practicadas."
),
not_applicable_reason=(
"Modelo 194 no aplica: el resumen anual de retenciones sobre capital "
"mobiliario solo corresponde a quien satisface tales rendimientos "
"sujetos a retención."
),
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-108",
"orden-eha-3377-2011:art-1",
),
),
# Modelo 188 - resumen anual de retenciones sobre operaciones de
# capitalizacion y contratos de seguro de vida o invalidez (capital
# mobiliario). Same payer fact as Modelo 194.
Modelo.M188: ModeloApplicabilityRule(
modelo=Modelo.M188,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_CAPITAL_INCOME_WITH_RETENCION,
applicable_reason=(
"Modelo 188 (resumen anual de retenciones sobre capitalizacion y "
"seguros de vida): el contribuyente satisface rendimientos del "
"capital mobiliario de operaciones de capitalizacion o seguros "
"sujetos a retencion y presenta el resumen anual."
),
not_applicable_reason=(
"Modelo 188 no aplica: solo corresponde a quien satisface "
"rendimientos de capitalizacion o seguros sujetos a retencion."
),
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-108",
"orden-eha-3377-2011:art-1",
),
),
# Modelo 187 - acciones/participaciones de IIC y resumen anual de
# retenciones sobre las ganancias patrimoniales derivadas. Payer's
# obligation, gated on the capital-income withholding payer fact.
Modelo.M187: ModeloApplicabilityRule(
modelo=Modelo.M187,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_CAPITAL_INCOME_WITH_RETENCION,
applicable_reason=(
"Modelo 187 (acciones y participaciones de IIC, resumen anual de "
"retenciones): el contribuyente satisface rentas o ganancias de IIC "
"sujetas a retencion y presenta el resumen anual."
),
not_applicable_reason=(
"Modelo 187 no aplica: solo corresponde a quien satisface rentas o ganancias de IIC sujetas a retencion."
),
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-108",
"orden-eha-3377-2011:art-1",
),
),
# Modelo 126 - autoliquidacion de retenciones sobre rendimientos del capital
# mobiliario de cuentas y depositos en instituciones financieras. Payer
# withholding obligation, gated on the capital-income withholding payer fact.
Modelo.M126: ModeloApplicabilityRule(
modelo=Modelo.M126,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_CAPITAL_INCOME_WITH_RETENCION,
applicable_reason=(
"Modelo 126 (retenciones sobre rendimientos del capital mobiliario de "
"cuentas y depositos): el contribuyente satisface rendimientos de "
"cuentas o depositos sujetos a retencion y autoliquida las retenciones."
),
not_applicable_reason=(
"Modelo 126 no aplica: solo corresponde a quien satisface rendimientos "
"de cuentas o depositos en instituciones financieras sujetos a retencion."
),
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-108",
"orden-eha-3435-2007:anexo-ii",
),
),
# Modelo 128 - autoliquidacion de retenciones sobre rentas de capital
# mobiliario de operaciones de capitalizacion y contratos de seguro de vida
# o invalidez. Same payer fact.
Modelo.M128: ModeloApplicabilityRule(
modelo=Modelo.M128,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_CAPITAL_INCOME_WITH_RETENCION,
applicable_reason=(
"Modelo 128 (retenciones sobre rentas de capitalizacion y seguros de "
"vida): el contribuyente satisface rentas de operaciones de "
"capitalizacion o seguros sujetas a retencion y autoliquida las "
"retenciones."
),
not_applicable_reason=(
"Modelo 128 no aplica: solo corresponde a quien satisface rentas de "
"capitalizacion o seguros de vida o invalidez sujetas a retencion."
),
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-108",
"orden-eha-3435-2007:anexo-ii",
),
),
# Modelo 117 - autoliquidacion de retenciones e ingresos a cuenta sobre
# rentas o ganancias por transmision o reembolso de acciones y
# participaciones de IIC. Payer withholding obligation.
Modelo.M117: ModeloApplicabilityRule(
modelo=Modelo.M117,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_CAPITAL_INCOME_WITH_RETENCION,
applicable_reason=(
"Modelo 117 (retenciones sobre transmision o reembolso de acciones y "
"participaciones de IIC): el contribuyente satisface rentas o ganancias "
"de IIC sujetas a retencion y autoliquida las retenciones."
),
not_applicable_reason=(
"Modelo 117 no aplica: solo corresponde a quien satisface rentas o "
"ganancias por transmision o reembolso de participaciones de IIC "
"sujetas a retencion."
),
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-108",
"orden-eha-3435-2007:anexo-ii",
),
),
# Modelo 115 — autoliquidación de retenciones por arrendamiento de
# inmuebles urbanos. The PAYER's obligation: a natural person, legal
# entity, or attribution entity who pays rent subject to retención.
# Whether the taxpayer pays such rent is a payer fact the three-axis
# model cannot decide alone; an undeclared fact yields INCOMPLETE.
Modelo.M115: ModeloApplicabilityRule(
modelo=Modelo.M115,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_RENT_WITH_RETENCION,
applicable_reason=(
"Modelo 115 (retenciones por arrendamiento de inmuebles "
"urbanos): el contribuyente paga alquiler de inmueble urbano "
"sujeto a retención y autoliquida las retenciones practicadas."
),
not_applicable_reason=(
"Modelo 115 no aplica: la autoliquidación de retenciones por "
"arrendamiento solo corresponde a quien paga alquileres "
"sujetos a retención."
),
# LIRPF art. 99 — obligación de practicar retenciones; RD 439/2007
# art. 100 — retención sobre rendimientos del arrendamiento de
# inmuebles urbanos; RD 439/2007 art. 108 — declaración e ingreso
# de las retenciones (Modelo 115).
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-100",
"rd-439-2007:art-108",
),
),
# Modelo 190 — resumen anual de retenciones e ingresos a cuenta del
# IRPF sobre rendimientos del trabajo y de actividades económicas. The
# annual companion to Modelo 111: a taxpayer who files Modelo 111
# files Modelo 190. Gated on the same payer fact as Modelo 111.
Modelo.M190: ModeloApplicabilityRule(
modelo=Modelo.M190,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_WITHHELD_INCOME,
applicable_reason=(
"Modelo 190 (resumen anual de retenciones del IRPF): el "
"contribuyente que paga rendimientos del trabajo o de "
"actividades profesionales sujetos a retención presenta el "
"resumen anual de las retenciones declaradas en el Modelo 111."
),
not_applicable_reason=(
"Modelo 190 no aplica: el resumen anual de retenciones del "
"IRPF solo corresponde a quien paga rendimientos sujetos a "
"retención."
),
# LIRPF art. 99 — obligación de retener; RD 439/2007 art. 108 —
# declaración trimestral/mensual y resumen anual de las retenciones
# e ingresos a cuenta.
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-108",
),
),
# Modelo 180 — resumen anual de retenciones e ingresos a cuenta del
# IRPF sobre rendimientos del arrendamiento de inmuebles urbanos. The
# annual companion to Modelo 115: gated on the same payer fact.
Modelo.M180: ModeloApplicabilityRule(
modelo=Modelo.M180,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.PAYS_RENT_WITH_RETENCION,
applicable_reason=(
"Modelo 180 (resumen anual de retenciones por arrendamiento): "
"el contribuyente que paga alquiler de inmueble urbano sujeto "
"a retención presenta el resumen anual de las retenciones "
"declaradas en el Modelo 115."
),
not_applicable_reason=(
"Modelo 180 no aplica: el resumen anual de retenciones por "
"arrendamiento solo corresponde a quien paga alquileres "
"sujetos a retención."
),
# LIRPF art. 99 — obligación de retener; RD 439/2007 art. 100 —
# retención sobre el arrendamiento de inmuebles urbanos; RD
# 439/2007 art. 108 — declaración trimestral/mensual y resumen
# anual de las retenciones e ingresos a cuenta.
legal_refs=(
"ley-35-2006:art-99",
"rd-439-2007:art-100",
"rd-439-2007:art-108",
),
),
# Modelo 349 — declaración recapitulativa de operaciones
# intracomunitarias. Applies to a taxpayer — a natural person with
# actividad económica, a legal entity, or an attribution entity — who
# performs operaciones intracomunitarias. Whether the taxpayer trades
# intracommunity is a payer fact the three-axis model cannot decide
# alone; an undeclared fact yields INCOMPLETE. Research §3.3.
Modelo.M349: ModeloApplicabilityRule(
modelo=Modelo.M349,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.TRADES_INTRACOMMUNITY,
applicable_reason=(
"Modelo 349 (declaración recapitulativa de operaciones "
"intracomunitarias): el contribuyente realiza operaciones "
"intracomunitarias y presenta su declaración recapitulativa."
),
not_applicable_reason=(
"Modelo 349 no aplica: la declaración recapitulativa solo "
"corresponde a quien realiza operaciones intracomunitarias."
),
# Orden EHA/769/2010 art. 1 — aprobación del Modelo 349; Orden
# HAC/174/2020 art. 1 — modificación del Modelo 349; RD
# 1624/1992 art. 79 — obligados a la declaración recapitulativa;
# LGT art. 93 — obligación de información.
legal_refs=(
"orden-eha-769-2010:art-1",
"orden-hac-174-2020:art-1",
"rd-1624-1992:art-79",
"ley-58-2003:art-93",
),
),
# Modelo 347 — declaración anual de operaciones con terceras personas.
# Applies to a natural person, legal entity, or attribution entity
# whose third-party transactions exceeded the declaration threshold.
# Whether the threshold is exceeded is a payer fact the three-axis
# model cannot decide alone; an undeclared fact yields INCOMPLETE.
Modelo.M347: ModeloApplicabilityRule(
modelo=Modelo.M347,
applicable_entity_types=_PAYER_FACT_ENTITY_TYPES,
required_payer_fact=PayerFact.EXCEEDS_THIRD_PARTY_THRESHOLD,
applicable_reason=(
"Modelo 347 (declaración anual de operaciones con terceras "
"personas): las operaciones del contribuyente con un tercero "
"superan el umbral de declaración y debe presentar la "
"declaración informativa anual."
),
not_applicable_reason=(
"Modelo 347 no aplica: la declaración de operaciones con "
"terceros solo corresponde a quien supera el umbral de "
"operaciones declarable."
),
# RD 1065/2007 art. 31 — obligados a informar sobre operaciones
# con terceros; Orden EHA/3012/2008 art. 1 — aprobación del
# Modelo 347 y obligados a presentarlo; Orden EHA/3012/2008 art.
# 10 — contenido de la declaración; LGT art. 93 — obligación de
# información sobre operaciones con terceros.
legal_refs=(
"rd-1065-2007:art-31",
"orden-eha-3012-2008:art-1",
"orden-eha-3012-2008:art-10",
"ley-58-2003:art-93",
),
),
# Modelo 390 — declaración-resumen anual del IVA. The annual companion
# to Modelo 303: a taxpayer in a periodic IVA self-assessment regime
# files it. A natural person must also declare actividad económica;
# legal and attribution entities do not carry the IRPF income-category
# axis, so their gate is entity type plus IVA regime. Same
# applicability gate as Modelo 303. (SII filers are exempt from Modelo
# 390; that suppression is a deferred expansion gated on the SII
# enrolment axis — research §3.1.)
Modelo.M390: ModeloApplicabilityRule(
modelo=Modelo.M390,
applicable_entity_types=_IVA_OBLIGED_ENTITY_TYPES,
required_income_categories=frozenset({IrpfIncomeCategory.ACTIVIDAD_ECONOMICA}),
applicable_iva_regimes=_IVA_SELF_ASSESSMENT_REGIMES,
applicable_reason=(
"Modelo 390 (resumen anual del IVA): el contribuyente realiza "
"una actividad económica sujeta al IVA y presenta la "
"declaración-resumen anual del impuesto."
),
not_applicable_reason=(
"Modelo 390 no aplica: sin una actividad económica sujeta al "
"IVA no hay declaración-resumen anual del impuesto."
),
# RD 1624/1992 art. 71 — declaraciones-liquidaciones del IVA y la
# declaración-resumen anual; Orden EHA/3111/2009 art. 1 —
# aprobación del Modelo 390.
legal_refs=(
"rd-1624-1992:art-71",
"orden-eha-3111-2009:art-1",
),
),
# Modelo 303 — autoliquidación periódica del IVA. Triggered by carrying
# on an actividad económica subject to IVA: a natural person with
# rendimientos de actividades económicas, or a legal / attribution
# entity in a periodic IVA self-assessment regime. A pure landlord of
# residential property, a salaried-only taxpayer, and a pensioner carry
# on no IVA-subject activity. (Commercial rental can be IVA-subject;
# the seed gates natural persons on the actividad-económica category,
# which a pure landlord does not declare. Finer rental-IVA nuance is a
# deferred expansion.)
Modelo.M303: ModeloApplicabilityRule(
modelo=Modelo.M303,
applicable_entity_types=_IVA_OBLIGED_ENTITY_TYPES,
required_income_categories=frozenset({IrpfIncomeCategory.ACTIVIDAD_ECONOMICA}),
applicable_iva_regimes=_IVA_SELF_ASSESSMENT_REGIMES,
applicable_reason=(
"Modelo 303 (autoliquidación del IVA): el contribuyente "
"realiza una actividad económica sujeta al IVA y presenta la "
"autoliquidación periódica."
),
not_applicable_reason=(
"Modelo 303 no aplica: sin una actividad económica sujeta al "
"IVA no hay autoliquidación periódica del impuesto."
),
# LIVA art. 99 — ejercicio del derecho a la deducción mediante
# las declaraciones-liquidaciones periódicas del IVA que liquida
# el Modelo 303.
legal_refs=("ley-37-1992:art-99",),
),
# Modelo 200 — autoliquidación anual del Impuesto sobre Sociedades.
# Applies, in general, to every IS contribuyente — a legal entity with
# personalidad jurídica. It does NOT apply to a natural person, who
# files the Renta (Modelo 100). Research §1.2.
Modelo.M200: ModeloApplicabilityRule(
modelo=Modelo.M200,
applicable_entity_types=_LEGAL_ENTITY,
required_income_categories=frozenset(),
applicable_fiscal_residencies=frozenset({FiscalResidency.RESIDENT_IRPF}),
applicable_reason=(
"Modelo 200 (Impuesto sobre Sociedades): una entidad jurídica "
"con personalidad jurídica es contribuyente del IS y presenta "
"la autoliquidación anual."
),
not_applicable_reason=(
"Modelo 200 no aplica: la autoliquidación del Impuesto sobre "
"Sociedades local corresponde a entidades jurídicas "
"contribuyentes del IS en la ruta residente. Un perfil "
"NON_RESIDENT_IRNR sin eje modelado de establecimiento permanente "
"en España no puede tratarse como listo para Modelo 200; use la "
"ruta IRNR/Modelo 210 por AEAT Sede cuando actúe sin "
"establecimiento permanente."
),
# Modelo 200 is the IS cuota self-assessment: an attribution
# entity asked about it gets the pass-through verdict — it runs
# no IS cuota of its own.
cuota_bearing=True,
# LIS art. 124 — obligación de presentar la declaración del
# Impuesto sobre Sociedades, que el Modelo 200 liquida. TRLIRNR
# art. 2 / 24 ground the non-resident/no-permanent-establishment
# exclusion until a Spanish-PE profile axis is modelled.
legal_refs=(
"ley-27-2014:art-124",
"trlirnr-rdleg-5-2004:art-2",
"trlirnr-rdleg-5-2004:art-24",
),
),
# Modelo 202 — pago fraccionado del Impuesto sobre Sociedades. Filed by
# IS contribuyentes in April / October / December. A natural person
# never files Modelo 202. Research §1.2.
Modelo.M202: ModeloApplicabilityRule(
modelo=Modelo.M202,
applicable_entity_types=_LEGAL_ENTITY,
required_income_categories=frozenset(),
applicable_fiscal_residencies=frozenset({FiscalResidency.RESIDENT_IRPF}),
applicable_reason=(
"Modelo 202 (pago fraccionado del IS): una entidad jurídica "
"contribuyente del Impuesto sobre Sociedades presenta los "
"pagos fraccionados de abril, octubre y diciembre."
),
not_applicable_reason=(
"Modelo 202 no aplica: el pago fraccionado del Impuesto sobre "
"Sociedades local solo corresponde a entidades jurídicas en la "
"ruta residente IS. Un perfil NON_RESIDENT_IRNR sin eje modelado "
"de establecimiento permanente en España no puede tratarse como "
"listo para pagos fraccionados del IS."
),
# Modelo 202 is an IS pago-fraccionado cuota self-assessment:
# an attribution entity asked about it gets the pass-through
# verdict.
cuota_bearing=True,
# LIS art. 40 — pago fraccionado del Impuesto sobre Sociedades,
# las modalidades y el calendario de abril, octubre y diciembre
# que liquida el Modelo 202.
legal_refs=(
"ley-27-2014:art-40",
"trlirnr-rdleg-5-2004:art-2",
),
),
# Modelo 184 — declaración informativa anual de Entidades en
# régimen de atribución de rentas. This is the attribution entity's
# OWN obligation — informational, not a cuota self-assessment (the
# substantive tax is each member's). It applies ONLY to an
# attribution entity; a natural person and a legal entity never
# file it. Modelo 184 is not cuota-bearing: a non-attribution
# entity asked about it gets a plain NOT_APPLICABLE, never a
# pass-through verdict. Corporate-entity ADR §2; research §1.3.
Modelo.M184: ModeloApplicabilityRule(
modelo=Modelo.M184,
applicable_entity_types=_ATTRIBUTION_ENTITY,
required_income_categories=frozenset(),
applicable_reason=(
"Modelo 184 (declaración informativa de entidades en régimen "
"de atribución de rentas): la entidad declara las rentas "
"obtenidas y las atribuibles a cada socio, comunero o "
"partícipe en el ejercicio. Es la obligación propia de la "
"entidad; la tributación de la renta corresponde a cada "
"miembro."
),
not_applicable_reason=(
"Modelo 184 no aplica: la declaración informativa de "
"atribución de rentas solo corresponde a las entidades en "
"régimen de atribución de rentas (comunidades de bienes, "
"sociedades civiles sin objeto mercantil). El tipo de "
"contribuyente declarado no es una entidad de esta clase."
),
cuota_bearing=False,
# Orden HAP/2250/2015 arts. 1-2 — aprobación del Modelo 184 y
# obligados a presentarlo (entidades en régimen de atribución de
# rentas; exención por debajo de 3.000 € sin actividad
# económica); art. 4 — plazo de presentación (mes de febrero).
legal_refs=(
"orden-hap-2250-2015:art-1",
"orden-hap-2250-2015:art-2",
"orden-hap-2250-2015:art-4",
),
),
# Modelo 721 — declaracion informativa sobre monedas virtuales situadas
# en el extranjero. The operative obligation lives in DA 18 LGT as
# amended by Ley 11/2021 DA 10a; the form is approved by Orden
# HFP/886/2023. It applies only when virtual currencies abroad exceed
# the declaration threshold. That is a crypto-specific threshold fact,
# distinct from Modelo 720's bienes/derechos extranjero fact.
Modelo.M721: ModeloApplicabilityRule(
modelo=Modelo.M721,
applicable_entity_types=frozenset({EntityType.NATURAL_PERSON, EntityType.LEGAL_ENTITY}),
required_income_categories=frozenset(),
required_payer_fact=PayerFact.MONEDAS_VIRTUALES_EXTRANJERO_ABOVE_THRESHOLD,
applicable_reason=(
"Modelo 721 (declaracion informativa sobre monedas virtuales en "
"el extranjero): el contribuyente que posee monedas virtuales "
"situadas en el extranjero con valor agregado superior a 50.000 "
"EUR el 31 de diciembre esta obligado a presentar esta declaracion "
"informativa anual. La obligacion operativa esta en la DA 18 de "
"la LGT, introducida por la Ley 11/2021 DA 10a, y el formulario "
"esta aprobado por Orden HFP/886/2023. Nota: la "
"aplicacion no ha implementado aun el calculo completo del Modelo "
"721; utilice la Sede Electronica de la AEAT para presentarlo."
),
not_applicable_reason=(
"Modelo 721 no aplica: la declaracion informativa sobre monedas "
"virtuales en el extranjero solo corresponde a personas fisicas o "
"entidades juridicas. El tipo de contribuyente declarado no esta "
"incluido en el ambito subjetivo de la Ley 11/2021 DA 10a."
),
cuota_bearing=False,
# LGT DA 18 letra d — operative obligation; RD 1065/2007 Art. 42
# quater — threshold and reglamento base; Orden HFP/886/2023
# arts. 1-3 — approved form, obligados and content.
legal_refs=(
"ley-58-2003:da-18",
"rd-1065-2007:art-42-quater",
"orden-hfp-886-2023:art-1",
"orden-hfp-886-2023:art-2",
"orden-hfp-886-2023:art-3",
),
),
# Modelo 720 — declaración informativa sobre bienes y derechos situados
# en el extranjero. Applies to any natural person or legal entity who
# holds foreign assets above the declaration threshold as of 31 December
# (Ley 7/2012 DA 1ª introducing DA 18ª Ley 58/2003 LGT; Orden
# HAP/72/2013). The threshold is whether the aggregate value exceeds
# the applicable limit — a payer-fact the three-axis model cannot
# resolve alone; a profile that does not positively declare
# ``bienes_extranjero_above_threshold = True`` yields INCOMPLETE rather
# than a guessed NOT_APPLICABLE.
#
# IMPORTANT: the IRPF Art. 93 special regime (impatriados / Beckham)
# exempts the taxpayer from Modelo 720 for the duration of the regime.
# An impatriado is taxed as a non-resident (IRNR) and does not owe the
# obligations reserved for IRPF residents. This exemption is enforced by
# the pre-check in :func:`derive_modelo_applicability` before this rule
# is evaluated.
Modelo.M720: ModeloApplicabilityRule(
modelo=Modelo.M720,
applicable_entity_types=frozenset({EntityType.NATURAL_PERSON, EntityType.LEGAL_ENTITY}),
required_payer_fact=PayerFact.BIENES_EXTRANJERO_ABOVE_THRESHOLD,
applicable_reason=(
"Modelo 720 (declaración informativa sobre bienes y derechos en "
"el extranjero): el contribuyente posee bienes o derechos situados "
"en el extranjero con valor agregado superior al umbral declarable "
"y está obligado a presentar esta declaración informativa anual. "
"La obligación se estableció por la Ley 7/2012 DA 1ª."
),
not_applicable_reason=(
"Modelo 720 no aplica: la declaración informativa sobre bienes en "
"el extranjero solo corresponde a personas físicas o entidades "
"jurídicas. El tipo de contribuyente declarado no está incluido en "
"el ámbito subjetivo de la DA 18ª Ley 58/2003 LGT."
),
cuota_bearing=False,
# Ley 7/2012 DA 1ª — obligación de declarar bienes y derechos en el
# extranjero (introducing DA 18ª Ley 58/2003 LGT); Orden HAP/72/2013
# Art. 1 — aprobación del Modelo 720 y obligados a presentarlo.
legal_refs=(
"ley-7-2012:da-1",
"orden-hap-72-2013:art-1",
),
),
}
"""Seed modelo-applicability rules — core persona coverage.
A modelo absent from this table has no derived rule yet: its
applicability is reported :attr:`ApplicabilityVerdict.INCOMPLETE` with
a rationale pointing at the deferred expansion. See
:data:`_SEED_COVERAGE_NOTICE`.
"""
[docs]
def has_applicability_rule(modelo: str) -> bool:
"""Return whether a seed applicability rule exists for ``modelo``."""
return modelo in _MODELO_APPLICABILITY_RULES
[docs]
def iter_modelo_applicability_rules() -> tuple[ModeloApplicabilityRule, ...]:
"""Return the registry-owned seed :class:`ModeloApplicabilityRule` instances.
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 tuple(_MODELO_APPLICABILITY_RULES[modelo] for modelo in sorted(_MODELO_APPLICABILITY_RULES))
[docs]
def taxpayer_model_is_declared(profile: TaxpayerProfile) -> bool:
"""Return whether the profile carries a usable taxpayer model.
The taxpayer model is "declared" when the operator has set an
``entity_type`` and — for a natural person — at least one IRPF
income category. Without these, modelo applicability cannot be
derived: the engine must report ``INCOMPLETE`` rather than assume
autónomo. A legal / attribution entity needs no income category;
the ``entity_type`` alone selects its tax.
Args:
profile: The :class:`TaxpayerProfile` to inspect.
"""
if profile.entity_type is None:
return False
if profile.entity_type is EntityType.NATURAL_PERSON:
return bool(profile.irpf_income_categories)
return True
[docs]
def derive_tax_route(profile: TaxpayerProfile) -> TaxRoute:
"""Return the tax branch ``profile`` routes to — corporate-entity ADR §4.
The routing contract: the ``entity_type`` axis 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 undeclared ``entity_type`` yields :attr:`TaxRoute.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.
Args:
profile: The :class:`TaxpayerProfile` whose ``entity_type``
axis selects the tax branch.
Returns:
The :class:`TaxRoute` branch the profile's ``entity_type``
selects, or :attr:`TaxRoute.INCOMPLETE` when ``entity_type``
is undeclared.
"""
if profile.entity_type is None:
return TaxRoute.INCOMPLETE
return _TAX_ROUTE_FOR_ENTITY_TYPE[profile.entity_type]
[docs]
def derive_modelo_applicability(
profile: TaxpayerProfile,
modelo: str,
*,
today: date | None = None,
) -> ModeloApplicability:
"""Derive a modelo's applicability from the taxpayer model.
The verdict is DERIVED from the three-axis
:class:`~domain.deadlines.TaxpayerProfile` model — never
assumed. An undeclared taxpayer model yields an explicit
:attr:`ApplicabilityVerdict.INCOMPLETE` answer; 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 ``INCOMPLETE`` so the operator is never told
a confident yes/no the registry rules cannot yet justify; the
rationale points at the deferred expansion.
Args:
profile: The operator's three-axis taxpayer model.
modelo: The AEAT modelo identifier to decide.
today: Reference date for the Beckham window check. Defaults to
``date.today()`` when ``None``. Pass an explicit date in tests
so results are deterministic.
Returns:
The :class:`ModeloApplicability` for ``modelo`` and ``profile``.
"""
_today = today if today is not None else date.today()
beckham_window_active = profile.beckham_window_active(_today)
# The Art. 93 impatriado route is a modelo-level switch while the
# six-year Beckham window is active: the annual declaration is Modelo
# 151, and the ordinary Renta self-assessment (Modelo 100) is not the
# filing route. Once the window expires, both modelos fall back to their
# ordinary applicability rules: M100 through the seed table below, M151
# to a positive NOT_APPLICABLE.
if beckham_window_active and modelo == Modelo.M100:
return ModeloApplicability(
modelo=Modelo.M100,
verdict=ApplicabilityVerdict.NOT_APPLICABLE,
reason=_IMPATRIADO_M100_SUPPRESSED_REASON,
legal_refs=_IMPATRIADO_M151_ROUTE_LEGAL_REFS,
)
if modelo == Modelo.M151:
return ModeloApplicability(
modelo=Modelo.M151,
verdict=(ApplicabilityVerdict.APPLICABLE if beckham_window_active else ApplicabilityVerdict.NOT_APPLICABLE),
reason=(
_IMPATRIADO_M151_APPLICABLE_REASON if beckham_window_active else _IMPATRIADO_M151_NOT_APPLICABLE_REASON
),
legal_refs=_IMPATRIADO_M151_ROUTE_LEGAL_REFS,
)
# An impatriado (LIRPF Art. 93 special regime) is taxed as a non-resident
# for the duration of the six-year Beckham window (RIRPF Art. 116.1) and
# is therefore exempt from IRPF-resident obligations. Modelo 720 (bienes
# en el extranjero) is one of those obligations: it applies to IRPF
# residents, not to non-resident taxpayers under Art. 93. Enforce the
# exemption before the rule table so the payer-fact gate is never reached.
# Year-7+ filers whose window has expired revert to the general IRPF
# regime and owe M720 again — the window-expiry check is wired here.
if modelo == Modelo.M720 and beckham_window_active:
return ModeloApplicability(
modelo=Modelo.M720,
verdict=ApplicabilityVerdict.NOT_APPLICABLE,
reason=_IMPATRIADO_M720_EXEMPT_REASON,
legal_refs=_IMPATRIADO_M720_LEGAL_REFS,
)
rule = _MODELO_APPLICABILITY_RULES.get(modelo)
if rule is None:
return _incomplete_applicability(modelo, unruled=True)
return rule.evaluate(profile)
__all__ = [
"ApplicabilityVerdict",
"Modelo202Modality",
"Modelo202ModalityVerdict",
"ModeloApplicability",
"ModeloApplicabilityRule",
"PayerFact",
"TaxRoute",
"derive_modelo_202_modality",
"derive_modelo_applicability",
"derive_tax_route",
"has_applicability_rule",
"iter_modelo_applicability_rules",
"modelo_202_modality_from_inputs",
"taxpayer_model_is_declared",
]