@fin.cx/einvoice 7.1.0 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/einvoice.d.ts +10 -9
- package/dist_ts/einvoice.js +40 -10
- package/dist_ts/formats/base/base.decoder.d.ts +6 -6
- package/dist_ts/formats/base/base.decoder.js +1 -1
- package/dist_ts/formats/base/base.encoder.d.ts +4 -4
- package/dist_ts/formats/base/base.validator.d.ts +5 -0
- package/dist_ts/formats/base/base.validator.js +28 -1
- package/dist_ts/formats/cii/cii.decoder.d.ts +8 -7
- package/dist_ts/formats/cii/cii.decoder.js +8 -9
- package/dist_ts/formats/cii/cii.encoder.d.ts +7 -7
- package/dist_ts/formats/cii/cii.encoder.js +5 -5
- package/dist_ts/formats/cii/cii.validator.d.ts +11 -0
- package/dist_ts/formats/cii/cii.validator.js +35 -1
- package/dist_ts/formats/cii/facturx/facturx.decoder.d.ts +6 -4
- package/dist_ts/formats/cii/facturx/facturx.decoder.js +14 -21
- package/dist_ts/formats/cii/facturx/facturx.encoder.d.ts +5 -5
- package/dist_ts/formats/cii/facturx/facturx.encoder.js +14 -10
- package/dist_ts/formats/cii/facturx/facturx.validator.js +8 -4
- package/dist_ts/formats/cii/zugferd/zugferd.decoder.d.ts +6 -4
- package/dist_ts/formats/cii/zugferd/zugferd.decoder.js +14 -21
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.d.ts +4 -4
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.js +13 -9
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.d.ts +6 -4
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.js +14 -21
- package/dist_ts/formats/cii/zugferd/zugferd.validator.js +5 -4
- package/dist_ts/formats/converters/xml-to-einvoice.converter.d.ts +5 -0
- package/dist_ts/formats/converters/xml-to-einvoice.converter.js +11 -2
- package/dist_ts/formats/semantic/semantic.adapter.d.ts +0 -8
- package/dist_ts/formats/semantic/semantic.adapter.js +5 -34
- package/dist_ts/formats/ubl/en16931.ubl.validator.js +5 -1
- package/dist_ts/formats/ubl/generic/ubl.encoder.d.ts +4 -4
- package/dist_ts/formats/ubl/generic/ubl.encoder.js +13 -14
- package/dist_ts/formats/ubl/ubl.decoder.d.ts +8 -7
- package/dist_ts/formats/ubl/ubl.decoder.js +11 -8
- package/dist_ts/formats/ubl/ubl.encoder.d.ts +7 -7
- package/dist_ts/formats/ubl/ubl.encoder.js +5 -5
- package/dist_ts/formats/ubl/ubl.validator.d.ts +11 -0
- package/dist_ts/formats/ubl/ubl.validator.js +35 -1
- package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.d.ts +6 -4
- package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.js +14 -21
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.d.ts +4 -4
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.js +6 -6
- package/dist_ts/formats/utils/document.typecode.d.ts +18 -0
- package/dist_ts/formats/utils/document.typecode.js +52 -0
- package/dist_ts/formats/utils/unit.codes.d.ts +40 -0
- package/dist_ts/formats/utils/unit.codes.js +193 -0
- package/dist_ts/formats/validation/codelist.validator.d.ts +1 -1
- package/dist_ts/formats/validation/codelist.validator.js +10 -12
- package/dist_ts/formats/validation/en16931.business-rules.validator.js +13 -13
- package/dist_ts/formats/validation/validation.types.d.ts +0 -4
- package/dist_ts/formats/validation/validation.types.js +1 -28
- package/dist_ts/index.d.ts +7 -1
- package/dist_ts/index.js +11 -1
- package/dist_ts/interfaces/common.d.ts +11 -0
- package/dist_ts_install/download-schematron.js +3 -5
- package/package.json +7 -7
- package/readme.md +99 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/einvoice.ts +59 -18
- package/ts/formats/base/base.decoder.ts +6 -6
- package/ts/formats/base/base.encoder.ts +4 -4
- package/ts/formats/base/base.validator.ts +28 -0
- package/ts/formats/cii/cii.decoder.ts +18 -14
- package/ts/formats/cii/cii.encoder.ts +11 -11
- package/ts/formats/cii/cii.validator.ts +47 -0
- package/ts/formats/cii/facturx/facturx.decoder.ts +23 -23
- package/ts/formats/cii/facturx/facturx.encoder.ts +20 -16
- package/ts/formats/cii/facturx/facturx.validator.ts +9 -3
- package/ts/formats/cii/zugferd/zugferd.decoder.ts +23 -23
- package/ts/formats/cii/zugferd/zugferd.encoder.ts +21 -17
- package/ts/formats/cii/zugferd/zugferd.v1.decoder.ts +23 -23
- package/ts/formats/cii/zugferd/zugferd.validator.ts +4 -3
- package/ts/formats/converters/xml-to-einvoice.converter.ts +11 -1
- package/ts/formats/semantic/semantic.adapter.ts +4 -35
- package/ts/formats/ubl/en16931.ubl.validator.ts +6 -0
- package/ts/formats/ubl/generic/ubl.encoder.ts +29 -24
- package/ts/formats/ubl/ubl.decoder.ts +23 -14
- package/ts/formats/ubl/ubl.encoder.ts +11 -11
- package/ts/formats/ubl/ubl.validator.ts +47 -0
- package/ts/formats/ubl/xrechnung/xrechnung.decoder.ts +23 -23
- package/ts/formats/ubl/xrechnung/xrechnung.encoder.ts +10 -10
- package/ts/formats/utils/document.typecode.ts +62 -0
- package/ts/formats/utils/unit.codes.ts +215 -0
- package/ts/formats/validation/codelist.validator.ts +12 -23
- package/ts/formats/validation/en16931.business-rules.validator.ts +13 -13
- package/ts/formats/validation/validation.types.ts +0 -28
- package/ts/index.ts +25 -0
- package/ts/interfaces/common.ts +17 -0
- package/ts/readme.md +3 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UBLEncoder } from '../generic/ubl.encoder.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { TAccountingDoc, TCreditNote, TInvoiceDocument } from '../../../interfaces/common.js';
|
|
3
3
|
import { DOMParser, XMLSerializer } from '../../../plugins.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -18,24 +18,24 @@ export class XRechnungEncoder extends UBLEncoder {
|
|
|
18
18
|
|
|
19
19
|
// Parse and modify for XRechnung
|
|
20
20
|
const doc = new DOMParser().parseFromString(baseXml, 'application/xml');
|
|
21
|
-
this.applyXRechnungCustomizations(doc, creditNote
|
|
21
|
+
this.applyXRechnungCustomizations(doc, creditNote);
|
|
22
22
|
|
|
23
23
|
// Serialize back to string
|
|
24
24
|
return new XMLSerializer().serializeToString(doc);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Encodes
|
|
29
|
-
* @param
|
|
28
|
+
* Encodes an invoice document (invoice, debit note or self-billed invoice) into XRechnung XML
|
|
29
|
+
* @param invoice Invoice document to encode
|
|
30
30
|
* @returns XRechnung XML string
|
|
31
31
|
*/
|
|
32
|
-
protected async
|
|
32
|
+
protected async encodeInvoice(invoice: TInvoiceDocument): Promise<string> {
|
|
33
33
|
// First get the base UBL XML
|
|
34
|
-
const baseXml = await super.
|
|
34
|
+
const baseXml = await super.encodeInvoice(invoice);
|
|
35
35
|
|
|
36
36
|
// Parse and modify for XRechnung
|
|
37
37
|
const doc = new DOMParser().parseFromString(baseXml, 'application/xml');
|
|
38
|
-
this.applyXRechnungCustomizations(doc,
|
|
38
|
+
this.applyXRechnungCustomizations(doc, invoice);
|
|
39
39
|
|
|
40
40
|
// Serialize back to string
|
|
41
41
|
return new XMLSerializer().serializeToString(doc);
|
|
@@ -46,7 +46,7 @@ export class XRechnungEncoder extends UBLEncoder {
|
|
|
46
46
|
* @param doc XML document
|
|
47
47
|
* @param invoice Invoice data
|
|
48
48
|
*/
|
|
49
|
-
private applyXRechnungCustomizations(doc: Document, invoice:
|
|
49
|
+
private applyXRechnungCustomizations(doc: Document, invoice: TAccountingDoc): void {
|
|
50
50
|
const root = doc.documentElement;
|
|
51
51
|
|
|
52
52
|
// Extract metadata if available
|
|
@@ -470,7 +470,7 @@ export class XRechnungEncoder extends UBLEncoder {
|
|
|
470
470
|
* @param doc XML document
|
|
471
471
|
* @param invoice Invoice data
|
|
472
472
|
*/
|
|
473
|
-
private enhancePartyInformation(doc: Document, invoice:
|
|
473
|
+
private enhancePartyInformation(doc: Document, invoice: TAccountingDoc): void {
|
|
474
474
|
// Enhance supplier party
|
|
475
475
|
this.addContactToParty(doc, 'cac:AccountingSupplierParty', this.contactInformationOf(invoice.from));
|
|
476
476
|
|
|
@@ -553,7 +553,7 @@ export class XRechnungEncoder extends UBLEncoder {
|
|
|
553
553
|
* @param doc XML document
|
|
554
554
|
* @param invoice Invoice data
|
|
555
555
|
*/
|
|
556
|
-
private enhanceLineItems(doc: Document, invoice:
|
|
556
|
+
private enhanceLineItems(doc: Document, invoice: TAccountingDoc): void {
|
|
557
557
|
const invoiceLines = doc.getElementsByTagName('cac:InvoiceLine');
|
|
558
558
|
|
|
559
559
|
for (let i = 0; i < invoiceLines.length && i < invoice.items.length; i++) {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { TAccountingDocType } from '../../interfaces/common.js';
|
|
2
|
+
import { EInvoiceFormatError } from '../../errors.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The UNTDID 1001 document type code (BT-3) written for each accounting
|
|
6
|
+
* document type.
|
|
7
|
+
*/
|
|
8
|
+
const DOCUMENT_TYPE_CODES: Record<TAccountingDocType, string> = {
|
|
9
|
+
'invoice': '380',
|
|
10
|
+
'creditnote': '381',
|
|
11
|
+
'debitnote': '383',
|
|
12
|
+
'self-billed-invoice': '389',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const ACCOUNTING_DOC_TYPES: readonly string[] = Object.keys(DOCUMENT_TYPE_CODES);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The credit note related codes of UNTDID 1001, as EN16931 rule BR-CL-01
|
|
19
|
+
* lists them for `cbc:CreditNoteTypeCode`. Every other code BR-CL-01 admits
|
|
20
|
+
* is invoice related.
|
|
21
|
+
*/
|
|
22
|
+
const CREDIT_NOTE_TYPE_CODES: ReadonlySet<string> = new Set([
|
|
23
|
+
'81', '83', '261', '262', '296', '308', '381', '396', '420', '458', '532',
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
export const isAccountingDocType = (value: unknown): value is TAccountingDocType =>
|
|
27
|
+
typeof value === 'string' && ACCOUNTING_DOC_TYPES.includes(value);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The type code an encoder writes for an accounting document type. The field
|
|
31
|
+
* is public and takes plain objects, so a value outside the type is refused
|
|
32
|
+
* here instead of being written as an invoice.
|
|
33
|
+
*/
|
|
34
|
+
export const getDocumentTypeCode = (accountingDocType: TAccountingDocType): string => {
|
|
35
|
+
if (!isAccountingDocType(accountingDocType)) {
|
|
36
|
+
throw new EInvoiceFormatError(
|
|
37
|
+
`Unsupported accounting document type: ${String(accountingDocType)}`,
|
|
38
|
+
{ unsupportedFeatures: [`accountingDocType=${String(accountingDocType)}`] },
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return DOCUMENT_TYPE_CODES[accountingDocType];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The accounting document type of a decoded type code. 383 and 389 have a
|
|
46
|
+
* type of their own; the remaining credit note related codes are credit
|
|
47
|
+
* notes; everything else is an invoice, which covers 380, 384 and the other
|
|
48
|
+
* invoice related codes (326, 386, 875, ...) the envelope has no name for.
|
|
49
|
+
* A missing or unlisted code stays an invoice as well: the document is an
|
|
50
|
+
* invoice document, and reporting the code is the validators' job (BR-04,
|
|
51
|
+
* BR-CL-01).
|
|
52
|
+
*/
|
|
53
|
+
export const getAccountingDocType = (typeCode: string): TAccountingDocType => {
|
|
54
|
+
const code = typeCode.trim();
|
|
55
|
+
if (code === DOCUMENT_TYPE_CODES['debitnote']) {
|
|
56
|
+
return 'debitnote';
|
|
57
|
+
}
|
|
58
|
+
if (code === DOCUMENT_TYPE_CODES['self-billed-invoice']) {
|
|
59
|
+
return 'self-billed-invoice';
|
|
60
|
+
}
|
|
61
|
+
return CREDIT_NOTE_TYPE_CODES.has(code) ? 'creditnote' : 'invoice';
|
|
62
|
+
};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The unit of measure codes EN 16931 admits, as business rule BR-CL-23 lists them: UN/ECE
|
|
3
|
+
* Recommendation 20 with the Recommendation 21 extension. They apply to the invoiced quantity
|
|
4
|
+
* unit of measure (BT-130) and the item price base quantity unit of measure (BT-150).
|
|
5
|
+
*
|
|
6
|
+
* Source: the EN 16931 validation artefacts of CEN/TC 434, release validation-1.3.16
|
|
7
|
+
* (https://github.com/ConnectingEurope/eInvoicing-EN16931/releases/tag/validation-1.3.16),
|
|
8
|
+
* rule BR-CL-23 in ubl/schematron/codelist/EN16931-UBL-codes.sch and
|
|
9
|
+
* cii/schematron/codelist/EN16931-CII-codes.sch, which carry the same 2162 codes. The codes are
|
|
10
|
+
* reproduced unaltered and in the order of the rule. The source files are licensed under EUPL-1.2;
|
|
11
|
+
* the codes are those of UN/ECE Recommendations 20 and 21.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** Where the EN 16931 unit code list comes from, and the codes it holds. */
|
|
15
|
+
export interface IEn16931UnitCodeList {
|
|
16
|
+
/** the business rule that lists the codes */
|
|
17
|
+
readonly rule: 'BR-CL-23';
|
|
18
|
+
/** the business terms whose values the rule checks */
|
|
19
|
+
readonly businessTerms: readonly ['BT-130', 'BT-150'];
|
|
20
|
+
/** the code lists the codes belong to */
|
|
21
|
+
readonly codeLists: 'UN/ECE Recommendation 20 with Recommendation 21 extension';
|
|
22
|
+
/** the release of the EN 16931 validation artefacts the codes are taken from */
|
|
23
|
+
readonly source: 'EN 16931 validation artefacts (CEN/TC 434) validation-1.3.16';
|
|
24
|
+
/**
|
|
25
|
+
* the codes, in the order of the rule; the array is frozen, and the validators check against a
|
|
26
|
+
* private copy, so nothing a caller does to it changes a check
|
|
27
|
+
*/
|
|
28
|
+
readonly codes: readonly string[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const BR_CL_23_CODES: readonly string[] = Object.freeze([
|
|
32
|
+
'10', '11', '13', '14', '15', '20', '21', '22', '23', '24', '25', '27', '28', '33',
|
|
33
|
+
'34', '35', '37', '38', '40', '41', '56', '57', '58', '59', '60', '61', '74', '77',
|
|
34
|
+
'80', '81', '85', '87', '89', '91', '1I', '2A', '2B', '2C', '2G', '2H', '2I', '2J',
|
|
35
|
+
'2K', '2L', '2M', '2N', '2P', '2Q', '2R', '2U', '2X', '2Y', '2Z', '3B', '3C', '4C',
|
|
36
|
+
'4G', '4H', '4K', '4L', '4M', '4N', '4O', '4P', '4Q', '4R', '4T', '4U', '4W', '4X',
|
|
37
|
+
'5A', '5B', '5E', '5J', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',
|
|
38
|
+
'A2', 'A20', 'A21', 'A22', 'A23', 'A24', 'A26', 'A27', 'A28', 'A29', 'A3', 'A30', 'A31', 'A32',
|
|
39
|
+
'A33', 'A34', 'A35', 'A36', 'A37', 'A38', 'A39', 'A4', 'A40', 'A41', 'A42', 'A43', 'A44', 'A45',
|
|
40
|
+
'A47', 'A48', 'A49', 'A5', 'A53', 'A54', 'A55', 'A56', 'A59', 'A6', 'A68', 'A69', 'A7', 'A70',
|
|
41
|
+
'A71', 'A73', 'A74', 'A75', 'A76', 'A8', 'A84', 'A85', 'A86', 'A87', 'A88', 'A89', 'A9', 'A90',
|
|
42
|
+
'A91', 'A93', 'A94', 'A95', 'A96', 'A97', 'A98', 'A99', 'AA', 'AB', 'ACR', 'ACT', 'AD', 'AE',
|
|
43
|
+
'AH', 'AI', 'AK', 'AL', 'AMH', 'AMP', 'ANN', 'APZ', 'AQ', 'AS', 'ASM', 'ASU', 'ATM', 'AWG',
|
|
44
|
+
'AY', 'AZ', 'B1', 'B10', 'B11', 'B12', 'B13', 'B14', 'B15', 'B16', 'B17', 'B18', 'B19', 'B20',
|
|
45
|
+
'B21', 'B22', 'B23', 'B24', 'B25', 'B26', 'B27', 'B28', 'B29', 'B3', 'B30', 'B31', 'B32', 'B33',
|
|
46
|
+
'B34', 'B35', 'B4', 'B41', 'B42', 'B43', 'B44', 'B45', 'B46', 'B47', 'B48', 'B49', 'B50', 'B52',
|
|
47
|
+
'B53', 'B54', 'B55', 'B56', 'B57', 'B58', 'B59', 'B60', 'B61', 'B62', 'B63', 'B64', 'B66', 'B67',
|
|
48
|
+
'B68', 'B69', 'B7', 'B70', 'B71', 'B72', 'B73', 'B74', 'B75', 'B76', 'B77', 'B78', 'B79', 'B8',
|
|
49
|
+
'B80', 'B81', 'B82', 'B83', 'B84', 'B85', 'B86', 'B87', 'B88', 'B89', 'B90', 'B91', 'B92', 'B93',
|
|
50
|
+
'B94', 'B95', 'B96', 'B97', 'B98', 'B99', 'BAR', 'BB', 'BFT', 'BHP', 'BIL', 'BLD', 'BLL', 'BP',
|
|
51
|
+
'BPM', 'BQL', 'BTU', 'BUA', 'BUI', 'C0', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17',
|
|
52
|
+
'C18', 'C19', 'C20', 'C21', 'C22', 'C23', 'C24', 'C25', 'C26', 'C27', 'C28', 'C29', 'C3', 'C30',
|
|
53
|
+
'C31', 'C32', 'C33', 'C34', 'C35', 'C36', 'C37', 'C38', 'C39', 'C40', 'C41', 'C42', 'C43', 'C44',
|
|
54
|
+
'C45', 'C46', 'C47', 'C48', 'C49', 'C50', 'C51', 'C52', 'C53', 'C54', 'C55', 'C56', 'C57', 'C58',
|
|
55
|
+
'C59', 'C60', 'C61', 'C62', 'C63', 'C64', 'C65', 'C66', 'C67', 'C68', 'C69', 'C7', 'C70', 'C71',
|
|
56
|
+
'C72', 'C73', 'C74', 'C75', 'C76', 'C78', 'C79', 'C8', 'C80', 'C81', 'C82', 'C83', 'C84', 'C85',
|
|
57
|
+
'C86', 'C87', 'C88', 'C89', 'C9', 'C90', 'C91', 'C92', 'C93', 'C94', 'C95', 'C96', 'C97', 'C99',
|
|
58
|
+
'CCT', 'CDL', 'CEL', 'CEN', 'CG', 'CGM', 'CKG', 'CLF', 'CLT', 'CMK', 'CMQ', 'CMT', 'CNP', 'CNT',
|
|
59
|
+
'COU', 'CTG', 'CTM', 'CTN', 'CUR', 'CWA', 'CWI', 'D03', 'D04', 'D1', 'D10', 'D11', 'D12', 'D13',
|
|
60
|
+
'D15', 'D16', 'D17', 'D18', 'D19', 'D2', 'D20', 'D21', 'D22', 'D23', 'D24', 'D25', 'D26', 'D27',
|
|
61
|
+
'D29', 'D30', 'D31', 'D32', 'D33', 'D34', 'D36', 'D41', 'D42', 'D43', 'D44', 'D45', 'D46', 'D47',
|
|
62
|
+
'D48', 'D49', 'D5', 'D50', 'D51', 'D52', 'D53', 'D54', 'D55', 'D56', 'D57', 'D58', 'D59', 'D6',
|
|
63
|
+
'D60', 'D61', 'D62', 'D63', 'D65', 'D68', 'D69', 'D73', 'D74', 'D77', 'D78', 'D80', 'D81', 'D82',
|
|
64
|
+
'D83', 'D85', 'D86', 'D87', 'D88', 'D89', 'D91', 'D93', 'D94', 'D95', 'DAA', 'DAD', 'DAY', 'DB',
|
|
65
|
+
'DBM', 'DBW', 'DD', 'DEC', 'DG', 'DJ', 'DLT', 'DMA', 'DMK', 'DMO', 'DMQ', 'DMT', 'DN', 'DPC',
|
|
66
|
+
'DPR', 'DPT', 'DRA', 'DRI', 'DRL', 'DT', 'DTN', 'DWT', 'DZN', 'DZP', 'E01', 'E07', 'E08', 'E09',
|
|
67
|
+
'E10', 'E12', 'E14', 'E15', 'E16', 'E17', 'E18', 'E19', 'E20', 'E21', 'E22', 'E23', 'E25', 'E27',
|
|
68
|
+
'E28', 'E30', 'E31', 'E32', 'E33', 'E34', 'E35', 'E36', 'E37', 'E38', 'E39', 'E4', 'E40', 'E41',
|
|
69
|
+
'E42', 'E43', 'E44', 'E45', 'E46', 'E47', 'E48', 'E49', 'E50', 'E51', 'E52', 'E53', 'E54', 'E55',
|
|
70
|
+
'E56', 'E57', 'E58', 'E59', 'E60', 'E61', 'E62', 'E63', 'E64', 'E65', 'E66', 'E67', 'E68', 'E69',
|
|
71
|
+
'E70', 'E71', 'E72', 'E73', 'E74', 'E75', 'E76', 'E77', 'E78', 'E79', 'E80', 'E81', 'E82', 'E83',
|
|
72
|
+
'E84', 'E85', 'E86', 'E87', 'E88', 'E89', 'E90', 'E91', 'E92', 'E93', 'E94', 'E95', 'E96', 'E97',
|
|
73
|
+
'E98', 'E99', 'EA', 'EB', 'EQ', 'F01', 'F02', 'F03', 'F04', 'F05', 'F06', 'F07', 'F08', 'F10',
|
|
74
|
+
'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24',
|
|
75
|
+
'F25', 'F26', 'F27', 'F28', 'F29', 'F30', 'F31', 'F32', 'F33', 'F34', 'F35', 'F36', 'F37', 'F38',
|
|
76
|
+
'F39', 'F40', 'F41', 'F42', 'F43', 'F44', 'F45', 'F46', 'F47', 'F48', 'F49', 'F50', 'F51', 'F52',
|
|
77
|
+
'F53', 'F54', 'F55', 'F56', 'F57', 'F58', 'F59', 'F60', 'F61', 'F62', 'F63', 'F64', 'F65', 'F66',
|
|
78
|
+
'F67', 'F68', 'F69', 'F70', 'F71', 'F72', 'F73', 'F74', 'F75', 'F76', 'F77', 'F78', 'F79', 'F80',
|
|
79
|
+
'F81', 'F82', 'F83', 'F84', 'F85', 'F86', 'F87', 'F88', 'F89', 'F90', 'F91', 'F92', 'F93', 'F94',
|
|
80
|
+
'F95', 'F96', 'F97', 'F98', 'F99', 'FAH', 'FAR', 'FBM', 'FC', 'FF', 'FH', 'FIT', 'FL', 'FNU',
|
|
81
|
+
'FOT', 'FP', 'FR', 'FS', 'FTK', 'FTQ', 'G01', 'G04', 'G05', 'G06', 'G08', 'G09', 'G10', 'G11',
|
|
82
|
+
'G12', 'G13', 'G14', 'G15', 'G16', 'G17', 'G18', 'G19', 'G2', 'G20', 'G21', 'G23', 'G24', 'G25',
|
|
83
|
+
'G26', 'G27', 'G28', 'G29', 'G3', 'G30', 'G31', 'G32', 'G33', 'G34', 'G35', 'G36', 'G37', 'G38',
|
|
84
|
+
'G39', 'G40', 'G41', 'G42', 'G43', 'G44', 'G45', 'G46', 'G47', 'G48', 'G49', 'G50', 'G51', 'G52',
|
|
85
|
+
'G53', 'G54', 'G55', 'G56', 'G57', 'G58', 'G59', 'G60', 'G61', 'G62', 'G63', 'G64', 'G65', 'G66',
|
|
86
|
+
'G67', 'G68', 'G69', 'G70', 'G71', 'G72', 'G73', 'G74', 'G75', 'G76', 'G77', 'G78', 'G79', 'G80',
|
|
87
|
+
'G81', 'G82', 'G83', 'G84', 'G85', 'G86', 'G87', 'G88', 'G89', 'G90', 'G91', 'G92', 'G93', 'G94',
|
|
88
|
+
'G95', 'G96', 'G97', 'G98', 'G99', 'GB', 'GBQ', 'GDW', 'GE', 'GF', 'GFI', 'GGR', 'GIA', 'GIC',
|
|
89
|
+
'GII', 'GIP', 'GJ', 'GL', 'GLD', 'GLI', 'GLL', 'GM', 'GO', 'GP', 'GQ', 'GRM', 'GRN', 'GRO',
|
|
90
|
+
'GV', 'GWH', 'H03', 'H04', 'H05', 'H06', 'H07', 'H08', 'H09', 'H10', 'H11', 'H12', 'H13', 'H14',
|
|
91
|
+
'H15', 'H16', 'H18', 'H19', 'H20', 'H21', 'H22', 'H23', 'H24', 'H25', 'H26', 'H27', 'H28', 'H29',
|
|
92
|
+
'H30', 'H31', 'H32', 'H33', 'H34', 'H35', 'H36', 'H37', 'H38', 'H39', 'H40', 'H41', 'H42', 'H43',
|
|
93
|
+
'H44', 'H45', 'H46', 'H47', 'H48', 'H49', 'H50', 'H51', 'H52', 'H53', 'H54', 'H55', 'H56', 'H57',
|
|
94
|
+
'H58', 'H59', 'H60', 'H61', 'H62', 'H63', 'H64', 'H65', 'H66', 'H67', 'H68', 'H69', 'H70', 'H71',
|
|
95
|
+
'H72', 'H73', 'H74', 'H75', 'H76', 'H77', 'H79', 'H80', 'H81', 'H82', 'H83', 'H84', 'H85', 'H87',
|
|
96
|
+
'H88', 'H89', 'H90', 'H91', 'H92', 'H93', 'H94', 'H95', 'H96', 'H98', 'H99', 'HA', 'HAD', 'HBA',
|
|
97
|
+
'HBX', 'HC', 'HDW', 'HEA', 'HGM', 'HH', 'HIU', 'HKM', 'HLT', 'HM', 'HMO', 'HMQ', 'HMT', 'HPA',
|
|
98
|
+
'HTZ', 'HUR', 'HWE', 'IA', 'IE', 'INH', 'INK', 'INQ', 'ISD', 'IU', 'IUG', 'IV', 'J10', 'J12',
|
|
99
|
+
'J13', 'J14', 'J15', 'J16', 'J17', 'J18', 'J19', 'J2', 'J20', 'J21', 'J22', 'J23', 'J24', 'J25',
|
|
100
|
+
'J26', 'J27', 'J28', 'J29', 'J30', 'J31', 'J32', 'J33', 'J34', 'J35', 'J36', 'J38', 'J39', 'J40',
|
|
101
|
+
'J41', 'J42', 'J43', 'J44', 'J45', 'J46', 'J47', 'J48', 'J49', 'J50', 'J51', 'J52', 'J53', 'J54',
|
|
102
|
+
'J55', 'J56', 'J57', 'J58', 'J59', 'J60', 'J61', 'J62', 'J63', 'J64', 'J65', 'J66', 'J67', 'J68',
|
|
103
|
+
'J69', 'J70', 'J71', 'J72', 'J73', 'J74', 'J75', 'J76', 'J78', 'J79', 'J81', 'J82', 'J83', 'J84',
|
|
104
|
+
'J85', 'J87', 'J90', 'J91', 'J92', 'J93', 'J95', 'J96', 'J97', 'J98', 'J99', 'JE', 'JK', 'JM',
|
|
105
|
+
'JNT', 'JOU', 'JPS', 'JWL', 'K1', 'K10', 'K11', 'K12', 'K13', 'K14', 'K15', 'K16', 'K17', 'K18',
|
|
106
|
+
'K19', 'K2', 'K20', 'K21', 'K22', 'K23', 'K26', 'K27', 'K28', 'K3', 'K30', 'K31', 'K32', 'K33',
|
|
107
|
+
'K34', 'K35', 'K36', 'K37', 'K38', 'K39', 'K40', 'K41', 'K42', 'K43', 'K45', 'K46', 'K47', 'K48',
|
|
108
|
+
'K49', 'K50', 'K51', 'K52', 'K53', 'K54', 'K55', 'K58', 'K59', 'K6', 'K60', 'K61', 'K62', 'K63',
|
|
109
|
+
'K64', 'K65', 'K66', 'K67', 'K68', 'K69', 'K70', 'K71', 'K73', 'K74', 'K75', 'K76', 'K77', 'K78',
|
|
110
|
+
'K79', 'K80', 'K81', 'K82', 'K83', 'K84', 'K85', 'K86', 'K87', 'K88', 'K89', 'K90', 'K91', 'K92',
|
|
111
|
+
'K93', 'K94', 'K95', 'K96', 'K97', 'K98', 'K99', 'KA', 'KAT', 'KB', 'KBA', 'KCC', 'KDW', 'KEL',
|
|
112
|
+
'KGM', 'KGS', 'KHY', 'KHZ', 'KI', 'KIC', 'KIP', 'KJ', 'KJO', 'KL', 'KLK', 'KLX', 'KMA', 'KMH',
|
|
113
|
+
'KMK', 'KMQ', 'KMT', 'KNI', 'KNM', 'KNS', 'KNT', 'KO', 'KPA', 'KPH', 'KPO', 'KPP', 'KR', 'KSD',
|
|
114
|
+
'KSH', 'KT', 'KTN', 'KUR', 'KVA', 'KVR', 'KVT', 'KW', 'KWH', 'KWN', 'KWO', 'KWS', 'KWT', 'KWY',
|
|
115
|
+
'KX', 'L10', 'L11', 'L12', 'L13', 'L14', 'L15', 'L16', 'L17', 'L18', 'L19', 'L2', 'L20', 'L21',
|
|
116
|
+
'L23', 'L24', 'L25', 'L26', 'L27', 'L28', 'L29', 'L30', 'L31', 'L32', 'L33', 'L34', 'L35', 'L36',
|
|
117
|
+
'L37', 'L38', 'L39', 'L40', 'L41', 'L42', 'L43', 'L44', 'L45', 'L46', 'L47', 'L48', 'L49', 'L50',
|
|
118
|
+
'L51', 'L52', 'L53', 'L54', 'L55', 'L56', 'L57', 'L58', 'L59', 'L60', 'L63', 'L64', 'L65', 'L66',
|
|
119
|
+
'L67', 'L68', 'L69', 'L70', 'L71', 'L72', 'L73', 'L74', 'L75', 'L76', 'L77', 'L78', 'L79', 'L80',
|
|
120
|
+
'L81', 'L82', 'L83', 'L84', 'L85', 'L86', 'L87', 'L88', 'L89', 'L90', 'L91', 'L92', 'L93', 'L94',
|
|
121
|
+
'L95', 'L96', 'L98', 'L99', 'LA', 'LAC', 'LBR', 'LBT', 'LD', 'LEF', 'LF', 'LH', 'LK', 'LM',
|
|
122
|
+
'LN', 'LO', 'LP', 'LPA', 'LR', 'LS', 'LTN', 'LTR', 'LUB', 'LUM', 'LUX', 'LY', 'M1', 'M10',
|
|
123
|
+
'M11', 'M12', 'M13', 'M14', 'M15', 'M16', 'M17', 'M18', 'M19', 'M20', 'M21', 'M22', 'M23', 'M24',
|
|
124
|
+
'M25', 'M26', 'M27', 'M29', 'M30', 'M31', 'M32', 'M33', 'M34', 'M35', 'M36', 'M37', 'M38', 'M39',
|
|
125
|
+
'M4', 'M40', 'M41', 'M42', 'M43', 'M44', 'M45', 'M46', 'M47', 'M48', 'M49', 'M5', 'M50', 'M51',
|
|
126
|
+
'M52', 'M53', 'M55', 'M56', 'M57', 'M58', 'M59', 'M60', 'M61', 'M62', 'M63', 'M64', 'M65', 'M66',
|
|
127
|
+
'M67', 'M68', 'M69', 'M7', 'M70', 'M71', 'M72', 'M73', 'M74', 'M75', 'M76', 'M77', 'M78', 'M79',
|
|
128
|
+
'M80', 'M81', 'M82', 'M83', 'M84', 'M85', 'M86', 'M87', 'M88', 'M89', 'M9', 'M90', 'M91', 'M92',
|
|
129
|
+
'M93', 'M94', 'M95', 'M96', 'M97', 'M98', 'M99', 'MAH', 'MAL', 'MAM', 'MAR', 'MAW', 'MBE', 'MBF',
|
|
130
|
+
'MBR', 'MC', 'MCU', 'MD', 'MGM', 'MHZ', 'MIK', 'MIL', 'MIN', 'MIO', 'MIU', 'MKD', 'MKM', 'MKW',
|
|
131
|
+
'MLD', 'MLT', 'MMK', 'MMQ', 'MMT', 'MND', 'MNJ', 'MON', 'MPA', 'MQD', 'MQH', 'MQM', 'MQS', 'MQW',
|
|
132
|
+
'MRD', 'MRM', 'MRW', 'MSK', 'MTK', 'MTQ', 'MTR', 'MTS', 'MTZ', 'MVA', 'MWH', 'N1', 'N10', 'N11',
|
|
133
|
+
'N12', 'N13', 'N14', 'N15', 'N16', 'N17', 'N18', 'N19', 'N20', 'N21', 'N22', 'N23', 'N24', 'N25',
|
|
134
|
+
'N26', 'N27', 'N28', 'N29', 'N3', 'N30', 'N31', 'N32', 'N33', 'N34', 'N35', 'N36', 'N37', 'N38',
|
|
135
|
+
'N39', 'N40', 'N41', 'N42', 'N43', 'N44', 'N45', 'N46', 'N47', 'N48', 'N49', 'N50', 'N51', 'N52',
|
|
136
|
+
'N53', 'N54', 'N55', 'N56', 'N57', 'N58', 'N59', 'N60', 'N61', 'N62', 'N63', 'N64', 'N65', 'N66',
|
|
137
|
+
'N67', 'N68', 'N69', 'N70', 'N71', 'N72', 'N73', 'N74', 'N75', 'N76', 'N77', 'N78', 'N79', 'N80',
|
|
138
|
+
'N81', 'N82', 'N83', 'N84', 'N85', 'N86', 'N87', 'N88', 'N89', 'N90', 'N91', 'N92', 'N93', 'N94',
|
|
139
|
+
'N95', 'N96', 'N97', 'N98', 'N99', 'NA', 'NAR', 'NCL', 'NEW', 'NF', 'NIL', 'NIU', 'NL', 'NM3',
|
|
140
|
+
'NMI', 'NMP', 'NPT', 'NT', 'NTU', 'NU', 'NX', 'OA', 'ODE', 'ODG', 'ODK', 'ODM', 'OHM', 'ON',
|
|
141
|
+
'ONZ', 'OPM', 'OT', 'OZA', 'OZI', 'P1', 'P10', 'P11', 'P12', 'P13', 'P14', 'P15', 'P16', 'P17',
|
|
142
|
+
'P18', 'P19', 'P2', 'P20', 'P21', 'P22', 'P23', 'P24', 'P25', 'P26', 'P27', 'P28', 'P29', 'P30',
|
|
143
|
+
'P31', 'P32', 'P33', 'P34', 'P35', 'P36', 'P37', 'P38', 'P39', 'P40', 'P41', 'P42', 'P43', 'P44',
|
|
144
|
+
'P45', 'P46', 'P47', 'P48', 'P49', 'P5', 'P50', 'P51', 'P52', 'P53', 'P54', 'P55', 'P56', 'P57',
|
|
145
|
+
'P58', 'P59', 'P60', 'P61', 'P62', 'P63', 'P64', 'P65', 'P66', 'P67', 'P68', 'P69', 'P70', 'P71',
|
|
146
|
+
'P72', 'P73', 'P74', 'P75', 'P76', 'P77', 'P78', 'P79', 'P80', 'P81', 'P82', 'P83', 'P84', 'P85',
|
|
147
|
+
'P86', 'P87', 'P88', 'P89', 'P90', 'P91', 'P92', 'P93', 'P94', 'P95', 'P96', 'P97', 'P98', 'P99',
|
|
148
|
+
'PAL', 'PD', 'PFL', 'PGL', 'PI', 'PLA', 'PO', 'PQ', 'PR', 'PS', 'PTD', 'PTI', 'PTL', 'PTN',
|
|
149
|
+
'Q10', 'Q11', 'Q12', 'Q13', 'Q14', 'Q15', 'Q16', 'Q17', 'Q18', 'Q19', 'Q20', 'Q21', 'Q22', 'Q23',
|
|
150
|
+
'Q24', 'Q25', 'Q26', 'Q27', 'Q28', 'Q29', 'Q3', 'Q30', 'Q31', 'Q32', 'Q33', 'Q34', 'Q35', 'Q36',
|
|
151
|
+
'Q37', 'Q38', 'Q39', 'Q40', 'Q41', 'Q42', 'QA', 'QAN', 'QB', 'QR', 'QTD', 'QTI', 'QTL', 'QTR',
|
|
152
|
+
'R1', 'R9', 'RH', 'RM', 'ROM', 'RP', 'RPM', 'RPS', 'RT', 'S3', 'S4', 'SAN', 'SCO', 'SCR',
|
|
153
|
+
'SEC', 'SET', 'SG', 'SIE', 'SM3', 'SMI', 'SQ', 'SQR', 'SR', 'STC', 'STI', 'STK', 'STL', 'STN',
|
|
154
|
+
'STW', 'SW', 'SX', 'SYR', 'T0', 'T3', 'TAH', 'TAN', 'TI', 'TIC', 'TIP', 'TKM', 'TMS', 'TNE',
|
|
155
|
+
'TP', 'TPI', 'TPR', 'TQD', 'TRL', 'TST', 'TTS', 'U1', 'U2', 'UB', 'UC', 'VA', 'VLT', 'VP',
|
|
156
|
+
'W2', 'WA', 'WB', 'WCD', 'WE', 'WEB', 'WEE', 'WG', 'WHR', 'WM', 'WSD', 'WTT', 'X1', 'YDK',
|
|
157
|
+
'YDQ', 'YRD', 'Z11', 'Z9', 'ZP', 'ZZ', 'X1A', 'X1B', 'X1D', 'X1F', 'X1G', 'X1W', 'X2C', 'X3A',
|
|
158
|
+
'X3H', 'X43', 'X44', 'X4A', 'X4B', 'X4C', 'X4D', 'X4F', 'X4G', 'X4H', 'X5H', 'X5L', 'X5M', 'X6H',
|
|
159
|
+
'X6P', 'X7A', 'X7B', 'X8A', 'X8B', 'X8C', 'XAA', 'XAB', 'XAC', 'XAD', 'XAE', 'XAF', 'XAG', 'XAH',
|
|
160
|
+
'XAI', 'XAJ', 'XAL', 'XAM', 'XAP', 'XAT', 'XAV', 'XB4', 'XBA', 'XBB', 'XBC', 'XBD', 'XBE', 'XBF',
|
|
161
|
+
'XBG', 'XBH', 'XBI', 'XBJ', 'XBK', 'XBL', 'XBM', 'XBN', 'XBO', 'XBP', 'XBQ', 'XBR', 'XBS', 'XBT',
|
|
162
|
+
'XBU', 'XBV', 'XBW', 'XBX', 'XBY', 'XBZ', 'XCA', 'XCB', 'XCC', 'XCD', 'XCE', 'XCF', 'XCG', 'XCH',
|
|
163
|
+
'XCI', 'XCJ', 'XCK', 'XCL', 'XCM', 'XCN', 'XCO', 'XCP', 'XCQ', 'XCR', 'XCS', 'XCT', 'XCU', 'XCV',
|
|
164
|
+
'XCW', 'XCX', 'XCY', 'XCZ', 'XDA', 'XDB', 'XDC', 'XDG', 'XDH', 'XDI', 'XDJ', 'XDK', 'XDL', 'XDM',
|
|
165
|
+
'XDN', 'XDP', 'XDR', 'XDS', 'XDT', 'XDU', 'XDV', 'XDW', 'XDX', 'XDY', 'XEC', 'XED', 'XEE', 'XEF',
|
|
166
|
+
'XEG', 'XEH', 'XEI', 'XEN', 'XFB', 'XFC', 'XFD', 'XFE', 'XFI', 'XFL', 'XFO', 'XFP', 'XFR', 'XFT',
|
|
167
|
+
'XFW', 'XFX', 'XGB', 'XGI', 'XGL', 'XGR', 'XGU', 'XGY', 'XGZ', 'XHA', 'XHB', 'XHC', 'XHG', 'XHN',
|
|
168
|
+
'XHR', 'XIA', 'XIB', 'XIC', 'XID', 'XIE', 'XIF', 'XIG', 'XIH', 'XIK', 'XIL', 'XIN', 'XIZ', 'XJB',
|
|
169
|
+
'XJC', 'XJG', 'XJR', 'XJT', 'XJY', 'XKG', 'XKI', 'XLE', 'XLG', 'XLT', 'XLU', 'XLV', 'XLZ', 'XMA',
|
|
170
|
+
'XMB', 'XMC', 'XME', 'XMR', 'XMS', 'XMT', 'XMW', 'XMX', 'XNA', 'XNE', 'XNF', 'XNG', 'XNS', 'XNT',
|
|
171
|
+
'XNU', 'XNV', 'XO1', 'XO2', 'XO3', 'XO4', 'XO5', 'XO6', 'XO7', 'XO8', 'XO9', 'XOA', 'XOB', 'XOC',
|
|
172
|
+
'XOD', 'XOE', 'XOF', 'XOG', 'XOH', 'XOI', 'XOJ', 'XOK', 'XOL', 'XOM', 'XON', 'XOP', 'XOQ', 'XOR',
|
|
173
|
+
'XOS', 'XOT', 'XOU', 'XOV', 'XOW', 'XOX', 'XOY', 'XOZ', 'XP1', 'XP2', 'XP3', 'XP4', 'XPA', 'XPB',
|
|
174
|
+
'XPC', 'XPD', 'XPE', 'XPF', 'XPG', 'XPH', 'XPI', 'XPJ', 'XPK', 'XPL', 'XPN', 'XPO', 'XPP', 'XPR',
|
|
175
|
+
'XPT', 'XPU', 'XPV', 'XPX', 'XPY', 'XPZ', 'XQA', 'XQB', 'XQC', 'XQD', 'XQF', 'XQG', 'XQH', 'XQJ',
|
|
176
|
+
'XQK', 'XQL', 'XQM', 'XQN', 'XQP', 'XQQ', 'XQR', 'XQS', 'XRD', 'XRG', 'XRJ', 'XRK', 'XRL', 'XRO',
|
|
177
|
+
'XRT', 'XRZ', 'XSA', 'XSB', 'XSC', 'XSD', 'XSE', 'XSH', 'XSI', 'XSK', 'XSL', 'XSM', 'XSO', 'XSP',
|
|
178
|
+
'XSS', 'XST', 'XSU', 'XSV', 'XSW', 'XSX', 'XSY', 'XSZ', 'XT1', 'XTB', 'XTC', 'XTD', 'XTE', 'XTG',
|
|
179
|
+
'XTI', 'XTK', 'XTL', 'XTN', 'XTO', 'XTR', 'XTS', 'XTT', 'XTU', 'XTV', 'XTW', 'XTY', 'XTZ', 'XUC',
|
|
180
|
+
'XUN', 'XVA', 'XVG', 'XVI', 'XVK', 'XVL', 'XVN', 'XVO', 'XVP', 'XVQ', 'XVR', 'XVS', 'XVY', 'XWA',
|
|
181
|
+
'XWB', 'XWC', 'XWD', 'XWF', 'XWG', 'XWH', 'XWJ', 'XWK', 'XWL', 'XWM', 'XWN', 'XWP', 'XWQ', 'XWR',
|
|
182
|
+
'XWS', 'XWT', 'XWU', 'XWV', 'XWW', 'XWX', 'XWY', 'XWZ', 'XXA', 'XXB', 'XXC', 'XXD', 'XXF', 'XXG',
|
|
183
|
+
'XXH', 'XXJ', 'XXK', 'XYA', 'XYB', 'XYC', 'XYD', 'XYF', 'XYG', 'XYH', 'XYJ', 'XYK', 'XYL', 'XYM',
|
|
184
|
+
'XYN', 'XYP', 'XYQ', 'XYR', 'XYS', 'XYT', 'XYV', 'XYW', 'XYX', 'XYY', 'XYZ', 'XZA', 'XZB', 'XZC',
|
|
185
|
+
'XZD', 'XZF', 'XZG', 'XZH', 'XZJ', 'XZK', 'XZL', 'XZM', 'XZN', 'XZP', 'XZQ', 'XZR', 'XZS', 'XZT',
|
|
186
|
+
'XZU', 'XZV', 'XZW', 'XZX', 'XZY', 'XZZ',
|
|
187
|
+
]);
|
|
188
|
+
|
|
189
|
+
/** the set every check uses; it never leaves this module */
|
|
190
|
+
const unitCodes: ReadonlySet<string> = new Set(BR_CL_23_CODES);
|
|
191
|
+
|
|
192
|
+
/** The EN 16931 unit code list (BR-CL-23) with its source. */
|
|
193
|
+
export const en16931UnitCodeList: IEn16931UnitCodeList = Object.freeze({
|
|
194
|
+
rule: 'BR-CL-23',
|
|
195
|
+
businessTerms: Object.freeze(['BT-130', 'BT-150'] as const),
|
|
196
|
+
codeLists: 'UN/ECE Recommendation 20 with Recommendation 21 extension',
|
|
197
|
+
source: 'EN 16931 validation artefacts (CEN/TC 434) validation-1.3.16',
|
|
198
|
+
codes: BR_CL_23_CODES,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Whether a value is a unit code EN 16931 admits (BR-CL-23). The comparison is exact: `HUR` is
|
|
203
|
+
* a code, `hur`, `HOURS` and ` HUR` are not.
|
|
204
|
+
*/
|
|
205
|
+
export const isEn16931UnitCode = (value: unknown): value is string =>
|
|
206
|
+
typeof value === 'string' && unitCodes.has(value);
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* BR-CL-23 as the official rule tests a `unitCode` attribute: XML whitespace around the value is
|
|
210
|
+
* ignored, and a value with whitespace inside it, or an empty value, fails.
|
|
211
|
+
*/
|
|
212
|
+
export const meetsUnitCodeRule = (attributeValue: string): boolean => {
|
|
213
|
+
const normalized = attributeValue.replace(/[ \t\r\n]+/g, ' ').replace(/^ | $/g, '');
|
|
214
|
+
return !normalized.includes(' ') && unitCodes.has(normalized);
|
|
215
|
+
};
|
|
@@ -3,6 +3,8 @@ import { CodeLists } from './validation.types.js';
|
|
|
3
3
|
import type { TAccountingDocItem } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
4
4
|
import type { EInvoice } from '../../einvoice.js';
|
|
5
5
|
import type { IExtendedAccountingDocItem } from '../../interfaces/en16931-metadata.js';
|
|
6
|
+
import { getDocumentTypeCode, isAccountingDocType } from '../utils/document.typecode.js';
|
|
7
|
+
import { en16931UnitCodeList, meetsUnitCodeRule } from '../utils/unit.codes.js';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Code List Validator for EN16931 compliance
|
|
@@ -123,10 +125,9 @@ export class CodeListValidator {
|
|
|
123
125
|
* Validate document type code (UNCL1001)
|
|
124
126
|
*/
|
|
125
127
|
private validateDocumentType(invoice: EInvoice): void {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
invoice.accountingDocType === 'debitnote' ? '383' : null);
|
|
128
|
+
// an explicit BT-3 code wins; otherwise the code the encoders write for the accounting document type
|
|
129
|
+
const typeCode = invoice.metadata?.documentTypeCode ||
|
|
130
|
+
(isAccountingDocType(invoice.accountingDocType) ? getDocumentTypeCode(invoice.accountingDocType) : null);
|
|
130
131
|
|
|
131
132
|
if (typeCode && !CodeLists.UNCL1001.codes.has(typeCode)) {
|
|
132
133
|
this.addError(
|
|
@@ -208,33 +209,21 @@ export class CodeListValidator {
|
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
/**
|
|
211
|
-
* Validate unit codes (
|
|
212
|
+
* Validate unit codes (BR-CL-23: UN/ECE Rec 20 with the Rec 21 extension)
|
|
212
213
|
*/
|
|
213
214
|
private validateUnitCodes(invoice: EInvoice): void {
|
|
214
215
|
invoice.items?.forEach((item, index) => {
|
|
215
216
|
const unitCode = item.unitType;
|
|
216
|
-
|
|
217
|
+
// an empty unit is an absent one, which BR-23 reports; BR-CL-23 checks a unit that is there
|
|
218
|
+
if (unitCode && !meetsUnitCodeRule(unitCode)) {
|
|
217
219
|
this.addError(
|
|
218
220
|
'BR-CL-23',
|
|
219
|
-
`Invalid unit code: ${unitCode}. Must be
|
|
221
|
+
`Invalid unit code: ${unitCode}. Must be UN/ECE Recommendation 20 with Rec 21 extension`,
|
|
220
222
|
'EN16931',
|
|
221
|
-
`items[${index}].
|
|
223
|
+
`items[${index}].unitType`,
|
|
222
224
|
'BT-130',
|
|
223
225
|
unitCode,
|
|
224
|
-
'
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Validate quantity is positive for standard units
|
|
229
|
-
if (unitCode && item.unitQuantity <= 0 && unitCode !== 'LS') { // LS = Lump sum can be 1
|
|
230
|
-
this.addError(
|
|
231
|
-
'BR-25',
|
|
232
|
-
`Quantity must be positive for unit ${unitCode}`,
|
|
233
|
-
'EN16931',
|
|
234
|
-
`items[${index}].quantity`,
|
|
235
|
-
'BT-129',
|
|
236
|
-
item.unitQuantity,
|
|
237
|
-
'> 0'
|
|
226
|
+
'A code of the EN 16931 unit code list, for example C62 (one), H87 (piece), HUR (hour), DAY (day), MON (month), LS (lump sum)'
|
|
238
227
|
);
|
|
239
228
|
}
|
|
240
229
|
});
|
|
@@ -310,7 +299,7 @@ export class CodeListValidator {
|
|
|
310
299
|
return { name: 'UNCL4461', version: CodeLists.UNCL4461.version };
|
|
311
300
|
}
|
|
312
301
|
if (ruleId.includes('CL-23')) {
|
|
313
|
-
return { name:
|
|
302
|
+
return { name: en16931UnitCodeList.codeLists, version: en16931UnitCodeList.source };
|
|
314
303
|
}
|
|
315
304
|
return undefined;
|
|
316
305
|
}
|
|
@@ -381,56 +381,56 @@ export class EN16931BusinessRulesValidator {
|
|
|
381
381
|
);
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
// BR-
|
|
384
|
+
// BR-25: Each Invoice line shall contain the Item name
|
|
385
385
|
if (!item.name) {
|
|
386
386
|
this.addError(
|
|
387
|
-
'BR-
|
|
387
|
+
'BR-25',
|
|
388
388
|
`Invoice line ${index + 1} must have an item name`,
|
|
389
389
|
`items[${index}].name`
|
|
390
390
|
);
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
// BR-
|
|
393
|
+
// BR-22: Each Invoice line shall have an Invoiced quantity
|
|
394
394
|
if (item.unitQuantity === undefined || item.unitQuantity === null) {
|
|
395
395
|
this.addError(
|
|
396
|
-
'BR-
|
|
396
|
+
'BR-22',
|
|
397
397
|
`Invoice line ${index + 1} must have a quantity`,
|
|
398
398
|
`items[${index}].quantity`
|
|
399
399
|
);
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
-
// BR-
|
|
402
|
+
// BR-23: An Invoice line shall have an Invoiced quantity unit of measure code
|
|
403
403
|
if (!item.unitType) {
|
|
404
404
|
this.addError(
|
|
405
|
-
'BR-
|
|
405
|
+
'BR-23',
|
|
406
406
|
`Invoice line ${index + 1} must have a unit of measure code`,
|
|
407
|
-
`items[${index}].
|
|
407
|
+
`items[${index}].unitType`
|
|
408
408
|
);
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
-
// BR-
|
|
411
|
+
// BR-24: Each Invoice line shall have an Invoice line net amount
|
|
412
412
|
const lineNetAmount = item.unitNetPrice * item.unitQuantity;
|
|
413
413
|
if (isNaN(lineNetAmount)) {
|
|
414
414
|
this.addError(
|
|
415
|
-
'BR-
|
|
415
|
+
'BR-24',
|
|
416
416
|
`Invoice line ${index + 1} must have a valid net amount`,
|
|
417
417
|
`items[${index}]`
|
|
418
418
|
);
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
-
// BR-
|
|
421
|
+
// BR-CO-04: Each Invoice line shall be categorized with an Invoiced item VAT category code
|
|
422
422
|
if (item.vatPercentage === undefined) {
|
|
423
423
|
this.addError(
|
|
424
|
-
'BR-
|
|
424
|
+
'BR-CO-04',
|
|
425
425
|
`Invoice line ${index + 1} must have a VAT category code`,
|
|
426
426
|
`items[${index}].vatPercentage`
|
|
427
427
|
);
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
-
// BR-
|
|
430
|
+
// BR-26: Each Invoice line shall contain the Item net price
|
|
431
431
|
if (item.unitNetPrice === undefined || item.unitNetPrice === null) {
|
|
432
432
|
this.addError(
|
|
433
|
-
'BR-
|
|
433
|
+
'BR-26',
|
|
434
434
|
`Invoice line ${index + 1} must have a net price`,
|
|
435
435
|
`items[${index}].unitPrice`
|
|
436
436
|
);
|
|
@@ -150,34 +150,6 @@ export const CodeLists = {
|
|
|
150
150
|
['58', 'SEPA credit transfer'],
|
|
151
151
|
['59', 'SEPA direct debit']
|
|
152
152
|
])
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
// UNECE Rec 20 Unit codes (subset)
|
|
156
|
-
UNECERec20: {
|
|
157
|
-
version: '2021',
|
|
158
|
-
codes: new Map([
|
|
159
|
-
['C62', 'One (unit)'],
|
|
160
|
-
['DAY', 'Day'],
|
|
161
|
-
['HAR', 'Hectare'],
|
|
162
|
-
['HUR', 'Hour'],
|
|
163
|
-
['KGM', 'Kilogram'],
|
|
164
|
-
['KTM', 'Kilometre'],
|
|
165
|
-
['KWH', 'Kilowatt hour'],
|
|
166
|
-
['LS', 'Lump sum'],
|
|
167
|
-
['LTR', 'Litre'],
|
|
168
|
-
['MIN', 'Minute'],
|
|
169
|
-
['MMT', 'Millimetre'],
|
|
170
|
-
['MON', 'Month'],
|
|
171
|
-
['MTK', 'Square metre'],
|
|
172
|
-
['MTQ', 'Cubic metre'],
|
|
173
|
-
['MTR', 'Metre'],
|
|
174
|
-
['NAR', 'Number of articles'],
|
|
175
|
-
['NPR', 'Number of pairs'],
|
|
176
|
-
['P1', 'Percent'],
|
|
177
|
-
['SET', 'Set'],
|
|
178
|
-
['TNE', 'Tonne (metric ton)'],
|
|
179
|
-
['WEE', 'Week']
|
|
180
|
-
])
|
|
181
153
|
}
|
|
182
154
|
};
|
|
183
155
|
|
package/ts/index.ts
CHANGED
|
@@ -37,6 +37,17 @@ import {
|
|
|
37
37
|
// Import format detector
|
|
38
38
|
import { FormatDetector } from './formats/utils/format.detector.js';
|
|
39
39
|
|
|
40
|
+
// Import the document type code table (BT-3)
|
|
41
|
+
import {
|
|
42
|
+
getAccountingDocType,
|
|
43
|
+
getDocumentTypeCode,
|
|
44
|
+
isAccountingDocType
|
|
45
|
+
} from './formats/utils/document.typecode.js';
|
|
46
|
+
|
|
47
|
+
// Import the EN 16931 unit code list (BR-CL-23)
|
|
48
|
+
import { en16931UnitCodeList, isEn16931UnitCode } from './formats/utils/unit.codes.js';
|
|
49
|
+
import type { IEn16931UnitCodeList } from './formats/utils/unit.codes.js';
|
|
50
|
+
|
|
40
51
|
// Import error classes
|
|
41
52
|
import {
|
|
42
53
|
EInvoiceError,
|
|
@@ -65,6 +76,11 @@ export type {
|
|
|
65
76
|
TInvoice,
|
|
66
77
|
TCreditNote,
|
|
67
78
|
TDebitNote,
|
|
79
|
+
TSelfBilledInvoice,
|
|
80
|
+
TAccountingDoc,
|
|
81
|
+
TAccountingDocType,
|
|
82
|
+
TAccountingDocEnvelope,
|
|
83
|
+
TInvoiceDocument,
|
|
68
84
|
TContact,
|
|
69
85
|
TLetterEnvelope,
|
|
70
86
|
TDocumentEnvelope,
|
|
@@ -119,6 +135,15 @@ export {
|
|
|
119
135
|
// Export format detector
|
|
120
136
|
export { FormatDetector };
|
|
121
137
|
|
|
138
|
+
// Export the document type code table, so a consumer that reads or writes BT-3
|
|
139
|
+
// itself does not need a second copy of it
|
|
140
|
+
export { getAccountingDocType, getDocumentTypeCode, isAccountingDocType };
|
|
141
|
+
|
|
142
|
+
// Export the EN 16931 unit code list (BR-CL-23: UN/ECE Recommendation 20 with the
|
|
143
|
+
// Recommendation 21 extension), so a consumer can check a unit before it builds a document
|
|
144
|
+
export { en16931UnitCodeList, isEn16931UnitCode };
|
|
145
|
+
export type { IEn16931UnitCodeList };
|
|
146
|
+
|
|
122
147
|
// Export error classes
|
|
123
148
|
export {
|
|
124
149
|
EInvoiceError,
|
package/ts/interfaces/common.ts
CHANGED
|
@@ -81,9 +81,26 @@ export interface IPdf {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Re-export types from tsclass for convenience
|
|
84
|
+
import type {
|
|
85
|
+
TInvoice,
|
|
86
|
+
TDebitNote,
|
|
87
|
+
TSelfBilledInvoice,
|
|
88
|
+
} from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
89
|
+
|
|
84
90
|
export type { TInvoice } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
85
91
|
export type { TCreditNote } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
86
92
|
export type { TDebitNote } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
93
|
+
export type { TSelfBilledInvoice } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
94
|
+
export type { TAccountingDoc } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
95
|
+
export type { TAccountingDocType } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
96
|
+
export type { TAccountingDocEnvelope } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The accounting documents that are written as an invoice document: the UBL
|
|
100
|
+
* `Invoice` root and the CII type codes of the invoice family. Only a credit
|
|
101
|
+
* note has a document shape of its own.
|
|
102
|
+
*/
|
|
103
|
+
export type TInvoiceDocument = TInvoice | TDebitNote | TSelfBilledInvoice;
|
|
87
104
|
export type { TContact } from '@tsclass/tsclass/dist_ts/business/index.js';
|
|
88
105
|
export type { TLetterEnvelope } from '@tsclass/tsclass/dist_ts/business/index.js';
|
|
89
106
|
export type { TDocumentEnvelope } from '@tsclass/tsclass/dist_ts/business/index.js';
|