cadrumo.domain.iva.establishment module¶
Resolve printed country evidence to a party’s territorial scope, or to nothing.
The IVA treatment of a business invoice turns on WHERE each party is established,
so a reading pipeline that recovers amounts but not places cannot answer the
question the operation actually poses. The only country signal a read document
carries is printed: the two-letter prefix on a NIF-IVA, or the country stated in a
party’s address. This module turns that printed evidence into the closed
IvaTerritorialScope the classifier consumes – or into None, which is
the answer far more often than it looks.
A code establishes a territory only through the closed vocabulary. Every rung
on this axis is a deterministic lookup against bounded registry data, and the
country rung is no exception: a code the catalogues do not carry is an unmatched
token that fires nothing. It was once a shape check instead, so any well-formed
pair resolved to the registry-projected third-country token – and third country
on the issued side is export treatment, zero-rated, so XX, ZZ and QQ
exempted an operation silently from a value with no referent. The ISO
user-assigned ranges denote nothing by construction; shape-validity is not
reference. An unmatched token is reported rather than dropped, through
stated_country_code_status(), which separates the operator’s typo from
this codebase’s own catalogue gap.
Absence is modelled as ``None``, never as an enum member. A missing scope is
not a kind of scope, and adding an UNKNOWN member would put a value into a
closed set that every consumer’s rule table would then have to special-case. The
optional type says the same thing where the type checker can enforce it.
A wrong establishment is worse than an absent one, and it is worse in a specific direction. Resolving an unrecognised or unstated country to the domestic scope silently converts an intra-community or reverse-charge operation into a domestic one – a value that is plausible at every boundary it crosses and wrong only against the counterparty’s own declaration. That is the restrictive-default shape this codebase has been bitten by before, so the rule here is strict: this module NEVER returns a Spanish scope.
Why “ES” resolves to ``None`` rather than to the mainland. This is the
substantive limit, not a caution. ES names the Member State, and Spain
contains three different IVA territories: the peninsula and Balearics inside the
territorio de aplicación del impuesto, the Canary Islands under IGIC, and Ceuta
and Melilla under IPSI – the latter two outside LIVA entirely (Ley 37/1992 art.
3.Dos). A country code cannot distinguish them, so resolving ES to
the registry-projected mainland token would place every Canarian and Ceutan
party inside a territory their operations are not subject to, which is exactly
the silent domestic capture above. Discriminating them needs sub-national printed
evidence – the address province or postal code – which this module does not
receive and does not guess at.
So the honest reading of a Spanish prefix is “Spain, territory undetermined”, and
the honest return for it is None.
Why a country NAME needs its own rung. A code is printed only where a NIF-IVA is printed. Everywhere else the country appears in an address block as a name, in the document’s own language – “Alemania”, “Deutschland”, “Germany”. Asking a reading stage for the code would be asking it to translate, and translation is inference. So the name is transcribed verbatim and matched against a bounded vocabulary held as registry data, which is deterministic lookup; the code that yields is then handed to the same country resolver, so nothing about what a country ESTABLISHES is decided twice.
Why a STATED code needs one too, and why it is not just a wider length check.
A machine-readable invoice does not print a name; it states a code, and the
syntaxes disagree about which code system. UBL states the alpha-2 form, Facturae
the alpha-3 form – ESP where everything here is keyed ES. Handed
straight to territorial_scope_for_country() that fails the shape test and
returns None, which is indistinguishable from a document stating no country
at all: the evidence is present and parsed and establishes nothing. So the
correspondence is a column in the same registry vocabulary the names are matched
against, and country_code_for_stated_country_code() is the lookup against
it – a bounded table, never a rule turning three letters into two.
See also
IvaTerritorialScopeThe closed target this resolves into.
EUMemberStateThe Member State catalogue the EU branch is derived from.
- SPAIN_COUNTRY_CODE: Final[str]¶
The one code this module deliberately refuses to resolve.
Named rather than inlined because two things depend on agreeing about it: the resolver’s refusal, and the gate that proves the refusal holds. A literal spelled twice is the drift this codebase keeps closing.
- class StatedCountryCodeStatus(*values)[source]¶
Bases:
StrEnumWhat a well-formed alpha-2 code IS, once the closed vocabulary is asked.
The axis exists because the two ways a code can fail to name a country are different problems with different owners, and collapsing them would leave an operator unable to tell which they are looking at. It says nothing about what a country ESTABLISHES –
territorial_scope_for_country()stays the single authority on that – and nothing about codes that are not well-formed alpha-2 pairs at all, which get no status.- CATALOGUED¶
A bounded catalogue in this codebase names the code.
The one status a rung can fire from. Spain is catalogued and still establishes no scope, which is a different refusal entirely:
ESnames the Member State while the IVA territory inside it stays undetermined.
- UNASSIGNED¶
The code is in an ISO user-assigned range, so it denotes nothing.
The operator’s typo signal.
XX,ZZandQQare the forms a placeholder, a truncated field or a slipped keystroke actually takes, and no catalogue anywhere will ever resolve them.
- UNCATALOGUED¶
The code may name a real jurisdiction the bundled vocabulary omits.
A data gap somebody can close by adding the country, rather than a document defect. Reported as the weaker claim it is: the ranges above are the only codes this codebase can say denote nothing, so anything outside them that the vocabulary does not carry is reported as unknown to US rather than asserted to be meaningless. It fires no rung until the catalogue carries it.
- stated_country_code_status(stated_code, *, operation)[source]¶
Return what a stated alpha-2 code is, or
Nonewhen it is not one.The diagnostic half of the country axis.
territorial_scope_for_country()answers “what does this establish” and returnsNonefor every code outside the vocabulary; this answers “and why”, so an unmatched token reaches the operator as a string they can correct rather than as a blank.- Parameters:
stated_code (
str|None) – The code as printed or as a structured record states it, orNone. Surrounding whitespace and letter case are normalised, the same way every other reader of this axis normalises them.operation (
PinnedAuthorityOperation) – The pinned authority operation supplying the country vocabulary.
- Return type:
- Returns:
The status, or
Nonewhen nothing that could be an alpha-2 code was stated. A status is a statement ABOUT a code, so an absent field, a blank one and an address line that landed in the country slot get none: reporting those as unassigned countries would spend the operator’s attention naming a string nobody claimed was a country.- Raises:
IvaCatalogueError – When the bundled vocabulary cannot be read.
- territorial_scope_for_country(country_code, *, operation)[source]¶
Return the territorial scope a country code establishes, via the closed vocabulary.
The rung is a match against a bounded vocabulary, never a shape check. A code this codebase’s catalogues do not carry is an UNMATCHED TOKEN: it fires nothing, and the caller walks on or exhausts to an unknown scope. That is the substantive rule of this function, and it is stated here rather than at any one caller because every caller inherits it – a resolver that answered on shape would hand the same wrong establishment to each of them.
Why shape is not enough, in the direction that costs money. Any well-formed pair once resolved to the registry-projected third-country token, so
XX,ZZandQQsettled a party outside the EU – and on the issued side third country is export treatment, zero-rated. An issuer typo, a placeholder or a truncated field therefore exempted an operation silently, from evidence the ladder treated as decisive. The ISO user-assigned ranges denote nothing by construction, so deriving a tax treatment from one derives it from a value with no referent: shape-validity is not reference, which is the same lesson a checksum-valid tax identifier of the wrong entity teaches one axis over.Decisiveness does not depend on the outcome. A code outside the vocabulary fires no rung whichever way the resulting treatment would fall. Making evidence count only when its consequence is unfavourable would invert the fact-to-derivation direction – the caller would need the tax consequence before deciding whether the evidence exists – and would leave a wrong third-country answer standing wherever the outcome happened to be the over-payment one, which nothing else in this codebase watches.
- Parameters:
An ISO 3166-1 alpha-2 code as printed or as a structured record states it – a NIF-IVA prefix or an address country. Surrounding whitespace and letter case are normalised here, because a document prints what it prints; anything that is not then a well-formed alpha-2 code is treated as ABSENT rather than coerced or refused.
Absent rather than refused is the deliberate half. The core jurisdiction validator raises on malformed input, which is right for a configured value an operator supplied and wrong for a transcription of whatever a supplier chose to print: unreadable evidence is a normal outcome of reading, not an error condition. The shape is therefore checked before that validator is consulted, so the validator stays the single authority on what a well-formed code is without an exception being used for ordinary control flow.
operation (
PinnedAuthorityOperation) – The pinned authority operation supplying the country vocabulary.
- Return type:
- Returns:
the registry-projected EU-member token for a Member State other than Spain, the registry-projected third-country token for a CATALOGUED country outside that catalogue, or
Nonewhen the code is absent, malformed, Spanish, or names no country the vocabulary carries.Noneis returned for Spain BY DESIGN, not as a gap: the code names the State while the IVA territory inside it stays undetermined, and the three Spanish territories are treated differently by law. A caller needing the Spanish scope must resolve it from sub-national evidence.Nonefor an unmatched token is not silence either. A caller that must tell an operator WHY nothing resolved asksstated_country_code_status(), which separates a code that denotes nothing from one this codebase simply does not carry yet.- Raises:
IvaCatalogueError – When the bundled vocabulary cannot be read or breaks its one-name-one-country invariant. Propagated rather than softened: a corrupt bundled table is a defect, not an unestablished party.
- country_code_for_printed_tax_identifier(printed_identifier, *, operation)[source]¶
Return the alpha-2 code a printed tax IDENTIFIER names, or
None.The first rung of the establishment ladder. An intra-community IVA number leads with its Member State’s IVA prefix, so a document printing
DE811234567states a country in the one place a domestic invoice’s address block often does not.The prefix is matched against the closed IVA prefix vocabulary, and the body against that State’s published VIES structure. The prefix alone is not evidence: two leading letters occur in plenty of strings a reader might put in an identifier field, and
FRANCISCOwould otherwise place a party in France. Requiring the whole number to match the shape its own prefix claims makes the rung answer only where a real IVA number was printed.A Spanish identifier contributes nothing here, by design.
ESis absent from the prefix vocabulary because Spanish identifiers are checksum identifiers rather than structural ones – and, more deeply, because registration is not establishment: the non-residentNleader, theL/Midentifiers and theX/Y/Zseries all belong to parties registered in Spain and established elsewhere, and establishment for IVA is the sede de actividad económica (Ley 37/1992 arts. 69-70). So a Spanish-prefixed number is handed back to the ladder, where the printed address country – a statement about WHERE the party is, not about where it is registered – is what may name Spain and open the postal rung.- Parameters:
printed_identifier (
str|None) – The identifier as transcribed, orNone. Spacing and separator punctuation are normalised away, because an issuer printsBE 0123.456.789as readily asBE0123456789.operation (
PinnedAuthorityOperation) – The pinned authority operation supplying the IVA prefix vocabulary.
- Return type:
- Returns:
The ISO 3166-1 alpha-2 code –
GRfor a GreekELnumber, since the IVA prefix and the ISO code diverge there and every catalogue downstream is ISO-keyed – orNonewhen no IVA number was printed, the prefix names no Member State, or the body does not match the shape its prefix claims.
- territorial_scope_for_spanish_postal_code(postal_code, *, operation)[source]¶
Return the Spanish IVA territory a printed postal code establishes.
The sub-national half of the establishment question, and the reason the country half returns nothing for Spain. The first two digits of a Spanish postal code are the province code, so this is a lookup against the excluded territories rather than an inference about them.
- Parameters:
postal_code (
str|None) – The postal code as printed. Surrounding whitespace is normalised; anything that is not five digits is treated as absent rather than coerced, because a document prints what it prints and unreadable evidence is a normal outcome of reading.operation (
PinnedAuthorityOperation) – The pinned authority operation supplying the territorial registry.
- Return type:
- Returns:
the registry-projected Canarias or Ceuta/Melilla token for a prefix the registry excludes, and the registry-projected mainland token for a well-formed code outside those, or
Nonewhen no code was readable.Nonerather than the mainland for an absent or malformed code, and that asymmetry is the whole safety property. The peninsula is the majority population, so a default would be invisible in testing and would silently place Canarian and Ceutan parties inside a territory their operations are not subject to – the restrictive-provision-as- default failure, one level below the country axis that already refuses it.- Raises:
IvaCatalogueError – When the bundled territory registry cannot be read.
- country_code_for_stated_country_code(stated_code, *, operation)[source]¶
Return the alpha-2 code a STRUCTURED record’s country element states.
The structured counterpart of
country_code_for_printed_country_name(), and it exists for the mirror-image reason. A printed document states a country as a name; a machine-readable one states it as a code – and the syntaxes disagree about which code system. UBL states the alpha-2 form (EN16931 BT-40 / BT-55); Facturae states the alpha-3 form,ESPwhere every country surface in this codebase is keyedES.The failure this closes is silent, which is why it is a function rather than a widened length check. An alpha-3 code handed to
territorial_scope_for_country()fails its shape test and returnsNone, indistinguishable from a document that stated no country – so a Facturae invoice whoseCountryCodeelement is present, read and parsed establishes nothing, and the postal rung gated on country evidence naming Spain stays shut for the entire Spanish national format.The alpha-3 leg is a lookup against registry data, never a transformation. The correspondence is a column in the bundled country vocabulary beside the alpha-2 code it names, so a code outside that bounded table yields
Noneexactly as an unlisted printed name does. There is no rule turning three letters into two.- Parameters:
stated_code (
str|None) – The country code as the record states it, in either code system, orNone. Surrounding whitespace and letter case are normalised, because the value is machine-produced but the case convention is the issuer’s.operation (
PinnedAuthorityOperation) – The pinned authority operation supplying the country vocabulary.
- Return type:
- Returns:
The upper-case ISO 3166-1 alpha-2 code, or
Nonewhen the element is absent, malformed, or states a code in either system that the closed vocabulary does not carry.Both legs are equally bounded, and that symmetry is the point rather than an implementation detail. A stated alpha-2 code is matched against the same closed vocabulary a printed one is, so a machine-readable document establishes exactly what the identical string printed in an address block establishes – neither more nor less. A looser alpha-2 leg would let a UBL
CountryCodeofXXsettle a party outside the EU while the printed form settled nothing, and the structured reader is precisely the surface that puts machine-stated strings in front of the rung.NoneNEVER degrades to a country and above all never to Spain, for the reason every other rung refuses to: the peninsula is the majority population, so a domestic default would be invisible in testing while placing foreign parties inside the territorio de aplicación del impuesto.- Raises:
IvaCatalogueError – When the bundled vocabulary cannot be read or breaks its one-code-one-country invariant. Propagated rather than softened: a corrupt bundled table is a defect, not an unestablished party.
- record_country_code_status(stated_code, *, operation)[source]¶
Return what a country code a RECORD states is, in either ISO spelling.
The structured sibling of
stated_country_code_status(), and here for the reason that one exists at all: an unmatched token has to reach the caller as a string it can act on rather than as a blank. What differs is which spellings are admitted. That function is handed values read off a printed page, where the country slot may hold anything the reader found, so it answers only about alpha-2 and declines everything else – correctly, because calling an address line a bad country code would spend an operator’s attention naming a string nobody claimed was a country.A machine-readable record’s country ELEMENT is not that. The schema has already said the token is a country code, and the formats disagree only about which spelling they state it in: EN16931 states alpha-2 (BT-40 / BT-55) and Facturae – the Spanish national format, so the majority of this corpus – states alpha-3. So this admits both, exactly as
country_code_for_stated_country_code()already does for the resolution question, and the two stay in step by construction because this asks that function first.Four answers, in the order the evidence narrows:
a token the bundled correspondence places –
ES,ESP,DEU– isCATALOGUED;an alpha-2 token keeps whatever
stated_country_code_status()calls it, so the ISO user-assigned pairs stay the issuer’s error and a real jurisdiction the vocabulary omits stays this codebase’s own gap;an alpha-3 token in the ISO user-assigned ranges is
UNASSIGNED, on exactly the terms its alpha-2 sibling is. Judged from_USER_ASSIGNED_ALPHA3rather than from length, because the catch-all below would otherwise reportZZZas a gap in our data whileZZ– the same placeholder – reports as the issuer’s;any other three-letter alphabetic token is
UNCATALOGUED. This is the answer the alpha-2 authority structurally cannot give: a three-letter string is outside its domain entirely.
The two failure kinds must stay apart, because they are opposite instructions. A consumer sparing a declared relief on a catalogue gap and refusing it on an ISO-unassigned code depends on this distinction: collapsing them either rejects a legitimate export over a row nobody has written, or honours a relief claimed on a code with no referent. The same split decides whether the operator is sent to re-read the document or to enrol a country – and enrolling a reserved code would be ungrounded registry data.
Any three-letter token in a country element is read as a country claim, including one that is plainly something else –
EURfrom a currency field,TOTfrom a totals row. That is deliberate rather than an oversight: the schema said this element holds a country code, so a token that is not one is a document defect worth naming, and the alternative is the silence this function exists to remove. It is the one place this axis is less cautious than its printed-value sibling, and it can afford to be because the element is typed.- Parameters:
stated_code (
str|None) – The token the record’s country element carries, orNone. Surrounding whitespace and letter case are normalised, the way every reader of this axis normalises them.operation (
PinnedAuthorityOperation) – The pinned authority operation supplying the country vocabulary.
- Return type:
- Returns:
The status, or
Nonewhen the element stated nothing – absent or blank – or stated something of no country-code shape at all. Absence is not a kind of failure.- Raises:
IvaCatalogueError – When the bundled vocabulary cannot be read.
- country_code_for_printed_country_name(printed_name, *, operation)[source]¶
Return the alpha-2 code a printed country NAME establishes, or
None.The second rung of the establishment ladder, and the reason it exists: a country prints as a name in the document’s own language – “Alemania”, “Deutschland”, “Germany” – so asking a reader for
DEwould be a translation, and translation is inference. Transcribing the name verbatim and matching it against this closed vocabulary is a deterministic lookup instead, the same shape as matching a transcribed regime mención against the closed statutory vocabulary.Matching is EXACT after normalisation, not containment. A country name is a field value rather than a phrase inside prose, and containment over country names is actively wrong:
"Niger"is contained in"Nigeria"and"Guinea"in"Papua New Guinea", so a containment match would place a party in the wrong tax territory from a correctly printed name. A near miss is not a match here.- Parameters:
printed_name (
str|None) – The country name transcribed from the document, orNone. Case, surrounding and repeated whitespace, and combining accents are normalised away; nothing else is.operation (
PinnedAuthorityOperation) – The pinned authority operation supplying the country vocabulary.
- Return type:
- Returns:
The upper-case ISO 3166-1 alpha-2 code, or
Nonewhen the name is absent, blank, or not in the vocabulary.NoneNEVER degrades to a country and above all never to Spain. The peninsula is the majority population, so a domestic default would be invisible in testing while silently placing foreign parties inside the territorio de aplicación del impuesto. An unrecognised name is handed back to the ladder, which exhausts to an unknown scope and asks the operator.- Raises:
IvaCatalogueError – When the bundled vocabulary cannot be read.