Source code for aeat.application.ledger._evidence_advisory
"""Printed-vs-derived IVA advisory cross-check.A non-blocking diagnostic: when an invoice's on-host-extracted text appears toprint an IVA figure that disagrees with the registry-DERIVED IVA, surface anadvisory so the operator verifies before filing. The public:func:`printed_iva_advisory` helper feeds the ``evidence_advisory`` field on:class:`aeat.application.ledger._llm_classification.LLMSaturatedSuggestion`after the saturation path has resolved evidence through:class:`aeat.domain.transactions.PromptSpec`.The printed figure is parsed deterministically on-host from the evidence text(never emitted by the model) and is used ONLY for this advisory -- it is neverpersisted and never overrides the derived value(llm-selects-system-derives-tax-numbers / no-silent-under-declaration). Parsingis best-effort; a miss simply yields no advisory."""from__future__importannotationsimportrefromdecimalimportDecimal,InvalidOperation__all__=["printed_iva_advisory"]# "IVA" followed (within a short gap) by a Spanish- or plain-formatted amount._IVA_AMOUNT=re.compile(r"\bIVA\b[^\d-]{0,12}(\d{1,3}(?:\.\d{3})*,\d{2}|\d+,\d{2}|\d+(?:\.\d{1,2})?)",re.IGNORECASE,)def_parse_amount(raw:str)->Decimal|None:"""Parse a Spanish- or plain-formatted :class:`~decimal.Decimal` string, best-effort."""text=raw.strip()if","intext:# Spanish: dot is the thousands separator, comma the decimal.text=text.replace(".","").replace(",",".")try:returnDecimal(text)exceptInvalidOperation:returnNone
[docs]defprinted_iva_advisory(evidence_text:str|None,derived_iva_amount:Decimal|None,*,tolerance:Decimal=Decimal("0.01"),)->str|None:"""Return an advisory string when the printed IVA disagrees with the derived IVA. The comparison is a best-effort cross-check between on-host-extracted evidence text and the registry-derived IVA amount carried by :class:`aeat.application.ledger._llm_classification.LLMSaturatedSuggestion`; it never supplies a tax value for persistence. Args: evidence_text: On-host-extracted text of the attached evidence, or ``None``. derived_iva_amount: The registry-derived :class:`~decimal.Decimal` IVA amount, or ``None``. tolerance: Absolute cent :class:`~decimal.Decimal` tolerance for the comparison. Returns: A non-blocking advisory message when a printed IVA figure is found and differs from ``derived_iva_amount`` beyond ``tolerance``; otherwise ``None`` (no evidence, no derived value, no parseable printed figure, or a match). """ifnotevidence_textorderived_iva_amountisNone:returnNonematch=_IVA_AMOUNT.search(evidence_text)ifmatchisNone:returnNoneprinted=_parse_amount(match.group(1))ifprintedisNone:returnNoneifabs(printed-derived_iva_amount)>tolerance:return(f"the attached evidence appears to print an IVA of {printed} but the registry-derived "f"IVA is {derived_iva_amount}; verify the classification before filing (advisory only -- "f"the derived value is authoritative)")returnNone