aeat.domain.calculations.registry._formula_runtime_m131 module¶
M131 módulos formula-op evaluators for the registry runtime.
Extracted from _formula_runtime to keep
that dispatcher under its size budget while preserving the existing registry op
names. Dispatch still lives in _formula_runtime; this module owns the
Modelo 131 estimación-objetiva módulos Fase 1ª-3ª evaluators and advisory flag
helpers.
See also
_formula_runtimeCentral formula dispatcher that routes M131 operation names here.
_formula_runtime_opsShared numeric-casilla, parameter, and arithmetic helpers used by these evaluators.
FormulaExpressionRegistry-authored operation graph consumed by each evaluator.
ParameterDefinitionKeyed-bracket and scalar parameter rows that carry the módulo tables and index rates.
calculate_registry_snapshot()Public calculation entry point that records these evaluator results in registry calculation provenance.
VerificationPredicateDefinitionAdvisory predicates that surface untabled or conflicting M131 módulo results instead of allowing silent zeros.
- evaluate_m131_resolve_modulos_previo(expression, ctx)[source]¶
Resolve the M131/M100 estimación-objetiva Fase 1ª rendimiento neto previo.
LIRPF art. 31 + the annual Orden de módulos (Anexo II) fix the mechanism: rendimiento neto previo = Σ(unidades_módulo × rendimiento anual por unidad antes de amortización), per IAE epígrafe. This op reads the operator- declared IAE epígrafe (a text casilla) and up to seven módulo unit-count casillas (the highest signo count among the tabled activities), looks up each módulo’s coefficient in the registry-declared
ParameterDefinition(data_type='keyed_bracket_table', key"<epígrafe>:<módulo>"), and sums the per-módulo products.An untabled epígrafe (bounded first-slice per the
2026-07-01-modelo-131-eo-modulos-engine-adr) or a blank epígrafe resolves toDecimal('0')— this op feeds an internal-only advisory-support casilla, never the filed casilla 01 directly, so a zero here means “the table-driven engine has no coverage for this activity”, not “the rendimiento is zero”. Theadvisory_when_computed_divergesverification predicate surfaces the gap or the discrepancy to the operator; it never silently substitutes.- Return type:
- Parameters:
expression (FormulaExpression)
ctx (_EvalContext)
- evaluate_m131_resolve_modulos_minoracion_empleo(expression, ctx)[source]¶
Resolve the M131/M100 estimación-objetiva Fase 2ª minoración por incentivos al empleo.
Orden HAC/1347/2024 Anexo II, instrucción 2.2.a) fixes the mechanism (AEAT Manual práctico de Renta 2025, Parte 1, Capítulo 8, worked example epígrafe 673.1): the minoración is the módulo «personal asalariado» coefficient (rendimiento anual por unidad antes de amortización) times a coeficiente de minoración, itself the sum of two sub-coefficients:
coeficiente por incremento— when the current year’s módulo 1 unit count exceeds the prior year’s, the positive difference times 0,40 (a scalarratioregistry parameter, not hardcoded peraeat-schema-central-config);coeficiente por tramos— a progressive bracket lookup (the Orden’s tramo table) applied to the módulo 1 units net of the increment already credited above (resolve_bracketreused verbatim; the tramo table is structurally the same cumulative-progressive-scale shape as an IRPF escala).
The prior-year módulo 1 casilla (
modulos-1-unidades-anterior) is an optional manual input that defaults toDecimal('0')when the operator has not declared a prior-year comparison. Because a genuinely zero prior-year headcount is legally indistinguishable, at this op’s boundary, from “no comparison declared”, a non-positiveanterioris treated as “no incremento claimed” — the coeficiente por incremento is skipped (never fabricated) and the coeficiente por tramos runs on the full current-year módulo 1 units. This never over-states the minoración (a real, undeclared increment simply goes uncredited, mirroring the ADR’s “omitting an undeclared reduction does not over-state the figure” principle) and keeps a blank optional input from silently manufacturing an increment credit.Both a blank epígrafe and an untabled epígrafe (no módulo 1 coefficient row) resolve to
Decimal('0')— this op feeds the same internal-only advisory-support casilla chain as Fase 1ª (evaluate_m131_resolve_modulos_previo()), so a zero here means “no minoración computed”, never a filed figure standing in for the operator’s manual casilla 01.- Return type:
- Parameters:
expression (FormulaExpression)
ctx (_EvalContext)
- evaluate_m131_resolve_modulos_indice_exceso(expression, ctx)[source]¶
Resolve the M131/M100 estimación-objetiva Fase 3ª índice corrector de exceso.
Orden HAC/1347/2024 Anexo II, instrucción 2.3.b.3) fixes the mechanism (AEAT Manual práctico de Renta 2025, Parte 1, Capítulo 8, worked example epígrafe 673.1): when the rendimiento neto minorado (Fase 2ª) exceeds a per-activity cuantía threshold, the excess above that threshold is multiplied by the índice 1,30 (a scalar
ratioregistry parameter):rendimiento_neto_modulos = cuantia + indice x (minorado - cuantia)
when
minorado > cuantia; otherwise the módulos figure equals the minorado figure unchanged (no other índice corrector is modelled in this first slice — a legitimately-zero-index case, per the manual: “si el rendimiento neto minorado … es una cantidad negativa, no se aplicarán los índices correctores”). A blank epígrafe, an untabled epígrafe (no cuantía row), or a non-positive minorado all resolve to the minorado figure unchanged — this op feeds the same internal-only advisory-support casilla chain as Fases 1ª/2ª, never a filed figure standing in for the operator’s manual casilla 01.Incompatibility gap (not modelled in this first slice). Orden HAC/1347/2024 Anexo II, instrucción 2.3 (see
orden-hac-1347-2024:anexo-ii-instruccion-2-3-incompatibilidades) declares the índice de exceso (b.3) applied here INCOMPATIBLE with two other índices this op does not model: “Cuando resulte aplicable el índice corrector para empresas de pequeña dimensión (b.1) no se aplicará el índice corrector de exceso (b.3)” (b.1 excludes b.3 outright), and the índices correctores especiales (a.2 transporte por autotaxis, a.3 transporte urbano colectivo, a.4 transporte de mercancías por carretera y servicios de mudanzas, a.5) are legally incompatible with b.1 for the same activities — so an activity eligible for a.2/a.4 that is ALSO eligible for b.1 must never apply b.3 either. Two of the tabled epígrafes inm131-modulos-cuantia-exceso-2025carry a documented índice especial (“721.2” transporte por autotaxis, letra a.2; “722” transporte de mercancías por carretera / servicios de mudanzas, letra a.4); this op applies b.3 to them unconditionally wheneverminorado > cuantia, without checking either exclusivity rule. Themodelo-131-2025-modulos-indice-exceso-incompatible-autotaxi/-mercanciasADVISORY verification predicates surface a non-blocking review prompt for these two epígrafes when the índice-exceso path activates, per no-silent-under-declaration — full modelling of b.1 and a.2/a.4 is deferred to Phase 2/3 of the 2026-07-01-modelo-131-eo-modulos-engine-adr.- Return type:
- Parameters:
expression (FormulaExpression)
ctx (_EvalContext)
- evaluate_m131_resolve_modulos_indices_generales(expression, ctx)[source]¶
Resolve the M131 estimación-objetiva Fase 3ª índices correctores generales cascade.
Orden HAC/1347/2024 Anexo II, instrucción 2.3 fixes both the mechanism and the application order for the índices correctores generales (letra b)): “Los índices correctores se aplicarán según el orden que aparecen enumerados a continuación, siempre que no resulten incompatibles, … sobre el rendimiento neto minorado o, en su caso, sobre el rectificado por aplicación de los mismos” — b.1) empresas de pequeña dimensión, b.2) temporada, b.3) exceso, b.4) inicio de nuevas actividades, each a multiplicative factor over the RUNNING rendimiento, not a single-índice pick nor a simultaneous product (mirrors the M100 EO-agraria índices correctores cascade,
_evaluate_m100_resolve_eo_agraria_indices_correctores()). The four steps are applied STRICTLY SEQUENTIALLY in that literal enumeration order — b.1, then b.2, then b.3, then b.4 — each on the running rendimiento left by the previous step; b.3’s exceso threshold is non-linear (identity below the tabled cuantía,cuantía + índice × excesoabove), so applying b.4 before b.3 (grouping b.2/b.4 as one step ahead of b.3) yields a materially different, non-commutative result and is a defect, not an equivalent reordering.Each índice casilla (pequeña dimensión, temporada, inicio de nuevas actividades) is an operator/preparer-declared rate: the taxpayer reads the applicable índice off the Anexo II tables (población del municipio / duración de la temporada / ejercicio de inicio, none of which this engine models as taxpayer facts) and enters it directly — the same honest-scalar pattern the índice de exceso (b.3) and the M100 agraria cascade already use. A blank or non-positive índice resolves to “not applied” (factor of 1), never a fabricated value.
Incompatibilidades (Orden HAC/1347/2024 Anexo II, instrucción 2.3, grounded in
orden-hac-1347-2024:anexo-ii-instruccion-2-3-incompatibilidades), enforced structurally rather than left to an advisory-only guard (per the prior b.3-only code-review HIGH finding on this same engine, commit939f3fe010):“En ningún caso será aplicable el índice corrector para empresas de pequeña dimensión (b.1) a las actividades para las que están previstos los índices correctores especiales” (a.2/a.3/a.4/a.5) — a declared pequeña-dimensión índice is IGNORED (never applied) for the two tabled epígrafes carrying a documented índice especial (
_M131_EPIGRAFES_INDICE_ESPECIAL: “721.2” transporte por autotaxis letra a.2, “722” transporte de mercancías letra a.4). Themodelo-131-2025-modulos-pequena-dimension-ignorado-especialADVISORY surfaces this to the operator as a non-blocking prompt (never a silent drop with no signal, per no-silent-under-declaration).“Cuando resulte aplicable el índice corrector para empresas de pequeña dimensión (b.1) no se aplicará el índice corrector de exceso (b.3)” — when a (non-ignored) pequeña-dimensión índice applies, the índice de exceso is skipped for this activity.
“Cuando resulte aplicable el índice corrector de temporada (b.2) no se aplicará el índice corrector por inicio de nuevas actividades (b.4)” — temporada and inicio de nuevas actividades are mutually exclusive; when both are declared, temporada (the Anexo’s own enumeration order, b.2 before b.4) takes precedence and inicio de nuevas actividades is skipped. The
modelo-131-2025-modulos-temporada-inicio-actividad-incompatiblesADVISORY surfaces the conflicting declaration.
A non-positive rendimiento neto minorado never receives índices correctores (the general estimación-objetiva principle applied uniformly across this engine — see the M100 agraria and M131 índice-de-exceso guards) and resolves to the minorado figure unchanged. This op feeds the same internal-only
modulos-rendimiento-neto-modulosadvisory-support casilla the índice de exceso already fed, never a filed figure standing in for the operator’s manual casilla 01.- Return type:
- Parameters:
expression (FormulaExpression)
ctx (_EvalContext)
- evaluate_m131_resolve_modulos_pequena_dimension_ignorado_flag(expression, ctx)[source]¶
Flag (1/0) whether a declared índice de pequeña dimensión (b.1) was ignored.
Orden HAC/1347/2024 Anexo II, instrucción 2.3: “En ningún caso será aplicable el índice corrector para empresas de pequeña dimensión (b.1) a las actividades para las que están previstos los índices correctores especiales enumerados en las letras a.2), a.3), a.4) y a.5).” Resolves to
Decimal('1')when the operator declared a positive índice de pequeña dimensión for an epígrafe carrying a documented índice especial (_M131_EPIGRAFES_INDICE_ESPECIAL) — the exact conditionevaluate_m131_resolve_modulos_indices_generales()uses to ignore the índice — never fabricating a value, only signalling the ignored declaration so the paired ADVISORY (viaadvisory_when_positive) can surface it to the operator (no-silent-under-declaration).- Return type:
- Parameters:
expression (FormulaExpression)
ctx (_EvalContext)
- evaluate_m131_resolve_modulos_temporada_inicio_conflicto_flag(expression, ctx)[source]¶
Flag (1/0) whether both índice de temporada (b.2) and índice de inicio (b.4) were declared.
Orden HAC/1347/2024 Anexo II, instrucción 2.3: “Cuando resulte aplicable el índice corrector de temporada (b.2) no se aplicará el índice corrector por inicio de nuevas actividades (b.4).” Resolves to
Decimal('1')when both índices are positive — the mutually-exclusive declarationevaluate_m131_resolve_modulos_indices_generales()resolves by preferring temporada (the Anexo’s own enumeration order) and skipping inicio de nuevas actividades — so the paired ADVISORY (viaadvisory_when_positive) can surface the conflicting declaration to the operator.- Return type:
- Parameters:
expression (FormulaExpression)
ctx (_EvalContext)