cadrumo.core.identity.tax_id module

Spanish tax-identifier validation (NIF / NIE / CIF) returning canonical strings.

The Agencia Tributaria’s identifier algorithm is shared infrastructure across multiple subpackages — invoice counterparty checks, encrypted master-key NIF canaries, sanitiser fixture validation, and CLI preflight gates. Co-locating the algorithm in core.identity gives every caller a public, layer-respecting import path.

This module differs from core.identity.documents only in its return shape: validate_spanish_tax_id() yields the normalised identifier string, while validate_identity() returns the matching IdentityDocument enum member. The shape is the ONLY difference – there is one implementation of the AEAT algorithm and one CIF leader policy, both in core.identity.documents, and this function delegates to them rather than restating them. It once did restate them, and the two copies drifted into disagreeing about whether an ABEH CIF may carry a letter control; two validators answering one question differently is not a laxer reading, it is a defect with a second opinion.

Both surfaces raise IdentityError; the shared NIF/NIE checksum table is defined by core.identity.documents.

tax_id_identity_token(value)[source]

Return the canonical identity form of a tax identifier, without a checksum claim.

The one comparison form for tax identifiers whose bearer is not guaranteed to be Spanish – a non-resident counterparty may carry a foreign identifier, so validate_spanish_tax_id()’s checksum gate would refuse a legitimately declared row. This function answers only “are these two identifiers the same identifier”, which is what grouping keys, distinct counts, and storage object keys need.

Normalisation is trim-and-uppercase and nothing more: it is idempotent, so a value already in canonical form is returned unchanged, and it never silently merges two identifiers that differ in their characters.

Applying it at the model boundary AND at the storage key is the point: when an aggregator groups by the raw value while the repository keys by a normalised one, two canonically-equal identifiers become two rollups but one stored row, so the declared distinct count and the persisted evidence disagree.

Parameters:

value (str) – Raw tax identifier as declared.

Return type:

str

Returns:

The trimmed, uppercased identifier.

same_tax_identifier(left, right)[source]

Return whether two declared identifiers name the same bearer.

The one “is this the same identifier” predicate. It asserts no checksum, which is the whole point: the question is identity, not validity, so a foreign identifier, or a Spanish one whose control character does not check out, must still be comparable. A comparison routed through validate_spanish_tax_id() answers False for both of those by returning nothing to compare, which reads as “different bearer” when the truth is “unverifiable identifier”.

Comparison is on the separator-stripped form (normalise_nif_iva()), so a printed B-1234567-4 matches a stored B12345674. That is deliberately looser than tax_id_identity_token(), which stays trim-and-uppercase because it keys stored objects and must never merge two characters-differ identifiers into one row; this predicate keys nothing.

Parameters:
  • left (str | None) – One identifier as declared, or None.

  • right (str | None) – The other identifier as declared, or None.

Return type:

bool

Returns:

True only when both sides carry a non-blank value and those values are the same identifier. An absent or blank side answers False: absence is not a match, and this predicate must never turn “nothing to compare” into “the same”.

validate_spanish_tax_id(value, tax_id_format)[source]

Validate a Spanish NIF, NIE, or CIF and return its canonical form.

Parameters:
  • value (str) – Raw tax identifier to validate.

  • tax_id_format (SpanishTaxIdFormat) – Complete authority-supplied format declarations.

Return type:

str

Returns:

The identifier in the package’s separator-stripped normal form – normalise_nif_iva(), the same form same_tax_identifier() compares on, so a printed B-1234567-4 and a stored B12345674 validate to one string rather than two.

Raises:

IdentityError – If the identifier is malformed or the checksum fails.

TaxIdIdentityToken