-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #92 from koblas/ca_sales_tax
fix: added CA/QST,GST,PST numbers
- Loading branch information
Showing
8 changed files
with
344 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { validate, format } from './gst'; | ||
import { InvalidLength, InvalidChecksum } from '../exceptions'; | ||
|
||
describe('ca/gst', () => { | ||
it('format:754039725 RT 0001', () => { | ||
const result = format('754039725 RT 0001'); | ||
|
||
expect(result).toEqual('754039725RT0001'); | ||
}); | ||
|
||
it('fvalidate:754039725 RT 0001', () => { | ||
const result = validate('754039725 RT 0001'); | ||
|
||
expect(result.isValid && result.compact).toEqual('754039725RT0001'); | ||
}); | ||
|
||
test.each(['807138417RT0001', '754039725 RT 0001'])('validate:%s', value => { | ||
const result = validate(value); | ||
|
||
expect(result.isValid).toEqual(true); | ||
}); | ||
|
||
it('validate:VALUE', () => { | ||
const result = validate('VALUE'); | ||
|
||
expect(result.error).toBeInstanceOf(InvalidLength); | ||
}); | ||
|
||
it('validate:754039729 RT 0001', () => { | ||
const result = validate('754039729 RT 0001'); | ||
|
||
expect(result.error).toBeInstanceOf(InvalidChecksum); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/** | ||
* GST (Canadian Sales Tax Number) | ||
* | ||
* It is the BN in a extensive form. | ||
* 9 digits - Business number to identify the business. It is the Bussines Number. | ||
* 2 alpha - A reference number to identify each account a business may have within a program type. | ||
* 4 digits - A reference number to identify each account a business may have within a program type. | ||
* | ||
* Source | ||
* https://wiki.scn.sap.com/wiki/display/CRM/Canada | ||
* https://www.canada.ca/en/revenue-agency/cra-canada.html | ||
* | ||
* ENTITY | ||
*/ | ||
|
||
import * as exceptions from '../exceptions'; | ||
import { strings } from '../util'; | ||
import { Validator, ValidateReturn } from '../types'; | ||
import { validate as bnValidate } from './bn'; | ||
|
||
function clean(input: string): ReturnType<typeof strings.cleanUnicode> { | ||
return strings.cleanUnicode(input, ' -'); | ||
} | ||
|
||
const validRe = /^\d{9}[A-Z]{2}\d{4}$/i; | ||
|
||
// const ALPHABET = '0123456789X'; | ||
|
||
const impl: Validator = { | ||
name: 'Goods and service Tax Number', | ||
localName: 'Goods and service Tax Number', | ||
abbreviation: 'GST', | ||
|
||
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 !== 15) { | ||
return { isValid: false, error: new exceptions.InvalidLength() }; | ||
} | ||
|
||
if (!validRe.test(value)) { | ||
return { isValid: false, error: new exceptions.InvalidFormat() }; | ||
} | ||
|
||
// The BN15 is the same as a GST | ||
return bnValidate(value); | ||
}, | ||
}; | ||
|
||
export const { name, localName, abbreviation, validate, format, compact } = | ||
impl; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
export * as bn from './bn'; | ||
export * as sin from './sin'; | ||
export * as gst from './gst'; | ||
export * as qst from './qst'; | ||
export * as pst from './pst'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { validate, format } from './pst'; | ||
import { InvalidLength } from '../exceptions'; | ||
|
||
describe('ca/pst', () => { | ||
it('format:PST12345678', () => { | ||
const result = format('PST12345678'); | ||
|
||
expect(result).toEqual('PST-1234-5678'); | ||
}); | ||
|
||
it('fvalidate:PST-1234-5678', () => { | ||
const result = validate('PST-1234-5678'); | ||
|
||
expect(result.isValid && result.compact).toEqual('PST12345678'); | ||
}); | ||
|
||
test.each(['PST-1234-5678'])('validate:%s', value => { | ||
const result = validate(value); | ||
|
||
expect(result.isValid).toEqual(true); | ||
}); | ||
|
||
it('validate:PST-1234-567', () => { | ||
const result = validate('PST-1234-567'); | ||
|
||
expect(result.error).toBeInstanceOf(InvalidLength); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/** | ||
* PST (Canadian BC Provincial Sales Tax) | ||
* | ||
* 3 alphanumeric (PST) | ||
* 8 digits | ||
* | ||
* Source | ||
* https://wiki.scn.sap.com/wiki/display/CRM/Canada | ||
* https://www2.gov.bc.ca/gov/content/taxes/sales-taxes/pst/register | ||
* | ||
* ENTITY | ||
*/ | ||
|
||
import * as exceptions from '../exceptions'; | ||
import { strings } from '../util'; | ||
import { Validator, ValidateReturn } from '../types'; | ||
|
||
function clean(input: string): ReturnType<typeof strings.cleanUnicode> { | ||
return strings.cleanUnicode(input, ' -'); | ||
} | ||
|
||
const validRe = /^PST\d{8}$/; | ||
|
||
// const ALPHABET = '0123456789X'; | ||
|
||
const impl: Validator = { | ||
name: 'Provincial Sales Tax', | ||
localName: '', | ||
abbreviation: 'PST', | ||
|
||
compact(input: string): string { | ||
const [value, err] = clean(input); | ||
|
||
if (err) { | ||
throw err; | ||
} | ||
|
||
return value; | ||
}, | ||
|
||
format(input: string): string { | ||
const [value] = clean(input); | ||
|
||
return strings.splitAt(value, 3, 7).join('-'); | ||
}, | ||
|
||
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() }; | ||
} | ||
|
||
return { | ||
isValid: true, | ||
compact: value, | ||
isIndividual: false, | ||
isCompany: true, | ||
}; | ||
}, | ||
}; | ||
|
||
export const { name, localName, abbreviation, validate, format, compact } = | ||
impl; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { validate, format } from './qst'; | ||
import { | ||
InvalidLength, | ||
InvalidChecksum, | ||
InvalidComponent, | ||
} from '../exceptions'; | ||
|
||
describe('ca/qst', () => { | ||
it('format:1224002901 TQ 0001', () => { | ||
const result = format('1224002901 TQ 0001'); | ||
|
||
expect(result).toEqual('1224002901TQ0001'); | ||
}); | ||
|
||
it('fvalidate:1224002901 TQ 0001', () => { | ||
const result = validate('1224002901 TQ 0001'); | ||
|
||
expect(result.isValid && result.compact).toEqual('1224002901TQ0001'); | ||
}); | ||
|
||
test.each(['1224002901 TQ 0001', '1214326422TQ0001'])( | ||
'validate:%s', | ||
value => { | ||
const result = validate(value); | ||
|
||
expect(result.isValid).toEqual(true); | ||
}, | ||
); | ||
|
||
it('validate:1224002901 TQ 000', () => { | ||
const result = validate('1224002901 TQ 000'); | ||
|
||
expect(result.error).toBeInstanceOf(InvalidLength); | ||
}); | ||
|
||
it('validate:1224002902 TQ 0001', () => { | ||
const result = validate('1224002902 TQ 0001'); | ||
|
||
expect(result.error).toBeInstanceOf(InvalidChecksum); | ||
}); | ||
|
||
it('validate:1224002901 TQ 0000', () => { | ||
const result = validate('1224002901 TQ 0000'); | ||
|
||
expect(result.error).toBeInstanceOf(InvalidComponent); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/** | ||
* QST (Quebec Sales Tax Number). | ||
* | ||
* DESCRIPTION | ||
* 10 digits - Business number to identify the business. It is the Bussines Number. | ||
* 2 alpha - QT / TQ (unclear) | ||
* 4 digits - Serial number | ||
* | ||
* Source | ||
* https://www5.services.mrq.gouv.qc.ca/mrqanonyme/g1/g1c/g1c1a_I_ValidationNoTVQ/PageIdentificationNoTVQ.aspx | ||
* https://wiki.scn.sap.com/wiki/display/CRM/Canada | ||
* | ||
* 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 validRe = /^\d{10}[a-z]{2}\d{4}$/i; | ||
|
||
// const ALPHABET = '0123456789X'; | ||
|
||
const impl: Validator = { | ||
name: 'Quebec Sales Tax Number', | ||
localName: '', | ||
abbreviation: 'QST', | ||
|
||
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 !== 16) { | ||
return { isValid: false, error: new exceptions.InvalidLength() }; | ||
} | ||
|
||
if (!validRe.test(value)) { | ||
return { isValid: false, error: new exceptions.InvalidFormat() }; | ||
} | ||
|
||
const [front, check, , serial] = strings.splitAt(value, 9, 10, 12); | ||
if (serial === '0000') { | ||
return { isValid: false, error: new exceptions.InvalidComponent() }; | ||
} | ||
|
||
const sum = weightedSum(front, { | ||
weights: [4, 3, 2, 7, 6, 5, 4, 3, 2], | ||
modulus: 11, | ||
}); | ||
|
||
if (String((11 - sum) % 10) !== check) { | ||
return { isValid: false, error: new exceptions.InvalidChecksum() }; | ||
} | ||
|
||
return { | ||
isValid: true, | ||
compact: value, | ||
isIndividual: false, | ||
isCompany: true, | ||
}; | ||
}, | ||
}; | ||
|
||
export const { name, localName, abbreviation, validate, format, compact } = | ||
impl; |