Functional Weave
Code in TypeScript

validation.uk-vat-number@1.0.0

README.md

2,688 bytes · view raw

# validation.uk-vat-number

THE CHECKSUM IS NOT A REGISTRATION CHECK. A number that passes is arithmetically
well formed; it does not mean the trader is registered, is still registered, or
is the trader named on the invoice. Only HMRC's VAT number checker (or the EU
VIES service for cross-border supplies) can tell you that, and for a zero-rated
intra-community supply or a reverse charge you are expected to have asked and to
have kept the evidence. Use this to reject a typo before it reaches the return,
not as the evidence itself.

FORMAT: nine digits for a standard registration, or twelve for a branch trader,
where the final three identify the branch and take no part in the checksum. An
optional "GB" prefix is accepted in any case. ASCII spaces are ignored anywhere,
including leading and trailing, because HMRC prints the number as "GB 999 9999
99" and people paste it that way. Nothing else is ignored: a tab, a hyphen or a
non-breaking space makes the value invalid rather than being skipped, because
those almost always mean a bad paste that the caller should see.

THE 97 CHECK: multiply the first seven digits by the weights 8, 7, 6, 5, 4, 3, 2
and sum them. Subtract 97 from the total repeatedly until the result is zero or
negative. The absolute value of that result must equal the last two digits, read
as a two-digit number. This is HMRC's own formulation, and the implementations
are written in that shape rather than as (-total) mod 97 so that a reviewer can
hold them against the published guidance.

THE 9755 VARIANT: HMRC introduced a second series for registrations issued from
around 2010. It is the same calculation with 55 added to the weighted total
before the subtraction loop. A number is valid if it satisfies either rule, and
it can never satisfy both, because 55 is not a multiple of 97. Checking only the
older rule silently rejects about half of the registrations issued in the last
fifteen years, which is the most common bug in home-grown VAT validators.

DELIBERATE EXCLUSIONS: the GD (government department, GBGD000-GBGD499) and HA
(health authority, GBHA500-GBHA999) formats are rejected. They carry no checksum
at all, so accepting them would mean accepting any three digits behind those
letters, and a caller who needs them should test for the prefix explicitly
rather than have this function wave them through.

All-zero numbers are rejected even though 000000000 satisfies the arithmetic. No
such registration has ever been issued, and an empty placeholder field reading
as valid is a worse failure than a false negative here.

Validators answer rather than throw: an unparseable value is not an exceptional
condition, it is the answer "no".