Source code for aeat.application.overview._coverage
"""Obligation-coverage reconciliation for the overview surface.The default ``overview`` surfaces (``calendar`` / ``agenda`` / ``backlog``)answer "what must this taxpayer file?". A filing obligation reaches thosesurfaces only when it has BOTH a registered deadline window (so the deadlineengine emits it) AND a positively ``APPLICABLE`` seed applicability verdict (sothe calendar keeps it). A modelo that lacks either is otherwise dropped without adefault-visible trace, so an operator — or the autonomous agent the CLI targets —trusting the surface would under-file.This module reconciles the full :func:`~application.modelo.registry_modelo_codes`set against what the calendar positively resolved and classifies every registrymodelo into exactly one disposition:* **surfaced** — it was resolved by a registry window and an applicable verdict;* **confidently excluded** — the taxpayer model positively answers "no" for it (``NOT_APPLICABLE`` / ``ATTRIBUTION_PASS_THROUGH``): an answered question, no advisory needed;* **advised** — it is applicable-but-window-less (e.g. Modelo 190) or its applicability is undetermined (``INCOMPLETE``): an unanswered question the operator MUST investigate;* **out of scope** — it is listed in :data:`~core.OUT_OF_SCOPE_OBLIGATIONS` with a recorded product-scope reason.The classification is total by construction, so no registry modelo can besilently absent. The **advised** set is projected into a default-visible:class:`~core.json_contract.Notice` by the CLI, closing the``no-silent-under-declaration`` gap one layer up, at obligation determination."""from__future__importannotationsfromcollections.abcimportIterablefromdatetimeimportdatefromenumimportStrEnumfrompydanticimportBaseModelfrom...coreimportOUT_OF_SCOPE_OBLIGATIONSas_OUT_OF_SCOPE_OBLIGATIONSfrom...coreimportSTRICT_FROZEN_CONFIGas_STRICT_FROZENfrom...coreimportUNMODELED_OBLIGATIONSas_UNMODELED_OBLIGATIONSfrom...domain.calculations.registry.applicabilityimport(ApplicabilityVerdict,derive_modelo_applicability,)from...domain.deadlinesimportTaxpayerProfile
[docs]classCoverageAdviceReason(StrEnum):"""Why an unsurfaced obligation is advised rather than silently dropped. Attributes: APPLICABLE_WINDOW_MISSING: The taxpayer model positively triggers the modelo (verdict ``APPLICABLE``) but the registry carries no deadline window for it, so the engine never placed it on the calendar. This is the former Modelo-190 shape — a genuine data gap. APPLICABILITY_UNDETERMINED: The seed applicability table cannot yet decide the modelo for this profile (verdict ``INCOMPLETE`` — no seed rule, or a payer/enrolment fact left undeclared). The operator must investigate whether it applies. REGISTRY_UNMODELED: The modelo is a recognized AEAT obligation (:data:`~core.UNMODELED_OBLIGATIONS`) that the registry does not model at all, so neither a window nor an applicability rule exists. It surfaces as advised — "AEAT may expect this; the app cannot yet scope it" — rather than being invisible. """APPLICABLE_WINDOW_MISSING="applicable_window_missing"APPLICABILITY_UNDETERMINED="applicability_undetermined"REGISTRY_UNMODELED="registry_unmodeled"
[docs]classAdvisedObligation(BaseModel):"""One registry modelo the operator must investigate, with its reason."""model_config=_STRICT_FROZENmodelo:strreason:CoverageAdviceReason
[docs]classObligationCoverageReport(BaseModel):"""Total partition of the registry modelo set by coverage disposition. Every :func:`~application.modelo.registry_modelo_codes` code lands in exactly one of the four tuples. ``advised`` is the load-bearing field: a non-empty ``advised`` means the default surface would otherwise have hidden a filing obligation the operator must investigate. Attributes: surfaced: Modelos positively resolved by registry windows and applicability for the queried schedule horizon. confidently_excluded: Modelos the taxpayer model positively answers "no" for — answered, so no advisory is raised. advised: Modelos the operator must investigate (window-missing or applicability-undetermined), each with its :class:`CoverageAdviceReason`. out_of_scope: Modelos declared out of scope in :data:`~core.OUT_OF_SCOPE_OBLIGATIONS`. """model_config=_STRICT_FROZENsurfaced:tuple[str,...]=()confidently_excluded:tuple[str,...]=()advised:tuple[AdvisedObligation,...]=()out_of_scope:tuple[str,...]=()@propertydefadvised_modelos(self)->tuple[str,...]:"""Return just the advised modelo codes, in report order."""returntuple(item.modeloforiteminself.advised)@propertydefhas_advisories(self)->bool:"""Return whether any obligation must be investigated."""returnbool(self.advised)
[docs]defbuild_obligation_coverage(profile:TaxpayerProfile,surfaced_modelos:Iterable[str],*,today:date,)->ObligationCoverageReport:"""Reconcile surfaced obligations against the full registry modelo set. Walks every :func:`~application.modelo.registry_modelo_codes` code and assigns it to exactly one disposition (see :class:`ObligationCoverageReport`). The classification is total, so a modelo can never be silently absent: one that is neither surfaced, nor confidently excluded, nor explicitly out of scope is ``advised``, and the CLI raises a default-visible advisory for it. Args: profile: The operator's three-axis :class:`~domain.deadlines.TaxpayerProfile`. surfaced_modelos: The modelo codes positively resolved by a registry deadline window and an applicable verdict for the queried schedule horizon. They need not have an entry inside the UI date range; an annual row outside a two-week agenda is still resolved, not a grounding gap. today: Reference date for applicability evaluation (the Modelo-720 Beckham-window check is date-sensitive). Returns: The :class:`ObligationCoverageReport` partition. """# Deferred to break a module-load cycle: application.modelo is a heavier# sibling package and importing it at module scope would couple overview's# import graph to it. The lookup itself is cheap (cached authority).from..modeloimportregistry_modelo_codessurfaced_set=frozenset(surfaced_modelos)registry_codes=frozenset(registry_modelo_codes())unmodeled_codes={str(code)forcodein_UNMODELED_OBLIGATIONS}out_of_scope_codes={str(code)forcodein_OUT_OF_SCOPE_OBLIGATIONS}# The AEAT obligation universe is the registry directory plus every recognized# obligation the registry does not model — those advised as unmodeled and those# explicitly declared out of scope. Binding the reconciliation to the full union# — not the registry alone — is what makes an obligation AEAT expects but the app# never modeled surface (as advised or as a recorded out-of-scope decision) rather# than being invisible.universe=registry_codes|unmodeled_codes|out_of_scope_codessurfaced:list[str]=[]confidently_excluded:list[str]=[]advised:list[AdvisedObligation]=[]out_of_scope:list[str]=[]formodeloinsorted(universe):ifmodeloinsurfaced_set:surfaced.append(modelo)continueifmodeloinout_of_scope_codes:out_of_scope.append(modelo)continueifmodelonotinregistry_codes:# A recognized AEAT obligation the registry does not model: no window# and no applicability rule exist, so it cannot be positively scoped.advised.append(AdvisedObligation(modelo=modelo,reason=CoverageAdviceReason.REGISTRY_UNMODELED))continueverdict=derive_modelo_applicability(profile,modelo,today=today).verdictifverdictin_CONFIDENT_NEGATIVE_VERDICTS:confidently_excluded.append(modelo)continuereason=(CoverageAdviceReason.APPLICABLE_WINDOW_MISSINGifverdictisApplicabilityVerdict.APPLICABLEelseCoverageAdviceReason.APPLICABILITY_UNDETERMINED)advised.append(AdvisedObligation(modelo=modelo,reason=reason))returnObligationCoverageReport(surfaced=tuple(surfaced),confidently_excluded=tuple(confidently_excluded),advised=tuple(advised),out_of_scope=tuple(out_of_scope),)