Skip to content
This repository was archived by the owner on Jan 26, 2024. It is now read-only.

Commit 9985cde

Browse files
authored
feat: norwegian account, organization and national identification number validation
* add mod 11 function * add isValidAccountNumber * add organization number validator * make mod11 more generic * add checksum validation to birth number * linting * formatting * move mod11 to utils module * prettier * Specify nationality on account, organization and national identification numbers
1 parent 2aed1b8 commit 9985cde

8 files changed

+147
-0
lines changed

src/utils/mod11.test.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import each from 'jest-each';
2+
3+
import { mod11 } from './mod11';
4+
5+
describe('utils', () => {
6+
describe('mod11', () => {
7+
each`
8+
value | expected
9+
${'1234567890'} | ${3}
10+
${'234567'} | ${6}
11+
`.it(
12+
'should return $expected when validating $value',
13+
({ value, expected }) => {
14+
expect(mod11(value)).toBe(expected);
15+
}
16+
);
17+
});
18+
});

src/utils/mod11.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// https://no.wikipedia.org/wiki/MOD11
2+
export const mod11 = (
3+
value: string,
4+
factors: number[] = [2, 3, 4, 5, 6, 7]
5+
): number => {
6+
const sum = value
7+
.split('')
8+
.reverse()
9+
.reduce(
10+
(acc, x, i) => acc + parseInt(x, 10) * factors[i % factors.length],
11+
0
12+
);
13+
return (11 - (sum % 11)) % 11;
14+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import each from 'jest-each';
2+
3+
import { isValidNorwegianAccountNumber } from './account-number-validator';
4+
5+
describe('account-number-validator', () => {
6+
describe('isValidNorwegianAccountNumber', () => {
7+
each`
8+
accountNumber | expected
9+
${1} | ${false}
10+
${undefined} | ${false}
11+
${null} | ${false}
12+
${'1234567890'} | ${false}
13+
${'12345678903'} | ${true}
14+
${'1234.56.78903'} | ${true}
15+
${12345678903} | ${true}
16+
`.it(
17+
'should return $expected when validating $accountNumber',
18+
({ accountNumber, expected }) => {
19+
expect(isValidNorwegianAccountNumber(accountNumber)).toBe(expected);
20+
}
21+
);
22+
});
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { mod11 } from '../../utils/mod11';
2+
3+
export const isValidNorwegianAccountNumber = (
4+
accountNumber: string
5+
): boolean => {
6+
const trimmed = ('' + accountNumber).replace(/\./g, '').trim();
7+
return (
8+
/^\d{11}$/.test(trimmed) &&
9+
mod11(trimmed.substr(0, 10)) === parseInt(trimmed.substr(-1), 10)
10+
);
11+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import each from 'jest-each';
2+
3+
import { isValidNorwegianIdentificationNumber } from './national-identification-number';
4+
5+
describe('national-identification-number', () => {
6+
describe('isValidNorwegianIdentificationNumber', () => {
7+
each`
8+
birthNumber | expected
9+
${1} | ${false}
10+
${undefined} | ${false}
11+
${null} | ${false}
12+
${'01010123476'} | ${true}
13+
${'01015780000'} | ${false}
14+
${'29029633310'} | ${true}
15+
${'47086303651'} | ${true}
16+
${47086303651} | ${true}
17+
`.it(
18+
'should return $expected when validating $birthNumber',
19+
({ birthNumber, expected }) => {
20+
expect(isValidNorwegianIdentificationNumber(birthNumber)).toBe(
21+
expected
22+
);
23+
}
24+
);
25+
});
26+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { mod11 } from '../../utils/mod11';
2+
3+
export const isValidNorwegianIdentificationNumber = (
4+
birthNumber: string
5+
): boolean => {
6+
const trimmed = ('' + birthNumber).replace(/ /g, '').trim();
7+
8+
if (!/^\d{11}$/.test(trimmed)) {
9+
return false;
10+
}
11+
12+
const checksum1 = mod11(trimmed.substr(0, 9), [2, 5, 4, 9, 8, 1, 6, 7, 3]);
13+
const checksum2 = mod11(trimmed.substr(0, 10));
14+
15+
return (
16+
checksum1 === parseInt(trimmed[9], 10) &&
17+
checksum2 === parseInt(trimmed[10], 10)
18+
);
19+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import each from 'jest-each';
2+
3+
import { isValidNorwegianOrganizationNumber } from './organization-number-validator';
4+
5+
describe('organization-number-validator', () => {
6+
describe('isValidNorwegianOrganizationNumber', () => {
7+
each`
8+
organizationNumber | expected
9+
${1} | ${false}
10+
${undefined} | ${false}
11+
${null} | ${false}
12+
${'12345678'} | ${false}
13+
${'123456785'} | ${true}
14+
${123456785} | ${true}
15+
`.it(
16+
'should return $expected when validating $organizationNumber',
17+
({ organizationNumber, expected }) => {
18+
expect(isValidNorwegianOrganizationNumber(organizationNumber)).toBe(
19+
expected
20+
);
21+
}
22+
);
23+
});
24+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { mod11 } from '../../utils/mod11';
2+
3+
// https://www.brreg.no/om-oss/oppgavene-vare/alle-registrene-vare/om-enhetsregisteret/organisasjonsnummeret/
4+
export const isValidNorwegianOrganizationNumber = (
5+
OrganizationNumber: string
6+
): boolean => {
7+
const trimmed = ('' + OrganizationNumber).replace(/\./g, '').trim();
8+
return (
9+
/^\d{9}$/.test(trimmed) &&
10+
mod11(trimmed.substr(0, 8)) === parseInt(trimmed.substr(-1), 10)
11+
);
12+
};

0 commit comments

Comments
 (0)