Source code for cadrumo.application.invoices.issuer_establishment
"""Whether the taxpayer issuing an ISSUED invoice is established in the TAI.RD 1619/2012 art. 6.1.d makes a factura simplificada's counterparty tax idmandatory in three cases. Case 3.º governs the DESTINATARIO's NIF for anoperation realised in the territorio de aplicación del impuesto [TAI] whoseissuer is established there: "operaciones que se entiendan realizadas en el[TAI] y el empresario o profesional obligado a la expedición de la facturahaya de considerarse establecido en dicho territorio."Scoped to ISSUED invoices only. The party the case asks about is whoever is"obligado a la expedición de la factura" -- the issuer -- and that partydiffers by direction: on an ISSUED invoice it is this app's own taxpayer, sothe case reduces to "does the destinatario's (the counterparty's) NIF need tobe on the document", a question this predicate can answer. On a RECEIVEDinvoice the issuer is the counterparty (the supplier), and the destinatariowhose NIF case 3.º would require is the PROFILE HOLDER -- this app's owntaxpayer, whose own NIF is not a fact this record needs to track (it isalready known) and not a field :class:`~cadrumo.domain.invoices.models.Invoice`carries. There is no second, RECEIVED-side version of this predicate tobuild; the question case 3.º asks has no unknown left to answer there.**This is not the same as "a received invoice's completeness is not ourconcern".** RD 1619/2012 art. 6.4, read together with LIVA art. 97.Uno,conditions the RIGHT TO DEDUCT the IVA soportado on holding a factura thatmeets art. 6's content requirements: "tendrá la consideración de facturaaquella que contenga todos los datos y reúna los requisitos a que se refiereeste artículo." A supplier's non-compliant invoice is very much thistaxpayer's problem -- it is the document the deduction rests on. Nothing inthis codebase currently checks whether a RECEIVED invoice is complete enoughto support the deduction it feeds; that is a real, adjacent, UNADDRESSED gapthis module does not attempt to close (it is a different question -- facturacompleteness for deduction purposes generally, not the narrow destinatario-NIF case 3.º asks about on the ISSUED side).:class:`~cadrumo.domain.invoices.models.Invoice` has nowhere to carry establishmenteven for the ISSUED side -- it is a pure domain record with no profiledependency, by design (a domain model does not reach into repository/profilestate) -- and it is not a NEW fact this app needs to learn::class:`~cadrumo.domain.deadlines.models.TaxpayerProfile` already carries:attr:`~cadrumo.domain.deadlines.models.TaxpayerProfile.fiscal_residency` (TRLIRNRRDLeg 5/2004 art. 2), which this module reads rather than duplicating.**The approximation, stated rather than hidden, with its error directionnamed.** ``fiscal_residency`` is an IRPF-RESIDENCE axis (national-level:resident in Spain vs not); TAI establishment is an IVA-TERRITORIAL axis thatexcludes Canarias (IGIC territory) and Ceuta/Melilla (IPSI territory) eventhough both are part of Spain. These are two different axes that happen tolook like one word. :class:`~cadrumo.domain.deadlines.models.TaxpayerProfile`carries no field distinguishing a Canarias- or Ceuta/Melilla-residenttaxpayer from a mainland one, so this predicate CANNOT currently tell themapart: a Canarias-resident autónomo reads ``fiscal_residency ==RESIDENT_IRPF`` (true) and is NOT established in the TAI (also true), andthis predicate returns ``True`` for both.The error direction is OVER-STRICT, which is the safer of the two possiblemistakes: for a Canarias/Ceuta/Melilla-resident issuer, this predicate wronglyreports "established" and so wrongly demands a counterparty NIF the law doesnot actually require there. It never does the reverse (it never reports"established" as ``False`` for someone who genuinely is). No``EstablecimientoPermanente``-style territorial axis exists on:class:`~cadrumo.domain.deadlines.models.TaxpayerProfile` today to close this;designing one is a real schema decision with its own blast radius and isexplicitly NOT this module's job.``test_a_canarias_or_ceuta_melilla_resident_is_a_pinned_known_limitation`` inthe test suite pins the current (wrong-but-safe) behaviour so the day thataxis is added, the test fails and points at exactly what to fix.See Also: :class:`cadrumo.domain.contribuyente.renta_codes.FiscalResidency` The two-member closed enum this predicate reads. :class:`cadrumo.domain.deadlines.models.TaxpayerProfile` Owns the per-taxpayer residency fact; one profile per bucket."""from__future__importannotationsfrom...domain.calculations.registry.renta_codes_catalogueimportfiscal_residency_requires_countryfrom...domain.deadlines.modelsimportTaxpayerProfilefrom...domain.invoices.enumsimportinvoice_class_simplificadafrom...domain.invoices.modelsimportInvoicefrom...domain.iva.classificationimportInvoiceKind_DOMESTIC_COUNTRY_CODE="ES"__all__=["issuer_established_in_tai","simplificada_requires_tax_id_for_domestic_issuer"]
[docs]defissuer_established_in_tai(profile:TaxpayerProfile)->bool:"""Return whether the taxpayer issuing invoices under ``profile`` is established in the TAI. ``fiscal_residency is None`` is treated as ``RESIDENT_IRPF``, matching the field's own documented default for engine consumers (:attr:`~cadrumo.domain.deadlines.models.TaxpayerProfile.fiscal_residency`). Args: profile: The bucket's :class:`TaxpayerProfile`. Returns: ``True`` unless the profile declares ``NON_RESIDENT_IRNR``. See the module docstring for the Canarias/Ceuta/Melilla over-strict approximation (a known, pinned limitation) and the non-resident- with-permanent-establishment carve-out this predicate does not yet model. """returnnotfiscal_residency_requires_country(profile.fiscal_residency)
[docs]defsimplificada_requires_tax_id_for_domestic_issuer(invoice:Invoice,profile:TaxpayerProfile)->bool:"""Return whether RD 1619/2012 art. 6.1.d case 3.º makes ``invoice`` need a tax id. Case 3.º applies to a domestic operation (``counterparty_country == "ES"``) whose issuer -- the :class:`TaxpayerProfile` holder passed as ``profile`` -- is established in the TAI. Scoped to :attr:`~cadrumo.domain.invoices.models.Invoice.kind` ``ISSUED`` only: case 3.º asks about the DESTINATARIO's NIF, which on an ISSUED invoice is the counterparty this predicate can evaluate; on a RECEIVED invoice the destinatario is the profile holder, whose own NIF is not a question this predicate (or this record) needs to answer -- see the module docstring for why that is not the same as declaring a received invoice's completeness out of scope generally. It is meaningful only for a factura simplificada that currently omits the tax id -- an ordinaria or rectificativa already requires one unconditionally (:mod:`cadrumo.domain.invoices`), and a simplificada that already carries one has nothing further to ask for. The ``kind`` check is defence in depth rather than the only thing preventing a false positive: :class:`~cadrumo.domain.invoices.models.Invoice`'s own class-consistency validator already refuses a received simplified invoice with no tax id, so ``counterparty_tax_id is None`` alone already implies ``kind is ISSUED`` for every :class:`~cadrumo.domain.invoices.models.Invoice` reachable through normal construction. The check is kept, and tested via a bypassed-validation construction, so this function's own contract does not silently depend on that domain invariant never changing. This is an ADVISORY-weight fact, not a construction-time or verify-time refusal: an ordinary domestic ticket with no identified customer is common, legitimate practice, and case 3.º's own destinatario-NIF requirement is the least certain of the three art. 6.1.d cases this codebase can evaluate (it rests on the residency approximation the module docstring states, over-strict for a Canarias/Ceuta/Melilla issuer). Callers should surface a positive result as a :class:`~cadrumo.core.json_contract.Notice`, never as a hard refusal. Args: invoice: The invoice to evaluate. profile: The bucket's taxpayer profile. Returns: ``True`` when the invoice is a domestic, ISSUED factura simplificada with no counterparty tax id, issued by a TAI-established taxpayer. """ifinvoice.kindisnotInvoiceKind.ISSUED:returnFalseifinvoice.invoice_class!=invoice_class_simplificada():returnFalseifinvoice.counterparty_tax_idisnotNone:returnFalseifinvoice.counterparty_country!=_DOMESTIC_COUNTRY_CODE:returnFalsereturnissuer_established_in_tai(profile)