cadrumo.domain.contribuyente.descendant_record module¶
Validated descendant facts and core Art. 58 eligibility behavior.
- class DescendantRecordFields(**data)[source]¶
Bases:
BaseModelCanonical field vocabulary shared by domain records and projections.
- Parameters:
data (Any)
- birth_date: date¶
- relacion: DescendantRelacion¶
- inscripcion_registro_civil_date: date | None¶
- acogimiento_resolucion_date: date | None¶
- death_date: date | None¶
- discapacidad_grado: Literal[0, 33, 65] | None¶
- convive_con_contribuyente: bool¶
- dependencia_economica: bool | None¶
- custodia_compartida: bool¶
- rentas_anuales_euros: Decimal | None¶
- presenta_declaracion_propia: bool¶
- prorrata_minimo: bool | None¶
- meses_madre_trabajo: tuple[int, ...]¶
- alta_posterior_nacimiento_mes: CalendarMonth | None¶
- segundo_ciclo_infantil_inicio_mes: CalendarMonth | None¶
- gastos_guarderia_euros: int¶
- gastos_guarderia_mensuales: tuple[GuarderiaMonthSpend, ...]¶
- nif: str | None¶
- class DescendantRecordBase(**data)[source]¶
Bases:
DescendantRecordFieldsStructured per-descendant data for Art. 58 mínimo-por-descendientes.
This record drives the mínimo-por-descendientes calculation (casilla 0513) and the bajo-3-años supplement (Art. 58.2). It is intentionally richer than
RentaDescendantProfile, which models official-form rows.Fields¶
- birth_date
Required date of birth.
- relacion
The legal relationship linking this descendant to the contribuyente (
DescendantRelacion). Defaults to the registry-declared ordinary-descendant token, so an absent fact means an ordinary descendant. Art. 58.1 assimilates tutela and acogimiento for the tranches while Art. 58.2 names only “adopción o acogimiento, tanto preadoptivo como permanente” for the increase, so the two clauses need this distinction drawn rather than inferred.- inscripcion_registro_civil_date
The Art. 58.2 entry event for an ADOPTION: the date the adoption was inscribed in the Registro Civil, or — where inscription is not required — the date of the resolución judicial o administrativa. One anchor with two legal sources, not two meanings, which is why it is one field. Permitted only on an registry-declared adoption record.
The date is the INSCRIPTION in the Registro Civil, which is what Art. 58.2 counts from — not the adoption’s finalisation. The two can fall in different periods, so the distinction is load-bearing rather than terminological.
- acogimiento_resolucion_date
The Art. 58.2 entry event for an acogimiento: the date of the FIRST ENTITLING resolución — preadoptivo or permanente, the two shapes the statute names. Permitted on those records and on an
ADOPTADOrecord, because Art. 58.2’s three periods are a CAP measured from the first entitling event rather than a count the later adoption restarts: a fostered-then-adopted child holds both dates and gets three periods in total, not six. A temporal placement is not entitling and therefore has no truthful value for this field.- discapacidad_grado
0 = sin discapacidad, 33 = grado ≥ 33 % < 65 %, 65 = grado ≥ 65 %. A disabled descendant remains mínimo-eligible regardless of age.
- convive_con_contribuyente
Whether the descendant cohabits with the taxpayer (Art. 58.1 condition). Stays a FACT about the household and is never overloaded to carry the dependency case; the two are separate fields precisely so a filer who does not cohabit is not forced to misstate cohabitation to reach the allowance they are entitled to.
- dependencia_economica
Whether the taxpayer contributes to this descendant’s economic upkeep without cohabiting.
None(the default) means UNSET, which never assimilates; only an explicitTruedoes, and only when the filer declares no judicial anualidades. The authority states the entitled case in terms — a progenitor with no custody, not even shared, paying no anualidades, who nonetheless contributes economically.Falseis a real answer distinct from unset: it records that the question was put and declined.- custodia_compartida
Art. 61 LIRPF: when
True, both progenitors share custody under a judicial or administrative arrangement. The mínimo-por-descendientes and the bajo-3-años supplement for this child are split 50 % between them (Art. 61 prorrata). DefaultFalse(sole custody / not applicable). Setting this flag on a non-cohabiting descendant has no additional effect because eligibility already fails.- rentas_anuales_euros
The descendant’s own annual rentas EXCLUDING exempt income, the figure Art. 58.1 LIRPF caps (“no tenga rentas anuales, excluidas las exentas, superiores a 8.000 euros”).
Nonemeans the operator has not declared a figure, which does NOT exclude the descendant — seeis_eligible_ordinary()for why absence is read as “no rentas to declare” rather than as a disqualification.- presenta_declaracion_propia
Whether the descendant files their own IRPF return. Art. 61 norma 2ª LIRPF withdraws the mínimo entirely when a descendant who generates the entitlement “presenten declaración por este Impuesto con rentas superiores a 1.800 euros” — so this flag alone does not exclude; it excludes only in combination with
rentas_anuales_eurosabove the norma 2ª threshold. DefaultFalse.- prorrata_minimo
Explicit per-descendant answer to Art. 61 norma 1ª: does another contribuyente also hold the right to this descendant’s mínimo?
Trueprorates,Falseclaims the full amount, andNone(the default) leaves the question unanswered so the caller may derive it from profile signals. An explicit value ALWAYS wins over bothcustodia_compartidaand any derivation.- meses_madre_trabajo
WHICH calendar months (1-12, ascending, no repeats) the mother met the Art. 81.1 requirements for this child. Used by the deducción maternidad as a count —
min(meses × 100, 1_200)per eligible child — and by the Art. 81.2 guardería increment as a SET.The months rather than their number, because Art. 81.2 prorates by “el número de meses en que se cumplan de forma simultánea los requisitos exigidos en el artículo 81.1 y 2”: an INTERSECTION with the declared nursery months, which a count cannot express. A mother entitled May to August against nursery paid January to June shares two months and the manual works
1.000 ÷ 12 × 2 = 166,67, where a count-basedmin(4, 6)yields four and 333,33 — an over-grant of the deducción, which under-declares tax. Default()(no deducción contribution from this child).- alta_posterior_nacimiento_mes
The calendar month (1-12) in which the mother — not registered with the Seguridad Social or a mutualidad at this child’s birth — completed the 30-day minimum contribution period Art. 81.1 LIRPF requires for the post-birth alta route (“que en dicho momento o en cualquier momento posterior estén dadas de alta … con un período mínimo, en este último caso, de 30 días cotizados”).
None(the default) means the ordinary case: no post-birth alta increment applies, whether because the mother was already registered at the birth or because none is declared. This is the mother’s employment history, exactly asmeses_madre_trabajois, and this application does not hold it and must not infer it.The route itself is filing-year gated: LIRPF art. 81.1 reached only a mother already registered “en el momento del nacimiento” before filing year 2023 (the
lirpf-art-81-maternity-post-birth-enrollment-effective-yeargoverned fact), so a declared month for an earlier filing year contributes no increment — seematernidad_alta_posterior_increment_applies().- gastos_guarderia_euros
Actual guardería / centro educación infantil autorizado expenses paid for this child (Art. 81.2 LIRPF), as an ANNUAL total. Integer euros, ≥ 0. Default
0(no guardería expenses declared for this child). Sufficient only while the child is under three for the whole period; it cannot express either month boundary the statute draws.- gastos_guarderia_mensuales
The same spend broken down by month, sparse: only months with spend appear. Required for the period in which the child turns three, because that period needs the post-birthday months separated and an annual total cannot be apportioned across a birthday. Mutually exclusive with
gastos_guarderia_eurosfor one child — declaring both is refused rather than reconciled, so a descendant always has exactly one spend authority.- death_date
The date this descendant died, or
None(the default) for a descendant who did not die. Art. 61 norma 4ª LIRPF turns on this fact twice, and the two limbs read it differently, which is why one date drives both rather than a bare “died this year” flag.A death IN the filing period replaces this descendant’s Art. 58.1 birth-order tranche with the norma 4ª flat cuantía, at any birth order — the flat figure coincides with the first-child tranche, so the substitution is invisible for a first child and worth 300 € to 2.100 € for a later one. The Art. 58.2 menor-3 supplement is NOT replaced: the AEAT manual states it “resulta aplicable en los casos en que el descendiente haya fallecido durante el período impositivo”, so it is added on top of the flat figure exactly as it is on top of a tranche.
A death BEFORE the devengo (31 December) additionally drops this descendant from the age ordering that ranks the survivors — the manual’s “sin computar a estos efectos aquellos descendientes que, en su caso, hubieran fallecido en el ejercicio con anterioridad a la fecha de devengo del impuesto”. The two limbs are deliberately NOT collapsed into one condition: the flat cuantía is owed on any death in the period, while the ordering exclusion is expressly conditioned on the death preceding the devengo, so a descendant who dies ON 31 December takes the flat figure and still occupies their rank. That case is degenerate but the clauses are worded differently, and reading them as one would be a choice neither text supports.
A death in a PRIOR year makes this descendant no part of this period at all — see
meets_non_income_conditions().- nif
Optional NIF/NIE; validated for shape when present.
- died_in_period(filing_year)[source]¶
True when this descendant died during filing_year.
The Art. 61 norma 4ª trigger for the FLAT cuantía, which the statute conditions on the fallecimiento alone with no reference to the devengo.
- died_before_devengo(filing_year)[source]¶
True when this descendant died in filing_year before its 31 December devengo.
The trigger for the ORDERING limb only, which the AEAT manual conditions on the death falling “con anterioridad a la fecha de devengo del impuesto”. Strictly narrower than
died_in_period(), and the gap between them is load-bearing rather than an oversight — see thedeath_datefield documentation.
- age_at_year_end(filing_year)[source]¶
Return the descendant’s age at the end of filing_year, or at death.
A descendant who died during the period is aged at their DEATH DATE, not at 31 December, and that distinction is load-bearing rather than pedantic. Aging them to year-end returns an age they never reached whenever their birthday falls between the death and 31 December, and the consequences are both silent and both against a bereaved filer: a child who died at 24 reads as 25 and fails the Art. 58.1 age limb outright, so the flat cuantía Art. 61 norma 4ª exists to grant is never reached; a toddler who died at two reads as three and loses the menor-tres increment this module’s own aggregate promises them.
Norma 4ª exists BECAUSE the deceased is absent at the devengo, so applying a 31-December test to someone the statute already treats as dead defeats the provision’s own premise. The AEAT manual cited at
minimo_descendientes_estatal()grants the menor-tres increase to a descendant who died during the period, which is the same reading.A death in a PRIOR year is not aged here at all – that descendant is already excluded by
meets_non_income_conditions(), which fails ondeath_date.year < filing_yearbefore any age question is asked.
- art_58_2_entry_date()[source]¶
The FIRST entitling entry event for the Art. 58.2 window, or
None.Art. 58.2’s three periods are a cap rather than a restart: where the circumstances change — the authority’s own worked example is an adoption following a fostering — the increase continues for the remaining periods up to a maximum of three. Anchoring on whichever event the record happens to hold would grant a fostered-then-adopted child up to six periods where the statute allows three, so the earliest entitling event is the anchor and the later one changes nothing.
Returns
Nonefor a relación the statute excludes from the limb (tutela, temporal acogimiento, an ordinary descendant) and for an entitling relación whose date is not yet recorded.
- exceeds_rentas_cap(thresholds)[source]¶
True when a DECLARED rentas figure breaches the Art. 58.1 ceiling.
Art. 58.1 LIRPF conditions the mínimo on the descendant holding no “rentas anuales, excluidas las exentas, superiores a” the ceiling, so the test is strictly greater-than: a descendant exactly AT the ceiling keeps the mínimo.
An undeclared figure (
rentas_anuales_euros is None) returnsFalse— absence of data is not evidence of income. The alternative default would zero the mínimo for every descendant nobody has yet entered a figure for, which is the overwhelming majority (a young child has no rentas to declare) and would be a large silent UNDER-claim against the taxpayer. The residual over-claim risk — a descendant who really does earn above the ceiling whose figure was never entered — is the operator’s to close by declaring the figure.- Return type:
- Parameters:
thresholds (MinimoDescendientesThresholds)
- excluded_by_declaracion_propia(thresholds)[source]¶
True when Art. 61 norma 2ª withdraws the mínimo for this descendant.
Norma 2ª bars the mínimo when the descendant who generates the entitlement “presenten declaración por este Impuesto con rentas superiores a” the norma 2ª figure. Both halves are required: filing a return is not disqualifying on its own (the AEAT manual is explicit that a descendant filing with “rentas iguales o inferiores a 1.800 euros” leaves the mínimo intact), and rentas alone are governed by the separate Art. 58.1 ceiling.
An undeclared rentas figure returns
Falsefor the same reason asexceeds_rentas_cap().- Return type:
- Parameters:
thresholds (MinimoDescendientesThresholds)
- is_eligible_ordinary(filing_year, *, thresholds, context, dependencia_assimilation_available=False)[source]¶
True when the descendant qualifies for the Art. 58.1 ordinary mínimo.
Eligibility requires ALL of:
cohabiting with the taxpayer (Art. 58.1 “siempre que conviva con el contribuyente”), OR assimilated economic dependency — see
meets_non_income_conditions();age < 25 at year-end OR any degree of discapacidad;
annual rentas excluding exempt income at or below the Art. 58.1 ceiling (
exceeds_rentas_cap());not excluded by the Art. 61 norma 2ª own-return rule (
excluded_by_declaracion_propia()).
thresholds is a required keyword argument rather than an optional one so no caller can silently evaluate the age/cohabitation half of the law while skipping the two income conditions.
- Return type:
- Parameters:
filing_year (int)
thresholds (MinimoDescendientesThresholds)
context (FamilyFactResolutionContext)
dependencia_assimilation_available (bool)
- meets_non_income_conditions(filing_year, *, context, dependencia_assimilation_available=False)[source]¶
The half of Art. 58.1 that needs no ceiling: the household limb and age/discapacidad.
Split out rather than inlined because one caller genuinely cannot supply the ceilings and does not need them. A descendant with NO declared rentas figure can never be excluded by either income condition — both read an absent figure as non-excluding — so for that descendant eligibility reduces exactly to this predicate. The calculate-path advisory that flags those descendants therefore asks this question directly instead of re-deriving it beside
is_eligible_ordinary(), which is how the two would drift.A descendant who died in a year BEFORE filing_year fails outright, ahead of every other condition. They were no part of this period, and the age limb would otherwise keep answering for them indefinitely —
birth_datealone goes on satisfying “under 25 at year-end” for years after the death, so without this gate a bereaved filer would keep claiming the mínimo for a child who died long ago, and the norma 4ª flat cuantía would not apply either because that limb is scoped to a death IN the period. Gated here rather than inis_eligible_ordinary()so the calculate-path advisory that asks this predicate directly cannot answer differently from the aggregate.The household limb is cohabitation OR assimilated economic dependency. The authority states the dependency case in terms: a progenitor without custody, not even shared, and paying no judicial anualidades, who nonetheless contributes to the descendant’s economic upkeep “tendrá derecho a la aplicación del mínimo por descendientes”. Cohabitation is therefore sufficient but not necessary, which is what an earlier reading of this predicate got wrong.
Assimilation requires BOTH halves and neither is a default. The descendant must carry an explicit
dependencia_economica = True— an unset field never assimilates, because the reachable-through-the-only- available-field shape is how an excluded case gets granted. And the caller must pass dependencia_assimilation_available, which the profile computes from the filer-level anualidades declaration.That flag defaults to
False, so a caller that forgets it gets the UNDER-granting answer rather than the claiming one. The default is the safe direction by construction rather than by convention.Not a public substitute for
is_eligible_ordinary(). AnsweringTruehere says only that the non-income conditions hold; a caller that HAS a rentas figure must still apply the ceilings.- Return type:
- Parameters:
filing_year (int)
context (FamilyFactResolutionContext)
dependencia_assimilation_available (bool)
- qualifies_on_household_limb(*, dependencia_assimilation_available=False)[source]¶
True when cohabitation holds, or economic dependency is assimilated in its place.
Named and public because three surfaces ask this question and one of them — the advisory that discloses the assimilation to the operator — needs it apart from the age limb.
- is_eligible_menor_tres(filing_year, *, context)[source]¶
True when the descendant is under three at the devengo date and cohabits.
Scoped to the Art. 81 deductions — the deducción por maternidad (art. 81.1) and the guardería incremento (art. 81.2). It is NOT the Art. 58.2 test: see
is_eligible_minimo_incremento_menor_tres(), which carries an additional limb this one deliberately lacks.Two known narrowings against the Art. 81 text, both in the over-taxing direction and both needing data this axis does not carry: art. 81.1 runs monthly “hasta que el menor alcance los tres años de edad” rather than testing age once at year-end, and art. 81.2 extends the guardería incremento through the period in which the child turns three, “respecto de los gastos incurridos con posterioridad al cumplimiento de dicha edad hasta el mes anterior a aquel en el que pueda comenzar el segundo ciclo de educación infantil”. Both need month-level figures;
gastos_guarderia_eurosis an annual total, so widening this predicate alone would swap an under-grant for an over-grant.- Return type:
- Parameters:
filing_year (int)
context (FamilyFactResolutionContext)
- Parameters:
birth_date (date)
relacion (DescendantRelacion)
inscripcion_registro_civil_date (date | None)
acogimiento_resolucion_date (date | None)
death_date (date | None)
discapacidad_grado (Literal[0, 33, 65] | None)
convive_con_contribuyente (bool)
dependencia_economica (bool | None)
custodia_compartida (bool)
rentas_anuales_euros (Annotated[Decimal | None, Ge(ge=Decimal('0'))])
presenta_declaracion_propia (bool)
prorrata_minimo (bool | None)
alta_posterior_nacimiento_mes (Annotated[int, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=1), Le(le=12)])] | None)
segundo_ciclo_infantil_inicio_mes (Annotated[int, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=1), Le(le=12)])] | None)
gastos_guarderia_mensuales (tuple[GuarderiaMonthSpend, ...])
nif (str | None)