Source code for cadrumo.domain.contribuyente.deduccion_maternidad

"""Art. 81 LIRPF deducción maternidad computation helpers.

Pure-domain arithmetic; no entrypoint or CLI dependencies.
:func:`compute_deduccion_maternidad_0611` reads its dated operands from the
governed-facts authority and derives the raised post-birth alta cap from the
ordinary cap plus the applicable increment.
"""

from __future__ import annotations

from collections.abc import Container
from datetime import date

from ..calculations.registry.errors import RegistryValidationError
from ..calculations.registry.facts.resolution import (
    MappingFactQuery,
    ResolvedMappingFact,
    ResolvedScalarFact,
    ScalarFactQuery,
)
from ..calculations.registry.governed_fact_scope import GovernedFactSource, governed_facts_in_scope
from ..calculations.registry.schema_base import DateAxis

_MATERNIDAD_FORMULA_SPEC_ID = "lirpf-art-81-maternity-formula-spec"
_REQUIRED_FORMULA_SPEC_KEYS = frozenset(
    {
        "formula.monthly_amount_fact_id",
        "formula.annual_cap_fact_id",
        "formula.increment_fact_id",
        "formula.increment_effective_year_fact_id",
    }
)


def _resolve_maternidad_formula_spec(
    filing_year: int,
    *,
    authority: GovernedFactSource | None = None,
) -> tuple[GovernedFactSource, date, dict[str, str]]:
    """Resolve and validate the dated mapping that names maternity operands."""
    effective_date = date(filing_year, 12, 31)
    authority = authority or governed_facts_in_scope()
    if authority is None:
        raise RegistryValidationError(
            "maternity formula specification requires an explicit authority operation or scope",
        )
    resolved = authority.resolve_governed_fact(
        MappingFactQuery(
            fact_id=_MATERNIDAD_FORMULA_SPEC_ID,
            date_axis=DateAxis.FILING_PERIOD,
            effective_date=effective_date,
        )
    )
    if not isinstance(resolved, ResolvedMappingFact):
        raise RegistryValidationError("maternity formula specification must resolve as a mapping fact")

    declarations: dict[str, str] = {}
    for entry in resolved.payload.entries:
        if type(entry.key) is not str or type(entry.value) is not str:
            raise RegistryValidationError("maternity formula specification entries must be strings")
        key = entry.key.strip()
        value = entry.value.strip()
        if not key or not value or key != entry.key or value != entry.value:
            raise RegistryValidationError("maternity formula specification contains blank or padded entries")
        if key in declarations:
            raise RegistryValidationError(f"maternity formula specification repeats key {key!r}")
        declarations[key] = value

    missing = _REQUIRED_FORMULA_SPEC_KEYS - declarations.keys()
    if missing:
        raise RegistryValidationError(f"maternity formula specification is missing required keys {sorted(missing)!r}")
    return authority, effective_date, declarations


def _resolve_maternidad_scalar(
    authority: GovernedFactSource,
    fact_id: str,
    effective_date: date,
) -> int:
    """Resolve one named integer operand at the mapping's exact coordinate."""
    resolved = authority.resolve_governed_fact(
        ScalarFactQuery(
            fact_id=fact_id,
            date_axis=DateAxis.FILING_PERIOD,
            effective_date=effective_date,
        )
    )
    if not isinstance(resolved, ResolvedScalarFact):
        raise RegistryValidationError(f"maternity operand {fact_id!r} did not resolve as a scalar fact")
    value = resolved.payload.value
    if type(value) is not int:
        raise RegistryValidationError(f"maternity operand {fact_id!r} must resolve as an integer")
    return value


def _resolve_maternidad_figure(
    filing_year: int,
    slug: str,
    *,
    authority: GovernedFactSource | None = None,
) -> int:
    """Read one Art. 81.1 figure from the published authority.

    The mapping specification names the typed governed facts. Consume that
    specification and each named scalar at their exact filing coordinate; an
    absent coordinate is a registry validation failure rather than a reason to
    read a parallel parameter copy.

    Returns:
        The integer euro figure the registry declares for ``filing_year``.
    """
    key_by_slug = {
        "mensual": "formula.monthly_amount_fact_id",
        "cap-anual": "formula.annual_cap_fact_id",
        "alta-posterior-incremento": "formula.increment_fact_id",
    }
    try:
        mapping_key = key_by_slug[slug]
    except KeyError as exc:
        raise RegistryValidationError(f"unknown maternity figure {slug!r}") from exc
    authority, effective_date, declarations = _resolve_maternidad_formula_spec(
        filing_year,
        authority=authority,
    )
    return _resolve_maternidad_scalar(authority, declarations[mapping_key], effective_date)


def _resolve_alta_posterior_increment(
    filing_year: int,
    *,
    authority: GovernedFactSource | None = None,
) -> int | None:
    """Return the increment, or ``None`` only when its dated declaration excludes it.

    The effective-year scalar is resolved through the mapping specification.
    Missing or malformed declarations remain registry failures.

    Returns:
        The increment for ``filing_year``, or ``None`` when none applies.
    """
    authority, effective_date, declarations = _resolve_maternidad_formula_spec(
        filing_year,
        authority=authority,
    )
    effective_year = _resolve_maternidad_scalar(
        authority,
        declarations["formula.increment_effective_year_fact_id"],
        effective_date,
    )
    if filing_year < effective_year:
        return None
    return _resolve_maternidad_scalar(authority, declarations["formula.increment_fact_id"], effective_date)


[docs] def compute_deduccion_maternidad_0611( meses_por_hijo: list[tuple[str, int]], *, filing_year: int, alta_posterior_hijos: Container[str] = frozenset(), authority: GovernedFactSource | None = None, ) -> int: """Compute Art. 81 LIRPF deducción maternidad from per-hijo meses pairs. The ordinary formula multiplies each child's eligible months by the dated monthly parameter and caps it at the dated annual parameter. A ``hijo_id`` named in *alta_posterior_hijos* additionally receives the Art. 81.1 post-birth alta increment for the one calendar month completing the 30-day minimum contribution period, ONLY for *filing_year* from a revision that declares the increment: its total adds that increment on top of the ordinary monthly accrual (the completion month is counted once at the ordinary rate, already inside ``meses``, and once again here), and its cap is raised to derived annual cap. Every other pair, and every pair for an earlier filing year, keeps the ordinary rate and cap untouched — the increment can only ever ADD to a hijo's total, never substitute for it. Returns an integer euros amount. """ mensual = _resolve_maternidad_figure(filing_year, "mensual", authority=authority) cap_anual = _resolve_maternidad_figure(filing_year, "cap-anual", authority=authority) increment = _resolve_alta_posterior_increment(filing_year, authority=authority) total = 0 for hijo_id, meses in meses_por_hijo: importe = meses * mensual cap = cap_anual if increment is not None and hijo_id in alta_posterior_hijos: importe += increment # The raised cap is DERIVED from its two inputs rather than stored, # so it cannot drift away from them the way an independent literal # would. cap = cap_anual + increment total += min(importe, cap) return total