"""Lookup helpers for IVA registry data.:func:`lookup_rate` resolves :class:`EUMemberState` and :class:`IvaRateKind`queries into :class:`IvaRateRecord` records loaded by:func:`aeat.domain.iva.load_iva_rate_table`; :func:`cite` renders:class:`IvaCategory` catalogue citations from an :class:`IvaCatalogue`."""from__future__importannotationsfromdatetimeimportdatefrom._catalogueimportresolve_cataloguefrom._errorsimportIvaCatalogueError,IvaCategoryNotFoundError,IvaRateNotFoundErrorfrom._ratesimportload_iva_rate_tablefrom._schemaimportEUMemberState,IvaCatalogue,IvaCategory,IvaRateKind,IvaRateRecord
[docs]deflookup_rate(member_state:EUMemberState,kind:IvaRateKind,on_date:date,)->IvaRateRecord:"""Return the :class:`aeat.domain.iva.IvaRateRecord` matching the supplied query. Iterates the rates registered for ``member_state`` in :data:`aeat.domain.iva.IVA_RATE_TABLE` and returns the first record whose :attr:`aeat.domain.iva.IvaRateRecord.kind` matches ``kind`` and whose effective window covers ``on_date``. Args: member_state: The EU member state whose rate is requested. kind: The rate tier (general / reduced / ...). on_date: The effective date for the lookup. Returns: The matching :class:`aeat.domain.iva.IvaRateRecord`. Raises: IvaRateNotFoundError: If no registered rate satisfies the query. """rates=load_iva_rate_table().get(member_state)ifnotrates:raiseIvaRateNotFoundError(f"no rates registered for member_state={member_state.value!r}")forrateinrates:ifrate.kindisnotkind:continueifrate.effective_from>on_date:continueifrate.effective_untilisnotNoneandon_date>rate.effective_until:continuereturnrateraiseIvaRateNotFoundError(f"no rate for member_state={member_state.value!r} kind={kind.value!r} on_date={on_date.isoformat()}",)
[docs]defcite(category:IvaCategory,*,on:date|None=None,catalogue:IvaCatalogue|None=None,)->str:"""Return the canonical citation string for ``category``. Uses the first :class:`aeat.domain.iva.IvaCitation` on the matching regulation as the canonical reference. The result includes a human-readable source label and the article reference so it is self-identifying when written to a log line. Args: category: The IVA category whose canonical citation is requested. on: Effective date used to resolve the committed catalogue. catalogue: Optional catalogue override. Returns: A canonical citation string such as ``"Ley 37/1992, Art. 90.Uno — <quoted_text>"``. Raises: IvaCatalogueError: If both ``catalogue`` and ``on`` are ``None``. """ifcatalogueisNoneandonisNone:raiseIvaCatalogueError("cite requires either an explicit catalogue or an effective date")ifonisNone:assertcatalogueisnotNonereturn_render_citation(category,catalogue)return_render_citation(category,catalogueifcatalogueisnotNoneelseresolve_catalogue(on=on))
def_render_citation(category:IvaCategory,catalogue:IvaCatalogue)->str:regulation=catalogue.get(category)ifregulationisNone:raiseIvaCategoryNotFoundError(f"IVA category {category.value!r} not found in catalogue")citation=regulation.citations[0]source_label=_SOURCE_LABELS.get(citation.source.value,citation.source.value)returnf"{source_label}, {citation.article}: {citation.quoted_text}"_SOURCE_LABELS:dict[str,str]={"ley-37-1992":"Ley 37/1992","manual-iva-2025":"Manual práctico IVA 2025","directive-2006-112-ec":"Directive 2006/112/EC","other":"other",}"""Human-readable labels for each :class:`aeat.domain.iva.IvaCitationSource`."""__all__=["cite","lookup_rate"]