Skip to content

Commit 7832d4a

Browse files
authored
Merge pull request #1989 from Dev1lDragon/patch-1
Update isVAT.js
2 parents 35b5ffb + bcac756 commit 7832d4a

3 files changed

Lines changed: 937 additions & 21 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ null' are accepted as valid JSON values.
170170
**isURL(str [, options])** | check if the string is an URL.<br/><br/>`options` is an object which defaults to `{ protocols: ['http','https','ftp'], require_tld: true, require_protocol: false, require_host: true, require_port: false, require_valid_protocol: true, allow_underscores: false, host_whitelist: false, host_blacklist: false, allow_trailing_dot: false, allow_protocol_relative_urls: false, allow_fragments: true, allow_query_components: true, disallow_auth: false, validate_length: true }`.<br/><br/>require_protocol - if set as true isURL will return false if protocol is not present in the URL.<br/>require_valid_protocol - isURL will check if the URL's protocol is present in the protocols option.<br/>protocols - valid protocols can be modified with this option.<br/>require_host - if set as false isURL will not check if host is present in the URL.<br/>require_port - if set as true isURL will check if port is present in the URL.<br/>allow_protocol_relative_urls - if set as true protocol relative URLs will be allowed.<br/>allow_fragments - if set as false isURL will return false if fragments are present.<br/>allow_query_components - if set as false isURL will return false if query components are present.<br/>validate_length - if set as false isURL will skip string length validation (2083 characters is IE max URL length).
171171
**isUUID(str [, version])** | check if the string is a UUID (version 1, 2, 3, 4 or 5).
172172
**isVariableWidth(str)** | check if the string contains a mixture of full and half-width chars.
173-
**isVAT(str, countryCode)** | checks that the string is a [valid VAT number](https://en.wikipedia.org/wiki/VAT_identification_number) if validation is available for the given country code matching [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). <br/><br/>Available country codes: `[ 'GB', 'IT','NL' ]`.
173+
**isVAT(str, countryCode)** | checks that the string is a [valid VAT number](https://en.wikipedia.org/wiki/VAT_identification_number) if validation is available for the given country code matching [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). <br/><br/>Available country codes: `[ 'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'EL', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'AL', 'MK', 'AU', 'BY', 'CA', 'IS', 'IN', 'ID', 'IL', 'KZ', 'NZ', 'NG', 'NO', 'PH', 'RU', 'SM', 'SA', 'RS', 'CH', 'TR', 'UA', 'GB', 'UZ', 'AR', 'BO', 'BR', 'CL', 'CO', 'CR', 'EC', 'SV', 'GT', 'HN', 'MX', 'NI', 'PA', 'PY', 'PE', 'DO', 'UY', 'VE' ]`.
174174
**isWhitelisted(str, chars)** | checks characters if they appear in the whitelist.
175175
**matches(str, pattern [, modifiers])** | check if string matches the pattern.<br/><br/>Either `matches('foo', /foo/i)` or `matches('foo', 'foo', 'i')`.
176176

src/lib/isVAT.js

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,109 @@
11
import assertString from './util/assertString';
2+
import * as algorithms from './util/algorithms';
3+
4+
const PT = (str) => {
5+
const match = str.match(/^(PT)?(\d{9})$/);
6+
if (!match) {
7+
return false;
8+
}
9+
10+
const tin = match[2];
11+
12+
const checksum = 11 - (algorithms.reverseMultiplyAndSum(tin.split('').slice(0, 8).map(a => parseInt(a, 10)), 9) % 11);
13+
if (checksum > 9) {
14+
return parseInt(tin[8], 10) === 0;
15+
}
16+
return checksum === parseInt(tin[8], 10);
17+
};
218

319
export const vatMatchers = {
4-
GB: /^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}))$/,
5-
IT: /^(IT)?[0-9]{11}$/,
6-
NL: /^(NL)?[0-9]{9}B[0-9]{2}$/,
20+
/**
21+
* European Union VAT identification numbers
22+
*/
23+
AT: str => /^(AT)?U\d{8}$/.test(str),
24+
BE: str => /^(BE)?\d{10}$/.test(str),
25+
BG: str => /^(BG)?\d{9,10}$/.test(str),
26+
HR: str => /^(HR)?\d{11}$/.test(str),
27+
CY: str => /^(CY)?\w{9}$/.test(str),
28+
CZ: str => /^(CZ)?\d{8,10}$/.test(str),
29+
DK: str => /^(DK)?\d{8}$/.test(str),
30+
EE: str => /^(EE)?\d{9}$/.test(str),
31+
FI: str => /^(FI)?\d{8}$/.test(str),
32+
FR: str => /^(FR)?\w{2}\d{9}$/.test(str),
33+
DE: str => /^(DE)?\d{9}$/.test(str),
34+
EL: str => /^(EL)?\d{9}$/.test(str),
35+
HU: str => /^(HU)?\d{8}$/.test(str),
36+
IE: str => /^(IE)?\d{7}\w{1}(W)?$/.test(str),
37+
IT: str => /^(IT)?\d{11}$/.test(str),
38+
LV: str => /^(LV)?\d{11}$/.test(str),
39+
LT: str => /^(LT)?\d{9,12}$/.test(str),
40+
LU: str => /^(LU)?\d{8}$/.test(str),
41+
MT: str => /^(MT)?\d{8}$/.test(str),
42+
NL: str => /^(NL)?\d{9}B\d{2}$/.test(str),
43+
PL: str => /^(PL)?(\d{10}|(\d{3}-\d{3}-\d{2}-\d{2})|(\d{3}-\d{2}-\d{2}-\d{3}))$/.test(str),
44+
PT,
45+
RO: str => /^(RO)?\d{2,10}$/.test(str),
46+
SK: str => /^(SK)?\d{10}$/.test(str),
47+
SI: str => /^(SI)?\d{8}$/.test(str),
48+
ES: str => /^(ES)?\w\d{7}[A-Z]$/.test(str),
49+
SE: str => /^(SE)?\d{12}$/.test(str),
50+
51+
/**
52+
* VAT numbers of non-EU countries
53+
*/
54+
AL: str => /^(AL)?\w{9}[A-Z]$/.test(str),
55+
MK: str => /^(MK)?\d{13}$/.test(str),
56+
AU: str => /^(AU)?\d{11}$/.test(str),
57+
BY: str => /^(УНП )?\d{9}$/.test(str),
58+
CA: str => /^(CA)?\d{9}$/.test(str),
59+
IS: str => /^(IS)?\d{5,6}$/.test(str),
60+
IN: str => /^(IN)?\d{15}$/.test(str),
61+
ID: str => /^(ID)?(\d{15}|(\d{2}.\d{3}.\d{3}.\d{1}-\d{3}.\d{3}))$/.test(str),
62+
IL: str => /^(IL)?\d{9}$/.test(str),
63+
KZ: str => /^(KZ)?\d{9}$/.test(str),
64+
NZ: str => /^(NZ)?\d{9}$/.test(str),
65+
NG: str => /^(NG)?(\d{12}|(\d{8}-\d{4}))$/.test(str),
66+
NO: str => /^(NO)?\d{9}MVA$/.test(str),
67+
PH: str => /^(PH)?(\d{12}|\d{3} \d{3} \d{3} \d{3})$/.test(str),
68+
RU: str => /^(RU)?(\d{10}|\d{12})$/.test(str),
69+
SM: str => /^(SM)?\d{5}$/.test(str),
70+
SA: str => /^(SA)?\d{15}$/.test(str),
71+
RS: str => /^(RS)?\d{9}$/.test(str),
72+
CH: str => /^(CH)?(\d{6}|\d{9}|(\d{3}.\d{3})|(\d{3}.\d{3}.\d{3}))(TVA|MWST|IVA)$/.test(str),
73+
TR: str => /^(TR)?\d{10}$/.test(str),
74+
UA: str => /^(UA)?\d{12}$/.test(str),
75+
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),
76+
UZ: str => /^(UZ)?\d{9}$/.test(str),
77+
78+
/**
79+
* VAT numbers of Latin American countries
80+
*/
81+
AR: str => /^(AR)?\d{11}$/.test(str),
82+
BO: str => /^(BO)?\d{7}$/.test(str),
83+
BR: str => /^(BR)?((\d{2}.\d{3}.\d{3}\/\d{4}-\d{2})|(\d{3}.\d{3}.\d{3}-\d{2}))$/.test(str),
84+
CL: str => /^(CL)?\d{8}-\d{1}$/.test(str),
85+
CO: str => /^(CO)?\d{10}$/.test(str),
86+
CR: str => /^(CR)?\d{9,12}$/.test(str),
87+
EC: str => /^(EC)?\d{13}$/.test(str),
88+
SV: str => /^(SV)?\d{4}-\d{6}-\d{3}-\d{1}$/.test(str),
89+
GT: str => /^(GT)?\d{7}-\d{1}$/.test(str),
90+
HN: str => /^(HN)?$/.test(str),
91+
MX: str => /^(MX)?\w{3,4}\d{6}\w{3}$/.test(str),
92+
NI: str => /^(NI)?\d{3}-\d{6}-\d{4}\w{1}$/.test(str),
93+
PA: str => /^(PA)?$/.test(str),
94+
PY: str => /^(PY)?\d{6,8}-\d{1}$/.test(str),
95+
PE: str => /^(PE)?\d{11}$/.test(str),
96+
DO: str => /^(DO)?(\d{11}|(\d{3}-\d{7}-\d{1})|[1,4,5]{1}\d{8}|([1,4,5]{1})-\d{2}-\d{5}-\d{1})$/.test(str),
97+
UY: str => /^(UY)?\d{12}$/.test(str),
98+
VE: str => /^(VE)?[J,G,V,E]{1}-(\d{9}|(\d{8}-\d{1}))$/.test(str),
799
};
8100

9101
export default function isVAT(str, countryCode) {
10102
assertString(str);
11103
assertString(countryCode);
12104

13105
if (countryCode in vatMatchers) {
14-
return vatMatchers[countryCode].test(str);
106+
return vatMatchers[countryCode](str);
15107
}
16108
throw new Error(`Invalid country code: '${countryCode}'`);
17109
}

0 commit comments

Comments
 (0)