Skip to content

Commit

Permalink
extract vat matcher for Switzerland (CH)
Browse files Browse the repository at this point in the history
- adjust number separation rule
- edit comments in test
  • Loading branch information
jimmyorpheus committed Mar 21, 2023
1 parent c3a4336 commit 823323e
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 17 deletions.
30 changes: 16 additions & 14 deletions src/lib/isVAT.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
import assertString from './util/assertString';
import * as algorithms from './util/algorithms';

const CH = (str) => {
// @see {@link https://www.ech.ch/de/ech/ech-0097/5.2.0}
const hasValidCheckNumber = (digits) => {
const lastDigit = digits.pop(); // used as check number
const weights = [5, 4, 3, 2, 7, 6, 5, 4];
const calculatedCheckNumber = (11 - (digits.reduce((acc, el, idx) =>
acc + (el * weights[idx]), 0) % 11)) % 11;

return lastDigit === calculatedCheckNumber;
};

// @see {@link https://www.estv.admin.ch/estv/de/home/mehrwertsteuer/uid/mwst-uid-nummer.html}
return /^(CHE[- ]?)?(\d{9}|(\d{3}\.\d{3}\.\d{3})|(\d{3} \d{3} \d{3})) ?(TVA|MWST|IVA)?$/.test(str) && hasValidCheckNumber((str.match(/\d/g).map(el => +el)));
};

const PT = (str) => {
const match = str.match(/^(PT)?(\d{9})$/);
if (!match) {
Expand Down Expand Up @@ -69,20 +84,7 @@ export const vatMatchers = {
SM: str => /^(SM)?\d{5}$/.test(str),
SA: str => /^(SA)?\d{15}$/.test(str),
RS: str => /^(RS)?\d{9}$/.test(str),
CH: (str) => {
// @see {@link https://www.ech.ch/de/ech/ech-0097/5.2.0}
const hasValidCheckNumber = (digits) => {
const lastDigit = digits.pop(); // used as check number
const weights = [5, 4, 3, 2, 7, 6, 5, 4];
const calculatedCheckNumber = (11 - (digits.reduce((acc, el, idx) =>
acc + (el * weights[idx]), 0) % 11)) % 11;

return lastDigit === calculatedCheckNumber;
};

// @see {@link https://www.estv.admin.ch/estv/de/home/mehrwertsteuer/uid/mwst-uid-nummer.html}
return /^(CHE[- ]?)?(\d{9}|(\d{3}[\. ]\d{3}[\. ]\d{3})) ?(TVA|MWST|IVA)?$/.test(str) && hasValidCheckNumber((str.match(/\d/g).map(el => +el)));
},
CH,
TR: str => /^(TR)?\d{10}$/.test(str),
UA: str => /^(UA)?\d{12}$/.test(str),
GB: str => /^GB((\d{3} \d{4} ([0-8][0-9]|9[0-6]))|(\d{9} \d{3})|(((GD[0-4])|(HA[5-9]))[0-9]{2}))$/.test(str),
Expand Down
6 changes: 3 additions & 3 deletions test/validators.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13885,10 +13885,10 @@ describe('Validators', () => {
invalid: [
'CH-116.281.710 MWST', // invalid prefix (should be CHE)
'CHE-116.281 MWST', // invalid number of digits (should be 9)
'CHE-123.456.789 MWST', // invalid last digits (should match the calculated check-number 8)
'CHE-123.356.780 MWST', // invalid check-number (there are no swiss UIDs for the calculated check number 10)
'CHE-123.456.789 MWST', // invalid last digit (should match the calculated check-number 8)
'CHE-123.356.780 MWST', // invalid check-number (there are no swiss UIDs with the calculated check number 10)
'CH-116.281.710 VAT', // invalid suffix (should be MWST, IVA or TVA)
'CHE-116/281/710 IVA', // invalid number separator (should be dot or space or empty-string)
'CHE-116/281/710 IVA', // invalid number separators (should be all dots or all spaces)
],
});
test({
Expand Down

0 comments on commit 823323e

Please sign in to comment.