isTaxID.js 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388
  1. function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
  2. function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
  3. function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
  4. function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
  5. function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
  6. function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
  7. import assertString from './util/assertString';
  8. import * as algorithms from './util/algorithms';
  9. import isDate from './isDate';
  10. /**
  11. * TIN Validation
  12. * Validates Tax Identification Numbers (TINs) from the US, EU member states and the United Kingdom.
  13. *
  14. * EU-UK:
  15. * National TIN validity is calculated using public algorithms as made available by DG TAXUD.
  16. *
  17. * See `https://ec.europa.eu/taxation_customs/tin/specs/FS-TIN%20Algorithms-Public.docx` for more information.
  18. *
  19. * US:
  20. * An Employer Identification Number (EIN), also known as a Federal Tax Identification Number,
  21. * is used to identify a business entity.
  22. *
  23. * NOTES:
  24. * - Prefix 47 is being reserved for future use
  25. * - Prefixes 26, 27, 45, 46 and 47 were previously assigned by the Philadelphia campus.
  26. *
  27. * See `http://www.irs.gov/Businesses/Small-Businesses-&-Self-Employed/How-EINs-are-Assigned-and-Valid-EIN-Prefixes`
  28. * for more information.
  29. */
  30. // Locale functions
  31. /*
  32. * bg-BG validation function
  33. * (Edinen graždanski nomer (EGN/ЕГН), persons only)
  34. * Checks if birth date (first six digits) is valid and calculates check (last) digit
  35. */
  36. function bgBgCheck(tin) {
  37. // Extract full year, normalize month and check birth date validity
  38. var century_year = tin.slice(0, 2);
  39. var month = parseInt(tin.slice(2, 4), 10);
  40. if (month > 40) {
  41. month -= 40;
  42. century_year = "20".concat(century_year);
  43. } else if (month > 20) {
  44. month -= 20;
  45. century_year = "18".concat(century_year);
  46. } else {
  47. century_year = "19".concat(century_year);
  48. }
  49. if (month < 10) {
  50. month = "0".concat(month);
  51. }
  52. var date = "".concat(century_year, "/").concat(month, "/").concat(tin.slice(4, 6));
  53. if (!isDate(date, 'YYYY/MM/DD')) {
  54. return false;
  55. }
  56. // split digits into an array for further processing
  57. var digits = tin.split('').map(function (a) {
  58. return parseInt(a, 10);
  59. });
  60. // Calculate checksum by multiplying digits with fixed values
  61. var multip_lookup = [2, 4, 8, 5, 10, 9, 7, 3, 6];
  62. var checksum = 0;
  63. for (var i = 0; i < multip_lookup.length; i++) {
  64. checksum += digits[i] * multip_lookup[i];
  65. }
  66. checksum = checksum % 11 === 10 ? 0 : checksum % 11;
  67. return checksum === digits[9];
  68. }
  69. /**
  70. * Check if an input is a valid Canadian SIN (Social Insurance Number)
  71. *
  72. * The Social Insurance Number (SIN) is a 9 digit number that
  73. * you need to work in Canada or to have access to government programs and benefits.
  74. *
  75. * https://en.wikipedia.org/wiki/Social_Insurance_Number
  76. * https://www.canada.ca/en/employment-social-development/services/sin.html
  77. * https://www.codercrunch.com/challenge/819302488/sin-validator
  78. *
  79. * @param {string} input
  80. * @return {boolean}
  81. */
  82. function isCanadianSIN(input) {
  83. var digitsArray = input.split('');
  84. var even = digitsArray.filter(function (_, idx) {
  85. return idx % 2;
  86. }).map(function (i) {
  87. return Number(i) * 2;
  88. }).join('').split('');
  89. var total = digitsArray.filter(function (_, idx) {
  90. return !(idx % 2);
  91. }).concat(even).map(function (i) {
  92. return Number(i);
  93. }).reduce(function (acc, cur) {
  94. return acc + cur;
  95. });
  96. return total % 10 === 0;
  97. }
  98. /*
  99. * cs-CZ validation function
  100. * (Rodné číslo (RČ), persons only)
  101. * Checks if birth date (first six digits) is valid and divisibility by 11
  102. * Material not in DG TAXUD document sourced from:
  103. * -`https://lorenc.info/3MA381/overeni-spravnosti-rodneho-cisla.htm`
  104. * -`https://www.mvcr.cz/clanek/rady-a-sluzby-dokumenty-rodne-cislo.aspx`
  105. */
  106. function csCzCheck(tin) {
  107. tin = tin.replace(/\W/, '');
  108. // Extract full year from TIN length
  109. var full_year = parseInt(tin.slice(0, 2), 10);
  110. if (tin.length === 10) {
  111. if (full_year < 54) {
  112. full_year = "20".concat(full_year);
  113. } else {
  114. full_year = "19".concat(full_year);
  115. }
  116. } else {
  117. if (tin.slice(6) === '000') {
  118. return false;
  119. } // Three-zero serial not assigned before 1954
  120. if (full_year < 54) {
  121. full_year = "19".concat(full_year);
  122. } else {
  123. return false; // No 18XX years seen in any of the resources
  124. }
  125. }
  126. // Add missing zero if needed
  127. if (full_year.length === 3) {
  128. full_year = [full_year.slice(0, 2), '0', full_year.slice(2)].join('');
  129. }
  130. // Extract month from TIN and normalize
  131. var month = parseInt(tin.slice(2, 4), 10);
  132. if (month > 50) {
  133. month -= 50;
  134. }
  135. if (month > 20) {
  136. // Month-plus-twenty was only introduced in 2004
  137. if (parseInt(full_year, 10) < 2004) {
  138. return false;
  139. }
  140. month -= 20;
  141. }
  142. if (month < 10) {
  143. month = "0".concat(month);
  144. }
  145. // Check date validity
  146. var date = "".concat(full_year, "/").concat(month, "/").concat(tin.slice(4, 6));
  147. if (!isDate(date, 'YYYY/MM/DD')) {
  148. return false;
  149. }
  150. // Verify divisibility by 11
  151. if (tin.length === 10) {
  152. if (parseInt(tin, 10) % 11 !== 0) {
  153. // Some numbers up to and including 1985 are still valid if
  154. // check (last) digit equals 0 and modulo of first 9 digits equals 10
  155. var checkdigit = parseInt(tin.slice(0, 9), 10) % 11;
  156. if (parseInt(full_year, 10) < 1986 && checkdigit === 10) {
  157. if (parseInt(tin.slice(9), 10) !== 0) {
  158. return false;
  159. }
  160. } else {
  161. return false;
  162. }
  163. }
  164. }
  165. return true;
  166. }
  167. /*
  168. * de-AT validation function
  169. * (Abgabenkontonummer, persons/entities)
  170. * Verify TIN validity by calling luhnCheck()
  171. */
  172. function deAtCheck(tin) {
  173. return algorithms.luhnCheck(tin);
  174. }
  175. /*
  176. * de-DE validation function
  177. * (Steueridentifikationsnummer (Steuer-IdNr.), persons only)
  178. * Tests for single duplicate/triplicate value, then calculates ISO 7064 check (last) digit
  179. * Partial implementation of spec (same result with both algorithms always)
  180. */
  181. function deDeCheck(tin) {
  182. // Split digits into an array for further processing
  183. var digits = tin.split('').map(function (a) {
  184. return parseInt(a, 10);
  185. });
  186. // Fill array with strings of number positions
  187. var occurences = [];
  188. for (var i = 0; i < digits.length - 1; i++) {
  189. occurences.push('');
  190. for (var j = 0; j < digits.length - 1; j++) {
  191. if (digits[i] === digits[j]) {
  192. occurences[i] += j;
  193. }
  194. }
  195. }
  196. // Remove digits with one occurence and test for only one duplicate/triplicate
  197. occurences = occurences.filter(function (a) {
  198. return a.length > 1;
  199. });
  200. if (occurences.length !== 2 && occurences.length !== 3) {
  201. return false;
  202. }
  203. // In case of triplicate value only two digits are allowed next to each other
  204. if (occurences[0].length === 3) {
  205. var trip_locations = occurences[0].split('').map(function (a) {
  206. return parseInt(a, 10);
  207. });
  208. var recurrent = 0; // Amount of neighbour occurences
  209. for (var _i = 0; _i < trip_locations.length - 1; _i++) {
  210. if (trip_locations[_i] + 1 === trip_locations[_i + 1]) {
  211. recurrent += 1;
  212. }
  213. }
  214. if (recurrent === 2) {
  215. return false;
  216. }
  217. }
  218. return algorithms.iso7064Check(tin);
  219. }
  220. /*
  221. * dk-DK validation function
  222. * (CPR-nummer (personnummer), persons only)
  223. * Checks if birth date (first six digits) is valid and assigned to century (seventh) digit,
  224. * and calculates check (last) digit
  225. */
  226. function dkDkCheck(tin) {
  227. tin = tin.replace(/\W/, '');
  228. // Extract year, check if valid for given century digit and add century
  229. var year = parseInt(tin.slice(4, 6), 10);
  230. var century_digit = tin.slice(6, 7);
  231. switch (century_digit) {
  232. case '0':
  233. case '1':
  234. case '2':
  235. case '3':
  236. year = "19".concat(year);
  237. break;
  238. case '4':
  239. case '9':
  240. if (year < 37) {
  241. year = "20".concat(year);
  242. } else {
  243. year = "19".concat(year);
  244. }
  245. break;
  246. default:
  247. if (year < 37) {
  248. year = "20".concat(year);
  249. } else if (year > 58) {
  250. year = "18".concat(year);
  251. } else {
  252. return false;
  253. }
  254. break;
  255. }
  256. // Add missing zero if needed
  257. if (year.length === 3) {
  258. year = [year.slice(0, 2), '0', year.slice(2)].join('');
  259. }
  260. // Check date validity
  261. var date = "".concat(year, "/").concat(tin.slice(2, 4), "/").concat(tin.slice(0, 2));
  262. if (!isDate(date, 'YYYY/MM/DD')) {
  263. return false;
  264. }
  265. // Split digits into an array for further processing
  266. var digits = tin.split('').map(function (a) {
  267. return parseInt(a, 10);
  268. });
  269. var checksum = 0;
  270. var weight = 4;
  271. // Multiply by weight and add to checksum
  272. for (var i = 0; i < 9; i++) {
  273. checksum += digits[i] * weight;
  274. weight -= 1;
  275. if (weight === 1) {
  276. weight = 7;
  277. }
  278. }
  279. checksum %= 11;
  280. if (checksum === 1) {
  281. return false;
  282. }
  283. return checksum === 0 ? digits[9] === 0 : digits[9] === 11 - checksum;
  284. }
  285. /*
  286. * el-CY validation function
  287. * (Arithmos Forologikou Mitroou (AFM/ΑΦΜ), persons only)
  288. * Verify TIN validity by calculating ASCII value of check (last) character
  289. */
  290. function elCyCheck(tin) {
  291. // split digits into an array for further processing
  292. var digits = tin.slice(0, 8).split('').map(function (a) {
  293. return parseInt(a, 10);
  294. });
  295. var checksum = 0;
  296. // add digits in even places
  297. for (var i = 1; i < digits.length; i += 2) {
  298. checksum += digits[i];
  299. }
  300. // add digits in odd places
  301. for (var _i2 = 0; _i2 < digits.length; _i2 += 2) {
  302. if (digits[_i2] < 2) {
  303. checksum += 1 - digits[_i2];
  304. } else {
  305. checksum += 2 * (digits[_i2] - 2) + 5;
  306. if (digits[_i2] > 4) {
  307. checksum += 2;
  308. }
  309. }
  310. }
  311. return String.fromCharCode(checksum % 26 + 65) === tin.charAt(8);
  312. }
  313. /*
  314. * el-GR validation function
  315. * (Arithmos Forologikou Mitroou (AFM/ΑΦΜ), persons/entities)
  316. * Verify TIN validity by calculating check (last) digit
  317. * Algorithm not in DG TAXUD document- sourced from:
  318. * - `http://epixeirisi.gr/%CE%9A%CE%A1%CE%99%CE%A3%CE%99%CE%9C%CE%91-%CE%98%CE%95%CE%9C%CE%91%CE%A4%CE%91-%CE%A6%CE%9F%CE%A1%CE%9F%CE%9B%CE%9F%CE%93%CE%99%CE%91%CE%A3-%CE%9A%CE%91%CE%99-%CE%9B%CE%9F%CE%93%CE%99%CE%A3%CE%A4%CE%99%CE%9A%CE%97%CE%A3/23791/%CE%91%CF%81%CE%B9%CE%B8%CE%BC%CF%8C%CF%82-%CE%A6%CE%BF%CF%81%CE%BF%CE%BB%CE%BF%CE%B3%CE%B9%CE%BA%CE%BF%CF%8D-%CE%9C%CE%B7%CF%84%CF%81%CF%8E%CE%BF%CF%85`
  319. */
  320. function elGrCheck(tin) {
  321. // split digits into an array for further processing
  322. var digits = tin.split('').map(function (a) {
  323. return parseInt(a, 10);
  324. });
  325. var checksum = 0;
  326. for (var i = 0; i < 8; i++) {
  327. checksum += digits[i] * Math.pow(2, 8 - i);
  328. }
  329. return checksum % 11 % 10 === digits[8];
  330. }
  331. /*
  332. * en-GB validation function (should go here if needed)
  333. * (National Insurance Number (NINO) or Unique Taxpayer Reference (UTR),
  334. * persons/entities respectively)
  335. */
  336. /*
  337. * en-IE validation function
  338. * (Personal Public Service Number (PPS No), persons only)
  339. * Verify TIN validity by calculating check (second to last) character
  340. */
  341. function enIeCheck(tin) {
  342. var checksum = algorithms.reverseMultiplyAndSum(tin.split('').slice(0, 7).map(function (a) {
  343. return parseInt(a, 10);
  344. }), 8);
  345. if (tin.length === 9 && tin[8] !== 'W') {
  346. checksum += (tin[8].charCodeAt(0) - 64) * 9;
  347. }
  348. checksum %= 23;
  349. if (checksum === 0) {
  350. return tin[7].toUpperCase() === 'W';
  351. }
  352. return tin[7].toUpperCase() === String.fromCharCode(64 + checksum);
  353. }
  354. // Valid US IRS campus prefixes
  355. var enUsCampusPrefix = {
  356. andover: ['10', '12'],
  357. atlanta: ['60', '67'],
  358. austin: ['50', '53'],
  359. brookhaven: ['01', '02', '03', '04', '05', '06', '11', '13', '14', '16', '21', '22', '23', '25', '34', '51', '52', '54', '55', '56', '57', '58', '59', '65'],
  360. cincinnati: ['30', '32', '35', '36', '37', '38', '61'],
  361. fresno: ['15', '24'],
  362. internet: ['20', '26', '27', '45', '46', '47'],
  363. kansas: ['40', '44'],
  364. memphis: ['94', '95'],
  365. ogden: ['80', '90'],
  366. philadelphia: ['33', '39', '41', '42', '43', '46', '48', '62', '63', '64', '66', '68', '71', '72', '73', '74', '75', '76', '77', '81', '82', '83', '84', '85', '86', '87', '88', '91', '92', '93', '98', '99'],
  367. sba: ['31']
  368. };
  369. // Return an array of all US IRS campus prefixes
  370. function enUsGetPrefixes() {
  371. var prefixes = [];
  372. for (var location in enUsCampusPrefix) {
  373. // https://github.com/gotwarlost/istanbul/blob/master/ignoring-code-for-coverage.md#ignoring-code-for-coverage-purposes
  374. // istanbul ignore else
  375. if (enUsCampusPrefix.hasOwnProperty(location)) {
  376. prefixes.push.apply(prefixes, _toConsumableArray(enUsCampusPrefix[location]));
  377. }
  378. }
  379. return prefixes;
  380. }
  381. /*
  382. * en-US validation function
  383. * Verify that the TIN starts with a valid IRS campus prefix
  384. */
  385. function enUsCheck(tin) {
  386. return enUsGetPrefixes().indexOf(tin.slice(0, 2)) !== -1;
  387. }
  388. /*
  389. * es-AR validation function
  390. * Clave Única de Identificación Tributaria (CUIT/CUIL)
  391. * Sourced from:
  392. * - https://servicioscf.afip.gob.ar/publico/abc/ABCpaso2.aspx?id_nivel1=3036&id_nivel2=3040&p=Conceptos%20b%C3%A1sicos
  393. * - https://es.wikipedia.org/wiki/Clave_%C3%9Anica_de_Identificaci%C3%B3n_Tributaria
  394. */
  395. function esArCheck(tin) {
  396. var accum = 0;
  397. var digits = tin.split('');
  398. var digit = parseInt(digits.pop(), 10);
  399. for (var i = 0; i < digits.length; i++) {
  400. accum += digits[9 - i] * (2 + i % 6);
  401. }
  402. var verif = 11 - accum % 11;
  403. if (verif === 11) {
  404. verif = 0;
  405. } else if (verif === 10) {
  406. verif = 9;
  407. }
  408. return digit === verif;
  409. }
  410. /*
  411. * es-ES validation function
  412. * (Documento Nacional de Identidad (DNI)
  413. * or Número de Identificación de Extranjero (NIE), persons only)
  414. * Verify TIN validity by calculating check (last) character
  415. */
  416. function esEsCheck(tin) {
  417. // Split characters into an array for further processing
  418. var chars = tin.toUpperCase().split('');
  419. // Replace initial letter if needed
  420. if (isNaN(parseInt(chars[0], 10)) && chars.length > 1) {
  421. var lead_replace = 0;
  422. switch (chars[0]) {
  423. case 'Y':
  424. lead_replace = 1;
  425. break;
  426. case 'Z':
  427. lead_replace = 2;
  428. break;
  429. default:
  430. }
  431. chars.splice(0, 1, lead_replace);
  432. // Fill with zeros if smaller than proper
  433. } else {
  434. while (chars.length < 9) {
  435. chars.unshift(0);
  436. }
  437. }
  438. // Calculate checksum and check according to lookup
  439. var lookup = ['T', 'R', 'W', 'A', 'G', 'M', 'Y', 'F', 'P', 'D', 'X', 'B', 'N', 'J', 'Z', 'S', 'Q', 'V', 'H', 'L', 'C', 'K', 'E'];
  440. chars = chars.join('');
  441. var checksum = parseInt(chars.slice(0, 8), 10) % 23;
  442. return chars[8] === lookup[checksum];
  443. }
  444. /*
  445. * et-EE validation function
  446. * (Isikukood (IK), persons only)
  447. * Checks if birth date (century digit and six following) is valid and calculates check (last) digit
  448. * Material not in DG TAXUD document sourced from:
  449. * - `https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/tax-identification-numbers/Estonia-TIN.pdf`
  450. */
  451. function etEeCheck(tin) {
  452. // Extract year and add century
  453. var full_year = tin.slice(1, 3);
  454. var century_digit = tin.slice(0, 1);
  455. switch (century_digit) {
  456. case '1':
  457. case '2':
  458. full_year = "18".concat(full_year);
  459. break;
  460. case '3':
  461. case '4':
  462. full_year = "19".concat(full_year);
  463. break;
  464. default:
  465. full_year = "20".concat(full_year);
  466. break;
  467. }
  468. // Check date validity
  469. var date = "".concat(full_year, "/").concat(tin.slice(3, 5), "/").concat(tin.slice(5, 7));
  470. if (!isDate(date, 'YYYY/MM/DD')) {
  471. return false;
  472. }
  473. // Split digits into an array for further processing
  474. var digits = tin.split('').map(function (a) {
  475. return parseInt(a, 10);
  476. });
  477. var checksum = 0;
  478. var weight = 1;
  479. // Multiply by weight and add to checksum
  480. for (var i = 0; i < 10; i++) {
  481. checksum += digits[i] * weight;
  482. weight += 1;
  483. if (weight === 10) {
  484. weight = 1;
  485. }
  486. }
  487. // Do again if modulo 11 of checksum is 10
  488. if (checksum % 11 === 10) {
  489. checksum = 0;
  490. weight = 3;
  491. for (var _i3 = 0; _i3 < 10; _i3++) {
  492. checksum += digits[_i3] * weight;
  493. weight += 1;
  494. if (weight === 10) {
  495. weight = 1;
  496. }
  497. }
  498. if (checksum % 11 === 10) {
  499. return digits[10] === 0;
  500. }
  501. }
  502. return checksum % 11 === digits[10];
  503. }
  504. /*
  505. * fi-FI validation function
  506. * (Henkilötunnus (HETU), persons only)
  507. * Checks if birth date (first six digits plus century symbol) is valid
  508. * and calculates check (last) digit
  509. */
  510. function fiFiCheck(tin) {
  511. // Extract year and add century
  512. var full_year = tin.slice(4, 6);
  513. var century_symbol = tin.slice(6, 7);
  514. switch (century_symbol) {
  515. case '+':
  516. full_year = "18".concat(full_year);
  517. break;
  518. case '-':
  519. full_year = "19".concat(full_year);
  520. break;
  521. default:
  522. full_year = "20".concat(full_year);
  523. break;
  524. }
  525. // Check date validity
  526. var date = "".concat(full_year, "/").concat(tin.slice(2, 4), "/").concat(tin.slice(0, 2));
  527. if (!isDate(date, 'YYYY/MM/DD')) {
  528. return false;
  529. }
  530. // Calculate check character
  531. var checksum = parseInt(tin.slice(0, 6) + tin.slice(7, 10), 10) % 31;
  532. if (checksum < 10) {
  533. return checksum === parseInt(tin.slice(10), 10);
  534. }
  535. checksum -= 10;
  536. var letters_lookup = ['A', 'B', 'C', 'D', 'E', 'F', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'];
  537. return letters_lookup[checksum] === tin.slice(10);
  538. }
  539. /*
  540. * fr/nl-BE validation function
  541. * (Numéro national (N.N.), persons only)
  542. * Checks if birth date (first six digits) is valid and calculates check (last two) digits
  543. */
  544. function frBeCheck(tin) {
  545. // Zero month/day value is acceptable
  546. if (tin.slice(2, 4) !== '00' || tin.slice(4, 6) !== '00') {
  547. // Extract date from first six digits of TIN
  548. var date = "".concat(tin.slice(0, 2), "/").concat(tin.slice(2, 4), "/").concat(tin.slice(4, 6));
  549. if (!isDate(date, 'YY/MM/DD')) {
  550. return false;
  551. }
  552. }
  553. var checksum = 97 - parseInt(tin.slice(0, 9), 10) % 97;
  554. var checkdigits = parseInt(tin.slice(9, 11), 10);
  555. if (checksum !== checkdigits) {
  556. checksum = 97 - parseInt("2".concat(tin.slice(0, 9)), 10) % 97;
  557. if (checksum !== checkdigits) {
  558. return false;
  559. }
  560. }
  561. return true;
  562. }
  563. /*
  564. * fr-FR validation function
  565. * (Numéro fiscal de référence (numéro SPI), persons only)
  566. * Verify TIN validity by calculating check (last three) digits
  567. */
  568. function frFrCheck(tin) {
  569. tin = tin.replace(/\s/g, '');
  570. var checksum = parseInt(tin.slice(0, 10), 10) % 511;
  571. var checkdigits = parseInt(tin.slice(10, 13), 10);
  572. return checksum === checkdigits;
  573. }
  574. /*
  575. * fr/lb-LU validation function
  576. * (numéro d’identification personnelle, persons only)
  577. * Verify birth date validity and run Luhn and Verhoeff checks
  578. */
  579. function frLuCheck(tin) {
  580. // Extract date and check validity
  581. var date = "".concat(tin.slice(0, 4), "/").concat(tin.slice(4, 6), "/").concat(tin.slice(6, 8));
  582. if (!isDate(date, 'YYYY/MM/DD')) {
  583. return false;
  584. }
  585. // Run Luhn check
  586. if (!algorithms.luhnCheck(tin.slice(0, 12))) {
  587. return false;
  588. }
  589. // Remove Luhn check digit and run Verhoeff check
  590. return algorithms.verhoeffCheck("".concat(tin.slice(0, 11)).concat(tin[12]));
  591. }
  592. /*
  593. * hr-HR validation function
  594. * (Osobni identifikacijski broj (OIB), persons/entities)
  595. * Verify TIN validity by calling iso7064Check(digits)
  596. */
  597. function hrHrCheck(tin) {
  598. return algorithms.iso7064Check(tin);
  599. }
  600. /*
  601. * hu-HU validation function
  602. * (Adóazonosító jel, persons only)
  603. * Verify TIN validity by calculating check (last) digit
  604. */
  605. function huHuCheck(tin) {
  606. // split digits into an array for further processing
  607. var digits = tin.split('').map(function (a) {
  608. return parseInt(a, 10);
  609. });
  610. var checksum = 8;
  611. for (var i = 1; i < 9; i++) {
  612. checksum += digits[i] * (i + 1);
  613. }
  614. return checksum % 11 === digits[9];
  615. }
  616. /*
  617. * lt-LT validation function (should go here if needed)
  618. * (Asmens kodas, persons/entities respectively)
  619. * Current validation check is alias of etEeCheck- same format applies
  620. */
  621. /*
  622. * it-IT first/last name validity check
  623. * Accepts it-IT TIN-encoded names as a three-element character array and checks their validity
  624. * Due to lack of clarity between resources ("Are only Italian consonants used?
  625. * What happens if a person has X in their name?" etc.) only two test conditions
  626. * have been implemented:
  627. * Vowels may only be followed by other vowels or an X character
  628. * and X characters after vowels may only be followed by other X characters.
  629. */
  630. function itItNameCheck(name) {
  631. // true at the first occurence of a vowel
  632. var vowelflag = false;
  633. // true at the first occurence of an X AFTER vowel
  634. // (to properly handle last names with X as consonant)
  635. var xflag = false;
  636. for (var i = 0; i < 3; i++) {
  637. if (!vowelflag && /[AEIOU]/.test(name[i])) {
  638. vowelflag = true;
  639. } else if (!xflag && vowelflag && name[i] === 'X') {
  640. xflag = true;
  641. } else if (i > 0) {
  642. if (vowelflag && !xflag) {
  643. if (!/[AEIOU]/.test(name[i])) {
  644. return false;
  645. }
  646. }
  647. if (xflag) {
  648. if (!/X/.test(name[i])) {
  649. return false;
  650. }
  651. }
  652. }
  653. }
  654. return true;
  655. }
  656. /*
  657. * it-IT validation function
  658. * (Codice fiscale (TIN-IT), persons only)
  659. * Verify name, birth date and codice catastale validity
  660. * and calculate check character.
  661. * Material not in DG-TAXUD document sourced from:
  662. * `https://en.wikipedia.org/wiki/Italian_fiscal_code`
  663. */
  664. function itItCheck(tin) {
  665. // Capitalize and split characters into an array for further processing
  666. var chars = tin.toUpperCase().split('');
  667. // Check first and last name validity calling itItNameCheck()
  668. if (!itItNameCheck(chars.slice(0, 3))) {
  669. return false;
  670. }
  671. if (!itItNameCheck(chars.slice(3, 6))) {
  672. return false;
  673. }
  674. // Convert letters in number spaces back to numbers if any
  675. var number_locations = [6, 7, 9, 10, 12, 13, 14];
  676. var number_replace = {
  677. L: '0',
  678. M: '1',
  679. N: '2',
  680. P: '3',
  681. Q: '4',
  682. R: '5',
  683. S: '6',
  684. T: '7',
  685. U: '8',
  686. V: '9'
  687. };
  688. for (var _i4 = 0, _number_locations = number_locations; _i4 < _number_locations.length; _i4++) {
  689. var i = _number_locations[_i4];
  690. if (chars[i] in number_replace) {
  691. chars.splice(i, 1, number_replace[chars[i]]);
  692. }
  693. }
  694. // Extract month and day, and check date validity
  695. var month_replace = {
  696. A: '01',
  697. B: '02',
  698. C: '03',
  699. D: '04',
  700. E: '05',
  701. H: '06',
  702. L: '07',
  703. M: '08',
  704. P: '09',
  705. R: '10',
  706. S: '11',
  707. T: '12'
  708. };
  709. var month = month_replace[chars[8]];
  710. var day = parseInt(chars[9] + chars[10], 10);
  711. if (day > 40) {
  712. day -= 40;
  713. }
  714. if (day < 10) {
  715. day = "0".concat(day);
  716. }
  717. var date = "".concat(chars[6]).concat(chars[7], "/").concat(month, "/").concat(day);
  718. if (!isDate(date, 'YY/MM/DD')) {
  719. return false;
  720. }
  721. // Calculate check character by adding up even and odd characters as numbers
  722. var checksum = 0;
  723. for (var _i5 = 1; _i5 < chars.length - 1; _i5 += 2) {
  724. var char_to_int = parseInt(chars[_i5], 10);
  725. if (isNaN(char_to_int)) {
  726. char_to_int = chars[_i5].charCodeAt(0) - 65;
  727. }
  728. checksum += char_to_int;
  729. }
  730. var odd_convert = {
  731. // Maps of characters at odd places
  732. A: 1,
  733. B: 0,
  734. C: 5,
  735. D: 7,
  736. E: 9,
  737. F: 13,
  738. G: 15,
  739. H: 17,
  740. I: 19,
  741. J: 21,
  742. K: 2,
  743. L: 4,
  744. M: 18,
  745. N: 20,
  746. O: 11,
  747. P: 3,
  748. Q: 6,
  749. R: 8,
  750. S: 12,
  751. T: 14,
  752. U: 16,
  753. V: 10,
  754. W: 22,
  755. X: 25,
  756. Y: 24,
  757. Z: 23,
  758. 0: 1,
  759. 1: 0
  760. };
  761. for (var _i6 = 0; _i6 < chars.length - 1; _i6 += 2) {
  762. var _char_to_int = 0;
  763. if (chars[_i6] in odd_convert) {
  764. _char_to_int = odd_convert[chars[_i6]];
  765. } else {
  766. var multiplier = parseInt(chars[_i6], 10);
  767. _char_to_int = 2 * multiplier + 1;
  768. if (multiplier > 4) {
  769. _char_to_int += 2;
  770. }
  771. }
  772. checksum += _char_to_int;
  773. }
  774. if (String.fromCharCode(65 + checksum % 26) !== chars[15]) {
  775. return false;
  776. }
  777. return true;
  778. }
  779. /*
  780. * lv-LV validation function
  781. * (Personas kods (PK), persons only)
  782. * Check validity of birth date and calculate check (last) digit
  783. * Support only for old format numbers (not starting with '32', issued before 2017/07/01)
  784. * Material not in DG TAXUD document sourced from:
  785. * `https://boot.ritakafija.lv/forums/index.php?/topic/88314-personas-koda-algoritms-%C4%8Deksumma/`
  786. */
  787. function lvLvCheck(tin) {
  788. tin = tin.replace(/\W/, '');
  789. // Extract date from TIN
  790. var day = tin.slice(0, 2);
  791. if (day !== '32') {
  792. // No date/checksum check if new format
  793. var month = tin.slice(2, 4);
  794. if (month !== '00') {
  795. // No date check if unknown month
  796. var full_year = tin.slice(4, 6);
  797. switch (tin[6]) {
  798. case '0':
  799. full_year = "18".concat(full_year);
  800. break;
  801. case '1':
  802. full_year = "19".concat(full_year);
  803. break;
  804. default:
  805. full_year = "20".concat(full_year);
  806. break;
  807. }
  808. // Check date validity
  809. var date = "".concat(full_year, "/").concat(tin.slice(2, 4), "/").concat(day);
  810. if (!isDate(date, 'YYYY/MM/DD')) {
  811. return false;
  812. }
  813. }
  814. // Calculate check digit
  815. var checksum = 1101;
  816. var multip_lookup = [1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
  817. for (var i = 0; i < tin.length - 1; i++) {
  818. checksum -= parseInt(tin[i], 10) * multip_lookup[i];
  819. }
  820. return parseInt(tin[10], 10) === checksum % 11;
  821. }
  822. return true;
  823. }
  824. /*
  825. * mt-MT validation function
  826. * (Identity Card Number or Unique Taxpayer Reference, persons/entities)
  827. * Verify Identity Card Number structure (no other tests found)
  828. */
  829. function mtMtCheck(tin) {
  830. if (tin.length !== 9) {
  831. // No tests for UTR
  832. var chars = tin.toUpperCase().split('');
  833. // Fill with zeros if smaller than proper
  834. while (chars.length < 8) {
  835. chars.unshift(0);
  836. }
  837. // Validate format according to last character
  838. switch (tin[7]) {
  839. case 'A':
  840. case 'P':
  841. if (parseInt(chars[6], 10) === 0) {
  842. return false;
  843. }
  844. break;
  845. default:
  846. {
  847. var first_part = parseInt(chars.join('').slice(0, 5), 10);
  848. if (first_part > 32000) {
  849. return false;
  850. }
  851. var second_part = parseInt(chars.join('').slice(5, 7), 10);
  852. if (first_part === second_part) {
  853. return false;
  854. }
  855. }
  856. }
  857. }
  858. return true;
  859. }
  860. /*
  861. * nl-NL validation function
  862. * (Burgerservicenummer (BSN) or Rechtspersonen Samenwerkingsverbanden Informatie Nummer (RSIN),
  863. * persons/entities respectively)
  864. * Verify TIN validity by calculating check (last) digit (variant of MOD 11)
  865. */
  866. function nlNlCheck(tin) {
  867. return algorithms.reverseMultiplyAndSum(tin.split('').slice(0, 8).map(function (a) {
  868. return parseInt(a, 10);
  869. }), 9) % 11 === parseInt(tin[8], 10);
  870. }
  871. /*
  872. * pl-PL validation function
  873. * (Powszechny Elektroniczny System Ewidencji Ludności (PESEL)
  874. * or Numer identyfikacji podatkowej (NIP), persons/entities)
  875. * Verify TIN validity by validating birth date (PESEL) and calculating check (last) digit
  876. */
  877. function plPlCheck(tin) {
  878. // NIP
  879. if (tin.length === 10) {
  880. // Calculate last digit by multiplying with lookup
  881. var lookup = [6, 5, 7, 2, 3, 4, 5, 6, 7];
  882. var _checksum = 0;
  883. for (var i = 0; i < lookup.length; i++) {
  884. _checksum += parseInt(tin[i], 10) * lookup[i];
  885. }
  886. _checksum %= 11;
  887. if (_checksum === 10) {
  888. return false;
  889. }
  890. return _checksum === parseInt(tin[9], 10);
  891. }
  892. // PESEL
  893. // Extract full year using month
  894. var full_year = tin.slice(0, 2);
  895. var month = parseInt(tin.slice(2, 4), 10);
  896. if (month > 80) {
  897. full_year = "18".concat(full_year);
  898. month -= 80;
  899. } else if (month > 60) {
  900. full_year = "22".concat(full_year);
  901. month -= 60;
  902. } else if (month > 40) {
  903. full_year = "21".concat(full_year);
  904. month -= 40;
  905. } else if (month > 20) {
  906. full_year = "20".concat(full_year);
  907. month -= 20;
  908. } else {
  909. full_year = "19".concat(full_year);
  910. }
  911. // Add leading zero to month if needed
  912. if (month < 10) {
  913. month = "0".concat(month);
  914. }
  915. // Check date validity
  916. var date = "".concat(full_year, "/").concat(month, "/").concat(tin.slice(4, 6));
  917. if (!isDate(date, 'YYYY/MM/DD')) {
  918. return false;
  919. }
  920. // Calculate last digit by mulitplying with odd one-digit numbers except 5
  921. var checksum = 0;
  922. var multiplier = 1;
  923. for (var _i7 = 0; _i7 < tin.length - 1; _i7++) {
  924. checksum += parseInt(tin[_i7], 10) * multiplier % 10;
  925. multiplier += 2;
  926. if (multiplier > 10) {
  927. multiplier = 1;
  928. } else if (multiplier === 5) {
  929. multiplier += 2;
  930. }
  931. }
  932. checksum = 10 - checksum % 10;
  933. return checksum === parseInt(tin[10], 10);
  934. }
  935. /*
  936. * pt-BR validation function
  937. * (Cadastro de Pessoas Físicas (CPF, persons)
  938. * Cadastro Nacional de Pessoas Jurídicas (CNPJ, entities)
  939. * Both inputs will be validated
  940. */
  941. function ptBrCheck(tin) {
  942. if (tin.length === 11) {
  943. var _sum;
  944. var remainder;
  945. _sum = 0;
  946. if (
  947. // Reject known invalid CPFs
  948. tin === '11111111111' || tin === '22222222222' || tin === '33333333333' || tin === '44444444444' || tin === '55555555555' || tin === '66666666666' || tin === '77777777777' || tin === '88888888888' || tin === '99999999999' || tin === '00000000000') return false;
  949. for (var i = 1; i <= 9; i++) _sum += parseInt(tin.substring(i - 1, i), 10) * (11 - i);
  950. remainder = _sum * 10 % 11;
  951. if (remainder === 10) remainder = 0;
  952. if (remainder !== parseInt(tin.substring(9, 10), 10)) return false;
  953. _sum = 0;
  954. for (var _i8 = 1; _i8 <= 10; _i8++) _sum += parseInt(tin.substring(_i8 - 1, _i8), 10) * (12 - _i8);
  955. remainder = _sum * 10 % 11;
  956. if (remainder === 10) remainder = 0;
  957. if (remainder !== parseInt(tin.substring(10, 11), 10)) return false;
  958. return true;
  959. }
  960. if (
  961. // Reject know invalid CNPJs
  962. tin === '00000000000000' || tin === '11111111111111' || tin === '22222222222222' || tin === '33333333333333' || tin === '44444444444444' || tin === '55555555555555' || tin === '66666666666666' || tin === '77777777777777' || tin === '88888888888888' || tin === '99999999999999') {
  963. return false;
  964. }
  965. var length = tin.length - 2;
  966. var identifiers = tin.substring(0, length);
  967. var verificators = tin.substring(length);
  968. var sum = 0;
  969. var pos = length - 7;
  970. for (var _i9 = length; _i9 >= 1; _i9--) {
  971. sum += identifiers.charAt(length - _i9) * pos;
  972. pos -= 1;
  973. if (pos < 2) {
  974. pos = 9;
  975. }
  976. }
  977. var result = sum % 11 < 2 ? 0 : 11 - sum % 11;
  978. if (result !== parseInt(verificators.charAt(0), 10)) {
  979. return false;
  980. }
  981. length += 1;
  982. identifiers = tin.substring(0, length);
  983. sum = 0;
  984. pos = length - 7;
  985. for (var _i10 = length; _i10 >= 1; _i10--) {
  986. sum += identifiers.charAt(length - _i10) * pos;
  987. pos -= 1;
  988. if (pos < 2) {
  989. pos = 9;
  990. }
  991. }
  992. result = sum % 11 < 2 ? 0 : 11 - sum % 11;
  993. if (result !== parseInt(verificators.charAt(1), 10)) {
  994. return false;
  995. }
  996. return true;
  997. }
  998. /*
  999. * pt-PT validation function
  1000. * (Número de identificação fiscal (NIF), persons/entities)
  1001. * Verify TIN validity by calculating check (last) digit (variant of MOD 11)
  1002. */
  1003. function ptPtCheck(tin) {
  1004. var checksum = 11 - algorithms.reverseMultiplyAndSum(tin.split('').slice(0, 8).map(function (a) {
  1005. return parseInt(a, 10);
  1006. }), 9) % 11;
  1007. if (checksum > 9) {
  1008. return parseInt(tin[8], 10) === 0;
  1009. }
  1010. return checksum === parseInt(tin[8], 10);
  1011. }
  1012. /*
  1013. * ro-RO validation function
  1014. * (Cod Numeric Personal (CNP) or Cod de înregistrare fiscală (CIF),
  1015. * persons only)
  1016. * Verify CNP validity by calculating check (last) digit (test not found for CIF)
  1017. * Material not in DG TAXUD document sourced from:
  1018. * `https://en.wikipedia.org/wiki/National_identification_number#Romania`
  1019. */
  1020. function roRoCheck(tin) {
  1021. if (tin.slice(0, 4) !== '9000') {
  1022. // No test found for this format
  1023. // Extract full year using century digit if possible
  1024. var full_year = tin.slice(1, 3);
  1025. switch (tin[0]) {
  1026. case '1':
  1027. case '2':
  1028. full_year = "19".concat(full_year);
  1029. break;
  1030. case '3':
  1031. case '4':
  1032. full_year = "18".concat(full_year);
  1033. break;
  1034. case '5':
  1035. case '6':
  1036. full_year = "20".concat(full_year);
  1037. break;
  1038. default:
  1039. }
  1040. // Check date validity
  1041. var date = "".concat(full_year, "/").concat(tin.slice(3, 5), "/").concat(tin.slice(5, 7));
  1042. if (date.length === 8) {
  1043. if (!isDate(date, 'YY/MM/DD')) {
  1044. return false;
  1045. }
  1046. } else if (!isDate(date, 'YYYY/MM/DD')) {
  1047. return false;
  1048. }
  1049. // Calculate check digit
  1050. var digits = tin.split('').map(function (a) {
  1051. return parseInt(a, 10);
  1052. });
  1053. var multipliers = [2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9];
  1054. var checksum = 0;
  1055. for (var i = 0; i < multipliers.length; i++) {
  1056. checksum += digits[i] * multipliers[i];
  1057. }
  1058. if (checksum % 11 === 10) {
  1059. return digits[12] === 1;
  1060. }
  1061. return digits[12] === checksum % 11;
  1062. }
  1063. return true;
  1064. }
  1065. /*
  1066. * sk-SK validation function
  1067. * (Rodné číslo (RČ) or bezvýznamové identifikačné číslo (BIČ), persons only)
  1068. * Checks validity of pre-1954 birth numbers (rodné číslo) only
  1069. * Due to the introduction of the pseudo-random BIČ it is not possible to test
  1070. * post-1954 birth numbers without knowing whether they are BIČ or RČ beforehand
  1071. */
  1072. function skSkCheck(tin) {
  1073. if (tin.length === 9) {
  1074. tin = tin.replace(/\W/, '');
  1075. if (tin.slice(6) === '000') {
  1076. return false;
  1077. } // Three-zero serial not assigned before 1954
  1078. // Extract full year from TIN length
  1079. var full_year = parseInt(tin.slice(0, 2), 10);
  1080. if (full_year > 53) {
  1081. return false;
  1082. }
  1083. if (full_year < 10) {
  1084. full_year = "190".concat(full_year);
  1085. } else {
  1086. full_year = "19".concat(full_year);
  1087. }
  1088. // Extract month from TIN and normalize
  1089. var month = parseInt(tin.slice(2, 4), 10);
  1090. if (month > 50) {
  1091. month -= 50;
  1092. }
  1093. if (month < 10) {
  1094. month = "0".concat(month);
  1095. }
  1096. // Check date validity
  1097. var date = "".concat(full_year, "/").concat(month, "/").concat(tin.slice(4, 6));
  1098. if (!isDate(date, 'YYYY/MM/DD')) {
  1099. return false;
  1100. }
  1101. }
  1102. return true;
  1103. }
  1104. /*
  1105. * sl-SI validation function
  1106. * (Davčna številka, persons/entities)
  1107. * Verify TIN validity by calculating check (last) digit (variant of MOD 11)
  1108. */
  1109. function slSiCheck(tin) {
  1110. var checksum = 11 - algorithms.reverseMultiplyAndSum(tin.split('').slice(0, 7).map(function (a) {
  1111. return parseInt(a, 10);
  1112. }), 8) % 11;
  1113. if (checksum === 10) {
  1114. return parseInt(tin[7], 10) === 0;
  1115. }
  1116. return checksum === parseInt(tin[7], 10);
  1117. }
  1118. /*
  1119. * sv-SE validation function
  1120. * (Personnummer or samordningsnummer, persons only)
  1121. * Checks validity of birth date and calls luhnCheck() to validate check (last) digit
  1122. */
  1123. function svSeCheck(tin) {
  1124. // Make copy of TIN and normalize to two-digit year form
  1125. var tin_copy = tin.slice(0);
  1126. if (tin.length > 11) {
  1127. tin_copy = tin_copy.slice(2);
  1128. }
  1129. // Extract date of birth
  1130. var full_year = '';
  1131. var month = tin_copy.slice(2, 4);
  1132. var day = parseInt(tin_copy.slice(4, 6), 10);
  1133. if (tin.length > 11) {
  1134. full_year = tin.slice(0, 4);
  1135. } else {
  1136. full_year = tin.slice(0, 2);
  1137. if (tin.length === 11 && day < 60) {
  1138. // Extract full year from centenarian symbol
  1139. // Should work just fine until year 10000 or so
  1140. var current_year = new Date().getFullYear().toString();
  1141. var current_century = parseInt(current_year.slice(0, 2), 10);
  1142. current_year = parseInt(current_year, 10);
  1143. if (tin[6] === '-') {
  1144. if (parseInt("".concat(current_century).concat(full_year), 10) > current_year) {
  1145. full_year = "".concat(current_century - 1).concat(full_year);
  1146. } else {
  1147. full_year = "".concat(current_century).concat(full_year);
  1148. }
  1149. } else {
  1150. full_year = "".concat(current_century - 1).concat(full_year);
  1151. if (current_year - parseInt(full_year, 10) < 100) {
  1152. return false;
  1153. }
  1154. }
  1155. }
  1156. }
  1157. // Normalize day and check date validity
  1158. if (day > 60) {
  1159. day -= 60;
  1160. }
  1161. if (day < 10) {
  1162. day = "0".concat(day);
  1163. }
  1164. var date = "".concat(full_year, "/").concat(month, "/").concat(day);
  1165. if (date.length === 8) {
  1166. if (!isDate(date, 'YY/MM/DD')) {
  1167. return false;
  1168. }
  1169. } else if (!isDate(date, 'YYYY/MM/DD')) {
  1170. return false;
  1171. }
  1172. return algorithms.luhnCheck(tin.replace(/\W/, ''));
  1173. }
  1174. /**
  1175. * uk-UA validation function
  1176. * Verify TIN validity by calculating check (last) digit (variant of MOD 11)
  1177. */
  1178. function ukUaCheck(tin) {
  1179. // Calculate check digit
  1180. var digits = tin.split('').map(function (a) {
  1181. return parseInt(a, 10);
  1182. });
  1183. var multipliers = [-1, 5, 7, 9, 4, 6, 10, 5, 7];
  1184. var checksum = 0;
  1185. for (var i = 0; i < multipliers.length; i++) {
  1186. checksum += digits[i] * multipliers[i];
  1187. }
  1188. return checksum % 11 === 10 ? digits[9] === 0 : digits[9] === checksum % 11;
  1189. }
  1190. // Locale lookup objects
  1191. /*
  1192. * Tax id regex formats for various locales
  1193. *
  1194. * Where not explicitly specified in DG-TAXUD document both
  1195. * uppercase and lowercase letters are acceptable.
  1196. */
  1197. var taxIdFormat = {
  1198. 'bg-BG': /^\d{10}$/,
  1199. 'cs-CZ': /^\d{6}\/{0,1}\d{3,4}$/,
  1200. 'de-AT': /^\d{9}$/,
  1201. 'de-DE': /^[1-9]\d{10}$/,
  1202. 'dk-DK': /^\d{6}-{0,1}\d{4}$/,
  1203. 'el-CY': /^[09]\d{7}[A-Z]$/,
  1204. 'el-GR': /^([0-4]|[7-9])\d{8}$/,
  1205. 'en-CA': /^\d{9}$/,
  1206. 'en-GB': /^\d{10}$|^(?!GB|NK|TN|ZZ)(?![DFIQUV])[A-Z](?![DFIQUVO])[A-Z]\d{6}[ABCD ]$/i,
  1207. 'en-IE': /^\d{7}[A-W][A-IW]{0,1}$/i,
  1208. 'en-US': /^\d{2}[- ]{0,1}\d{7}$/,
  1209. 'es-AR': /(20|23|24|27|30|33|34)[0-9]{8}[0-9]/,
  1210. 'es-ES': /^(\d{0,8}|[XYZKLM]\d{7})[A-HJ-NP-TV-Z]$/i,
  1211. 'et-EE': /^[1-6]\d{6}(00[1-9]|0[1-9][0-9]|[1-6][0-9]{2}|70[0-9]|710)\d$/,
  1212. 'fi-FI': /^\d{6}[-+A]\d{3}[0-9A-FHJ-NPR-Y]$/i,
  1213. 'fr-BE': /^\d{11}$/,
  1214. 'fr-FR': /^[0-3]\d{12}$|^[0-3]\d\s\d{2}(\s\d{3}){3}$/,
  1215. // Conforms both to official spec and provided example
  1216. 'fr-LU': /^\d{13}$/,
  1217. 'hr-HR': /^\d{11}$/,
  1218. 'hu-HU': /^8\d{9}$/,
  1219. 'it-IT': /^[A-Z]{6}[L-NP-V0-9]{2}[A-EHLMPRST][L-NP-V0-9]{2}[A-ILMZ][L-NP-V0-9]{3}[A-Z]$/i,
  1220. 'lv-LV': /^\d{6}-{0,1}\d{5}$/,
  1221. // Conforms both to DG TAXUD spec and original research
  1222. 'mt-MT': /^\d{3,7}[APMGLHBZ]$|^([1-8])\1\d{7}$/i,
  1223. 'nl-NL': /^\d{9}$/,
  1224. 'pl-PL': /^\d{10,11}$/,
  1225. 'pt-BR': /(?:^\d{11}$)|(?:^\d{14}$)/,
  1226. 'pt-PT': /^\d{9}$/,
  1227. 'ro-RO': /^\d{13}$/,
  1228. 'sk-SK': /^\d{6}\/{0,1}\d{3,4}$/,
  1229. 'sl-SI': /^[1-9]\d{7}$/,
  1230. 'sv-SE': /^(\d{6}[-+]{0,1}\d{4}|(18|19|20)\d{6}[-+]{0,1}\d{4})$/,
  1231. 'uk-UA': /^\d{10}$/
  1232. };
  1233. // taxIdFormat locale aliases
  1234. taxIdFormat['lb-LU'] = taxIdFormat['fr-LU'];
  1235. taxIdFormat['lt-LT'] = taxIdFormat['et-EE'];
  1236. taxIdFormat['nl-BE'] = taxIdFormat['fr-BE'];
  1237. taxIdFormat['fr-CA'] = taxIdFormat['en-CA'];
  1238. // Algorithmic tax id check functions for various locales
  1239. var taxIdCheck = {
  1240. 'bg-BG': bgBgCheck,
  1241. 'cs-CZ': csCzCheck,
  1242. 'de-AT': deAtCheck,
  1243. 'de-DE': deDeCheck,
  1244. 'dk-DK': dkDkCheck,
  1245. 'el-CY': elCyCheck,
  1246. 'el-GR': elGrCheck,
  1247. 'en-CA': isCanadianSIN,
  1248. 'en-IE': enIeCheck,
  1249. 'en-US': enUsCheck,
  1250. 'es-AR': esArCheck,
  1251. 'es-ES': esEsCheck,
  1252. 'et-EE': etEeCheck,
  1253. 'fi-FI': fiFiCheck,
  1254. 'fr-BE': frBeCheck,
  1255. 'fr-FR': frFrCheck,
  1256. 'fr-LU': frLuCheck,
  1257. 'hr-HR': hrHrCheck,
  1258. 'hu-HU': huHuCheck,
  1259. 'it-IT': itItCheck,
  1260. 'lv-LV': lvLvCheck,
  1261. 'mt-MT': mtMtCheck,
  1262. 'nl-NL': nlNlCheck,
  1263. 'pl-PL': plPlCheck,
  1264. 'pt-BR': ptBrCheck,
  1265. 'pt-PT': ptPtCheck,
  1266. 'ro-RO': roRoCheck,
  1267. 'sk-SK': skSkCheck,
  1268. 'sl-SI': slSiCheck,
  1269. 'sv-SE': svSeCheck,
  1270. 'uk-UA': ukUaCheck
  1271. };
  1272. // taxIdCheck locale aliases
  1273. taxIdCheck['lb-LU'] = taxIdCheck['fr-LU'];
  1274. taxIdCheck['lt-LT'] = taxIdCheck['et-EE'];
  1275. taxIdCheck['nl-BE'] = taxIdCheck['fr-BE'];
  1276. taxIdCheck['fr-CA'] = taxIdCheck['en-CA'];
  1277. // Regexes for locales where characters should be omitted before checking format
  1278. var allsymbols = /[-\\\/!@#$%\^&\*\(\)\+\=\[\]]+/g;
  1279. var sanitizeRegexes = {
  1280. 'de-AT': allsymbols,
  1281. 'de-DE': /[\/\\]/g,
  1282. 'fr-BE': allsymbols
  1283. };
  1284. // sanitizeRegexes locale aliases
  1285. sanitizeRegexes['nl-BE'] = sanitizeRegexes['fr-BE'];
  1286. /*
  1287. * Validator function
  1288. * Return true if the passed string is a valid tax identification number
  1289. * for the specified locale.
  1290. * Throw an error exception if the locale is not supported.
  1291. */
  1292. export default function isTaxID(str) {
  1293. var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en-US';
  1294. assertString(str);
  1295. // Copy TIN to avoid replacement if sanitized
  1296. var strcopy = str.slice(0);
  1297. if (locale in taxIdFormat) {
  1298. if (locale in sanitizeRegexes) {
  1299. strcopy = strcopy.replace(sanitizeRegexes[locale], '');
  1300. }
  1301. if (!taxIdFormat[locale].test(strcopy)) {
  1302. return false;
  1303. }
  1304. if (locale in taxIdCheck) {
  1305. return taxIdCheck[locale](strcopy);
  1306. }
  1307. // Fallthrough; not all locales have algorithmic checks
  1308. return true;
  1309. }
  1310. throw new Error("Invalid locale '".concat(locale, "'"));
  1311. }