Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
name: Release

permissions:
id-token: write # Required for OIDC
contents: write

on:
#push:
# branches:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ How you can help! This library currently support about half the countries in the
| ---------------------- | ---- | --------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| Andorra | AD | NRT | Tax | Tax Register Identifier (Número de Registre Tributari) |
| Albania | AL | NIPT | Vat | Albanian Vat Identifier (Numri i Identifikimit për Personin e Tatueshëm) |
| Anguilla | AI | TIN | Tax | Tax Identification Number |
| Argentina | AR | CBU | Bank | Single Banking Code (Clave Bancaria Uniforme) |
| Argentina | AR | CUIT | Tax | Unique Tax Identification Code (Código Único de Identificación Tributaria) |
| Argentina | AR | DNI | Person | National Identity Document (Documento Nacional de Identidad) |
Expand Down
1 change: 1 addition & 0 deletions src/ai/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as tin from './tin';
54 changes: 54 additions & 0 deletions src/ai/tin.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { validate, format } from './tin';
import { InvalidLength, InvalidFormat } from '../exceptions';

describe('ai/tin', () => {
it('format:12345-67890', () => {
const result = format('1234567890');

expect(result).toEqual('12345-67890');
});

it('validate:12345-67890', () => {
const result = validate('12345-67890');

expect(result.isValid && result.compact).toEqual('1234567890');
});

test.each([
'1234567890', // Valid format
'12345-67890', // Valid format with hyphen
])('validate:%s', value => {
const result = validate(value);

expect(result.isValid).toEqual(true);
});

it('validate:12345678', () => {
const result = validate('12345678');

expect(result.error).toBeInstanceOf(InvalidLength);
});

it('validate:3234567890', () => {
const result = validate('3234567890');
expect(result.isValid).toEqual(false);
});

it('validate:123456789', () => {
const result = validate('123456789');

expect(result.error).toBeInstanceOf(InvalidLength);
});

it('validate:12345A6789', () => {
const result = validate('12345A6789');

expect(result.error).toBeInstanceOf(InvalidFormat);
});

// it('validate:123456788', () => {
// const result = validate('123456788');

// expect(result.error).toBeInstanceOf(InvalidChecksum);
// });
});
96 changes: 96 additions & 0 deletions src/ai/tin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* TIN (Anguilla Tax Identification Number).
*
* The Anguilla Tax Identification Number is issued to individuals and entities
* for tax purposes. The number consists of 10 digits in the format XXXXX-XXXXX
* where the first 5 digits represent the taxpayer's registration number and
* the last 5 digits are a sequence number (including prefix and check digit).
*
* TINs are unique numbers automatically generated by the tax administration system
* and consist of 10 digits, including prefix digit and check digit.
* - Individual TINs start with prefix 1
* - Non-Individual (business) TINs start with prefix 2
*
* Source
* https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/tax-identification-numbers/Anguilla-TIN.pdf
*
* PERSON/ENTITY
*/

import * as exceptions from '../exceptions';
import { strings } from '../util';
import { Validator, ValidateReturn } from '../types';
// import { weightedSum } from '../util/checksum';

function clean(input: string): ReturnType<typeof strings.cleanUnicode> {
return strings.cleanUnicode(input, ' -');
}

const impl: Validator = {
name: 'Anguilla Tax Identification Number',
localName: 'Tax Identification Number',
abbreviation: 'TIN',

compact(input: string): string {
const [value, err] = clean(input);

if (err) {
throw err;
}

return value;
},

format(input: string): string {
const [value] = clean(input);

if (value.length !== 10) {
return value;
}

return `${value.substring(0, 5)}-${value.substring(5)}`;
},

validate(input: string): ValidateReturn {
const [value, error] = clean(input);

if (error) {
return { isValid: false, error };
}

if (value.length !== 10) {
return { isValid: false, error: new exceptions.InvalidLength() };
}

if (!strings.isdigits(value)) {
return { isValid: false, error: new exceptions.InvalidFormat() };
}

const prefix = value[0];

if (prefix !== '1' && prefix !== '2') {
return { isValid: false, error: new exceptions.InvalidComponent() };
}

// Validate checksum
// const [front, check] = strings.splitAt(value, 8);
// const sum = weightedSum(front, {
// weights: [7, 3, 1, 7, 3, 1, 7, 3],
// modulus: 10,
// });

// if (String(sum) !== check) {
// return { isValid: false, error: new exceptions.InvalidChecksum() };
// }

return {
isValid: true,
compact: value,
isIndividual: prefix === '1',
isCompany: prefix === '2',
};
},
};

export const { name, localName, abbreviation, validate, format, compact } =
impl;
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as AD from './ad';
import * as AI from './ai';
import * as AL from './al';
import * as AR from './ar';
import * as AT from './at';
Expand Down Expand Up @@ -186,6 +187,7 @@ export const stdnum: Record<string, Record<string, Validator>> = {

export const personValidators: Record<string, Validator[]> = {
AD: [AD.nrt],
AI: [AI.tin],
AL: [AL.nipt],
AR: [AR.cuit, AR.dni],
AT: [AT.vnr],
Expand Down Expand Up @@ -214,6 +216,7 @@ export const personValidators: Record<string, Validator[]> = {
FI: [FI.hetu],
FR: [FR.nif, FR.nir],
GB: [GB.nino, GB.utr],
GH: [GH.tin],
GR: [GR.amka],
GT: [GT.cui],
HK: [HK.hkid],
Expand Down Expand Up @@ -251,14 +254,17 @@ export const personValidators: Record<string, Validator[]> = {
SV: [SV.nit],
TH: [TH.idnr],
TR: [TR.tckimlik],
TW: [TW.ubn],
UA: [UA.rntrc],
US: [US.ssn],
UY: [UY.nie, UY.cedula],
VN: [VN.mst],
ZA: [ZA.tin, ZA.idnr],
};

export const entityValidators: Record<string, Validator[]> = {
AD: [AD.nrt],
AI: [AI.tin],
AL: [AL.nipt],
AR: [AR.cuit],
AT: [AT.businessid, AT.tin, AT.uid],
Expand Down