Source code for aeat.domain.calculations.registry._observation_fold
"""One observation-fold helper for cross-filing fold-ins.The single gather-and-fold primitive shared by both relation fold paths (theapplication-layer relation prefill and the domain-layer:func:`domain.calculations.registry.resolve_relation_values_from_observations`).It matches the source filings a:class:`~domain.calculations.registry.RegistryFoldRequirement` declares andextracts the source casilla value per period, then folds the gathered valuesthrough the requirement's declared ``copy`` / ``sum`` aggregation to one:class:`~decimal.Decimal`.Lives in the domain registry package (not the application source mesh) becausethe domain relation resolver consumes it and the hexagonal direction forbids adomain module importing the application layer.See Also: :mod:`domain.calculations.registry._relations` Domain relation resolver that gathers and folds requirements here. :mod:`domain.calculations.registry._bindings_previous_filing` Previous-filing binding resolver that reuses :func:`fold_sum_or_copy`."""from__future__importannotationsfromdecimalimportDecimalfromtypingimportTYPE_CHECKINGfrom._errorsimportRegistryValidationErrorifTYPE_CHECKING:from._bindingsimportRegistryModeloObservationfrom._relationsimportRegistryFoldRequirement
[docs]defgather_observed_requirement_values(requirement:RegistryFoldRequirement,observations:tuple[RegistryModeloObservation,...],)->tuple[Decimal,...]:"""Return the source-casilla values matched for one fold requirement, per period. Matches exactly one :class:`~domain.calculations.registry.RegistryModeloObservation` per declared source period and extracts the requirement's single source :class:`~domain.calculations.registry.CasillaId` value from each. The returned tuple carries one value per ``requirement.periods`` entry, in declaration order, ready for :func:`fold_observed_requirement_values`. """source_casilla_id=requirement.source_casilla_ids[0]values:list[Decimal]=[]forsource_periodinrequirement.periods:matches=tuple(observationforobservationinobservationsifobservation.modelo==requirement.source_modeloandobservation.filing_year==requirement.filing_yearandobservation.period==source_period)iflen(matches)!=1:raiseRegistryValidationError(f"relation requirement {requirement.relation_ids!r} expected one observed filing "f"{requirement.source_modelo!r}/{requirement.filing_year}/{source_period!r}, found {len(matches)}",)value=matches[0].casilla_values.get(source_casilla_id)ifvalueisNone:raiseRegistryValidationError(f"relation requirement {requirement.relation_ids!r} requires observed source casilla id "f"{source_casilla_id!r} from "f"{requirement.source_modelo!r}/{requirement.filing_year}/{source_period!r}",)values.append(value)returntuple(values)
[docs]deffold_sum_or_copy(op:str,values:tuple[Decimal,...]|list[Decimal],*,subject:str,copy_unit:str,)->Decimal:"""Fold a value sequence through the shared ``sum`` / ``copy`` arithmetic. The one place ``sum`` (add every value) and ``copy`` (require exactly one value and return it) are implemented. ``subject`` and ``copy_unit`` carry the caller's diagnostic vocabulary so a refused copy names the right entity (a relation requirement's observation, or a binding's source casilla). An op that is neither ``sum`` nor ``copy`` is rejected; callers handle any other op (e.g. the Modelo 130 ``prior_pagos_fraccionados`` identity) before delegating. Used by both :func:`fold_observed_requirement_values` and :func:`domain.calculations.registry.resolve_previous_filing_binding_values`. """ifop=="copy":iflen(values)!=1:raiseRegistryValidationError(f"{subject} copy aggregation requires one {copy_unit}")returnvalues[0]ifop=="sum":returnsum(values,Decimal("0"))raiseRegistryValidationError(f"{subject} uses unsupported aggregation op {op!r}")
[docs]deffold_observed_requirement_values(requirement:RegistryFoldRequirement,values:tuple[Decimal,...],)->Decimal:"""Fold per-period source values through a requirement's ``copy`` / ``sum`` op. ``copy`` requires exactly one gathered value and returns it; ``sum`` adds the gathered values. This is the one fold both relation paths apply to a :class:`~domain.calculations.registry.RegistryFoldRequirement`; the period match is :func:`gather_observed_requirement_values`. """returnfold_sum_or_copy(requirement.aggregation_op,values,subject=f"relation requirement {requirement.relation_ids!r}",copy_unit="observation",)
[docs]defresolve_observed_requirement_value(requirement:RegistryFoldRequirement,observations:tuple[RegistryModeloObservation,...],)->Decimal:"""Gather and fold one requirement to a single :class:`~decimal.Decimal`. Convenience wrapper for callers that already hold the normalized :class:`~domain.calculations.registry.RegistryModeloObservation` rows. """returnfold_observed_requirement_values(requirement,gather_observed_requirement_values(requirement,observations),)