Skip to content

Commit

Permalink
Merge pull request #82 from koblas/gh_tin
Browse files Browse the repository at this point in the history
fix: added gh/tin
  • Loading branch information
koblas authored Jul 6, 2023
2 parents 6a60e24 + 0572dd2 commit 9a612f0
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ All country validators are in the "namespace" of the ISO country code.
| Great Britain | GB | NINO | Person | NINO (United Kingdom National Insurance Number) |
| Great Britain | GB | UTR | Person | UTR (United Kingdom Unique Taxpayer Reference) |
| Great Britain | GB | VAT | Company | VAT (United Kingdom (and Isle of Man) VAT registration number) |
| Ghana | GH | TIN | Person/Company | Taxpayer Identification Number, Ghana tax number |
| Guinea | GN | NIFP | Person/Company | Numéro d'Identification Fiscale Permanent, Guinea tax number |
| Greece | GR | AMKA | Company | AMKA (Αριθμός Μητρώου Κοινωνικής Ασφάλισης, Greek social security number) |
| Guatemala | GT | CUI | Person | Guatemala person (Código Único de Identificación) |
| Guatemala | GT | NIT | Company | Guatemala company tax number (Número de Identificación Tributaria) |
| Guinea | GN | NIFP | Person/Company | Numéro d'Identification Fiscale Permanent, Guinea tax number |
| Greece | GR | VAT | Company | FPA, ΦΠΑ, ΑΦΜ (Αριθμός Φορολογικού Μητρώου, the Greek VAT number) |
| France | FR | NIR | Person | NIR (French personal identification number) |
| France | FR | SIREN | Company | SIREN (a French company identification number) |
Expand Down
1 change: 1 addition & 0 deletions src/gh/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as tin from './tin';
42 changes: 42 additions & 0 deletions src/gh/tin.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { validate, format } from './tin';
import { InvalidLength, InvalidChecksum } from '../exceptions';

describe('gn/tin', () => {
it('format:C0000803561', () => {
const result = format('C0000803561');

expect(result).toEqual('C0000803561');
});

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

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

test.each([
'C0000803561',
'C0002147866',
'C001095242X',
'C000366497X',
'G0061140708',
'V0003107108',
'P0008816751',
])('validate:%s', value => {
const result = validate(value);

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

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

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

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

expect(result.error).toBeInstanceOf(InvalidChecksum);
});
});
93 changes: 93 additions & 0 deletions src/gh/tin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* TIN (Taxpayer Identification Number, Ghana tax number).
*
* This number is issued by the Ghana Revenue Authority (GRA) to individuals who
* are not eligible for the Ghanacard PIN and other entities.
* This number consists of 11 alpha-numeric characters. It begins with one of the
* following prefixes:
* P00 For Individuals.
* C00 For Companies limited by guarantee, shares, Unlimited (i.e organisation
* required to register with the RGD).
* G00 Government Agencies, MDAs.
* Q00 Foreign Missions, Employees of foreign missions.
* V00 Public Institutions, Trusts, Co-operatives, Foreign Shareholder
* (Offshore), (Entities not registered by RGD).
*
* Source
* https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/tax-identification-numbers/Ghana-TIN.pdf
* https://gra.gov.gh/tin/
* https://gra.gov.gh/tin/tin-faq/
* ENTITY/PERSON
*/

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 validRe = /^[PCGQV]{1}00[A-Z0-9]{8}$/;

const ALPHABET = '0123456789X';

const impl: Validator = {
name: 'Taxpayer Identification Number',
localName: '',
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);

return value;
},

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

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

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

const [, front, check] = strings.splitAt(value, 1, 10);

const sum = weightedSum(front, {
weights: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
modulus: 11,
});

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

return {
isValid: true,
compact: value,
isIndividual: value[0] === 'P',
isCompany: value[0] !== 'P',
};
},
};

export const { name, localName, abbreviation, validate, format, compact } =
impl;
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import * as ES from './es';
import * as FI from './fi';
import * as FR from './fr';
import * as GB from './gb';
import * as GH from './gh';
import * as GR from './gr';
import * as GN from './gn';
import * as GT from './gt';
Expand Down Expand Up @@ -117,6 +118,7 @@ export const stdnum: Record<string, Record<string, Validator>> = {
FI,
FR,
GB,
GH,
GR,
GN,
GT,
Expand Down

0 comments on commit 9a612f0

Please sign in to comment.