@fin.cx/einvoice 8.1.0 → 8.2.1
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 +14 -1
- package/dist_ts/einvoice.js +17 -2
- package/dist_ts/formats/base/base.decoder.js +4 -3
- package/dist_ts/formats/base/base.encoder.d.ts +1 -1
- package/dist_ts/formats/cii/cii.decoder.d.ts +27 -1
- package/dist_ts/formats/cii/cii.decoder.js +61 -1
- package/dist_ts/formats/cii/cii.encoder.d.ts +14 -3
- package/dist_ts/formats/cii/cii.encoder.js +58 -6
- package/dist_ts/formats/cii/cii.types.d.ts +1 -0
- package/dist_ts/formats/cii/cii.types.js +3 -2
- package/dist_ts/formats/cii/facturx/facturx.decoder.d.ts +1 -1
- package/dist_ts/formats/cii/facturx/facturx.decoder.js +11 -8
- package/dist_ts/formats/cii/facturx/facturx.encoder.d.ts +2 -2
- package/dist_ts/formats/cii/facturx/facturx.encoder.js +18 -15
- package/dist_ts/formats/cii/zugferd/zugferd.decoder.d.ts +1 -1
- package/dist_ts/formats/cii/zugferd/zugferd.decoder.js +12 -10
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.d.ts +1 -1
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.js +26 -19
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.d.ts +19 -1
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.js +51 -10
- package/dist_ts/formats/ubl/generic/ubl.encoder.d.ts +23 -1
- package/dist_ts/formats/ubl/generic/ubl.encoder.js +69 -14
- package/dist_ts/formats/ubl/ubl.decoder.d.ts +1 -1
- package/dist_ts/formats/ubl/ubl.encoder.d.ts +16 -3
- package/dist_ts/formats/ubl/ubl.encoder.js +75 -13
- package/dist_ts/formats/ubl/ubl.types.d.ts +6 -0
- package/dist_ts/formats/ubl/ubl.types.js +9 -3
- package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.d.ts +6 -1
- package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.js +46 -14
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.d.ts +1 -1
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.js +7 -12
- package/dist_ts/formats/utils/date.value.d.ts +28 -0
- package/dist_ts/formats/utils/date.value.js +50 -0
- package/dist_ts/formats/utils/document.typecode.d.ts +3 -3
- package/dist_ts/formats/utils/document.typecode.js +8 -4
- package/dist_ts/formats/utils/format.detector.js +6 -4
- package/dist_ts/formats/utils/payment.terms.d.ts +18 -0
- package/dist_ts/formats/utils/payment.terms.js +32 -0
- package/dist_ts/formats/utils/preceding.invoice.d.ts +26 -0
- package/dist_ts/formats/utils/preceding.invoice.js +52 -0
- package/dist_ts/formats/validation/integrated.validator.js +6 -3
- package/dist_ts/formats/validation/xrechnung.validator.js +6 -4
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/index.js +1 -1
- package/dist_ts/interfaces/common.d.ts +6 -2
- package/package.json +3 -3
- package/readme.md +77 -10
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/einvoice.ts +18 -1
- package/ts/formats/base/base.decoder.ts +3 -2
- package/ts/formats/base/base.encoder.ts +1 -1
- package/ts/formats/cii/cii.decoder.ts +74 -1
- package/ts/formats/cii/cii.encoder.ts +62 -6
- package/ts/formats/cii/cii.types.ts +2 -1
- package/ts/formats/cii/facturx/facturx.decoder.ts +11 -7
- package/ts/formats/cii/facturx/facturx.encoder.ts +18 -14
- package/ts/formats/cii/zugferd/zugferd.decoder.ts +12 -9
- package/ts/formats/cii/zugferd/zugferd.encoder.ts +26 -18
- package/ts/formats/cii/zugferd/zugferd.v1.decoder.ts +58 -9
- package/ts/formats/ubl/generic/ubl.encoder.ts +76 -13
- package/ts/formats/ubl/ubl.decoder.ts +1 -1
- package/ts/formats/ubl/ubl.encoder.ts +77 -13
- package/ts/formats/ubl/ubl.types.ts +8 -2
- package/ts/formats/ubl/xrechnung/xrechnung.decoder.ts +56 -13
- package/ts/formats/ubl/xrechnung/xrechnung.encoder.ts +7 -12
- package/ts/formats/utils/date.value.ts +52 -0
- package/ts/formats/utils/document.typecode.ts +7 -3
- package/ts/formats/utils/format.detector.ts +5 -5
- package/ts/formats/utils/payment.terms.ts +37 -0
- package/ts/formats/utils/preceding.invoice.ts +74 -0
- package/ts/formats/validation/integrated.validator.ts +5 -2
- package/ts/formats/validation/xrechnung.validator.ts +5 -3
- package/ts/index.ts +3 -0
- package/ts/interfaces/common.ts +6 -1
|
@@ -7,6 +7,7 @@ import { EInvoiceFormatError } from '../../errors.js';
|
|
|
7
7
|
*/
|
|
8
8
|
const DOCUMENT_TYPE_CODES: Record<TAccountingDocType, string> = {
|
|
9
9
|
'invoice': '380',
|
|
10
|
+
'corrected-invoice': '384',
|
|
10
11
|
'creditnote': '381',
|
|
11
12
|
'debitnote': '383',
|
|
12
13
|
'self-billed-invoice': '389',
|
|
@@ -42,9 +43,9 @@ export const getDocumentTypeCode = (accountingDocType: TAccountingDocType): stri
|
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
|
-
* The accounting document type of a decoded type code. 383 and 389 have
|
|
46
|
-
* type of their own; the remaining credit note related codes are credit
|
|
47
|
-
* notes; everything else is an invoice, which covers 380
|
|
46
|
+
* The accounting document type of a decoded type code. 383, 384 and 389 have
|
|
47
|
+
* a type of their own; the remaining credit note related codes are credit
|
|
48
|
+
* notes; everything else is an invoice, which covers 380 and the other
|
|
48
49
|
* invoice related codes (326, 386, 875, ...) the envelope has no name for.
|
|
49
50
|
* A missing or unlisted code stays an invoice as well: the document is an
|
|
50
51
|
* invoice document, and reporting the code is the validators' job (BR-04,
|
|
@@ -55,6 +56,9 @@ export const getAccountingDocType = (typeCode: string): TAccountingDocType => {
|
|
|
55
56
|
if (code === DOCUMENT_TYPE_CODES['debitnote']) {
|
|
56
57
|
return 'debitnote';
|
|
57
58
|
}
|
|
59
|
+
if (code === DOCUMENT_TYPE_CODES['corrected-invoice']) {
|
|
60
|
+
return 'corrected-invoice';
|
|
61
|
+
}
|
|
58
62
|
if (code === DOCUMENT_TYPE_CODES['self-billed-invoice']) {
|
|
59
63
|
return 'self-billed-invoice';
|
|
60
64
|
}
|
|
@@ -80,7 +80,9 @@ export class FormatDetector {
|
|
|
80
80
|
);
|
|
81
81
|
const customizationId = customizationIdMatch?.[1] ?? '';
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
// both identifier families: urn:xeinkauf.de:kosit:xrechnung_3.0 (XRechnung 3.0) and
|
|
84
|
+
// urn:xoev-de:kosit:standard:xrechnung_x.y (XRechnung 1.x and 2.x)
|
|
85
|
+
if (/xrechnung/i.test(customizationId)) {
|
|
84
86
|
return InvoiceFormat.XRECHNUNG;
|
|
85
87
|
}
|
|
86
88
|
return InvoiceFormat.UBL;
|
|
@@ -133,10 +135,8 @@ export class FormatDetector {
|
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
// Check for obvious XRechnung indicators
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
/urn:xoev-de:kosit:standard:xrechnung/i.test(sample)
|
|
139
|
-
) {
|
|
138
|
+
// covers both identifier families (urn:xeinkauf.de:kosit:xrechnung_, urn:xoev-de:kosit:standard:xrechnung_)
|
|
139
|
+
if (/xrechnung/i.test(sample)) {
|
|
140
140
|
return InvoiceFormat.XRECHNUNG;
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { getWritableDueDate } from './date.value.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The payment terms note (BT-20) the encoders write: the due date (BT-9) the
|
|
5
|
+
* document states, in the document language (German for `de`, English
|
|
6
|
+
* otherwise). It names the date rather than a count of days, so it reads
|
|
7
|
+
* correctly for every term:
|
|
8
|
+
* - a term of 0 days: "Zahlbar sofort" / "Payable immediately";
|
|
9
|
+
* - a later due date: "Zahlbar bis 04.10.2026" / "Payable by 2026-10-04";
|
|
10
|
+
* - an earlier due date, which is legitimate when the payment fell due before
|
|
11
|
+
* the invoice was issued, as with an agreed advance payment or an invoice
|
|
12
|
+
* issued after the contractual due date: "Fällig seit dem 03.09.2026" /
|
|
13
|
+
* "Due since 2026-09-03".
|
|
14
|
+
* A term that is no whole number of days is refused by `getWritableDueDate`.
|
|
15
|
+
* @param issueTimestamp The issue date (BT-2)
|
|
16
|
+
* @param dueInDays The payment term in days, as the document states it
|
|
17
|
+
* @param language The document language
|
|
18
|
+
* @param targetFormat The format being written
|
|
19
|
+
*/
|
|
20
|
+
export const getPaymentTermsNote = (
|
|
21
|
+
issueTimestamp: unknown,
|
|
22
|
+
dueInDays: unknown,
|
|
23
|
+
language: string | undefined,
|
|
24
|
+
targetFormat: string,
|
|
25
|
+
): string => {
|
|
26
|
+
const dueDate = getWritableDueDate(issueTimestamp, dueInDays, targetFormat);
|
|
27
|
+
const isoDate = dueDate.toISOString().slice(0, 10);
|
|
28
|
+
const german = (language ?? '').toLowerCase().startsWith('de');
|
|
29
|
+
const germanDate = `${isoDate.slice(8, 10)}.${isoDate.slice(5, 7)}.${isoDate.slice(0, 4)}`;
|
|
30
|
+
if (dueInDays === 0) {
|
|
31
|
+
return german ? 'Zahlbar sofort' : 'Payable immediately';
|
|
32
|
+
}
|
|
33
|
+
if ((dueInDays as number) > 0) {
|
|
34
|
+
return german ? `Zahlbar bis ${germanDate}` : `Payable by ${isoDate}`;
|
|
35
|
+
}
|
|
36
|
+
return german ? `Fällig seit dem ${germanDate}` : `Due since ${isoDate}`;
|
|
37
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TAccountingDoc,
|
|
3
|
+
TAccountingDocType,
|
|
4
|
+
TCorrectedInvoiceReference,
|
|
5
|
+
TRelatedDocument,
|
|
6
|
+
} from '../../interfaces/common.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* One preceding invoice reference (BG-3): the number of the preceding invoice
|
|
10
|
+
* (BT-25) and, when the document states it, its issue date (BT-26).
|
|
11
|
+
*/
|
|
12
|
+
export type TPrecedingInvoiceReference = TCorrectedInvoiceReference;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The preceding invoice references (BG-3) an encoder writes for a document,
|
|
16
|
+
* taken only from what the document states:
|
|
17
|
+
* - a corrected invoice: the invoice it corrects (`correctedInvoice`);
|
|
18
|
+
* - a corrected invoice or a credit note: every related document with the
|
|
19
|
+
* relation `'corrects'`.
|
|
20
|
+
* Other documents and other relations write none.
|
|
21
|
+
*/
|
|
22
|
+
export const getPrecedingInvoiceReferences = (
|
|
23
|
+
accountingDoc: TAccountingDoc,
|
|
24
|
+
): TPrecedingInvoiceReference[] => {
|
|
25
|
+
const references: TPrecedingInvoiceReference[] = [];
|
|
26
|
+
if (accountingDoc.accountingDocType === 'corrected-invoice' && accountingDoc.correctedInvoice) {
|
|
27
|
+
references.push(accountingDoc.correctedInvoice);
|
|
28
|
+
}
|
|
29
|
+
if (
|
|
30
|
+
accountingDoc.accountingDocType === 'corrected-invoice' ||
|
|
31
|
+
accountingDoc.accountingDocType === 'creditnote'
|
|
32
|
+
) {
|
|
33
|
+
for (const relatedDocument of accountingDoc.relatedDocuments ?? []) {
|
|
34
|
+
if (relatedDocument.relationType === 'corrects') {
|
|
35
|
+
references.push(
|
|
36
|
+
relatedDocument.issueDate === undefined
|
|
37
|
+
? { documentId: relatedDocument.documentId }
|
|
38
|
+
: { documentId: relatedDocument.documentId, issueDate: relatedDocument.issueDate },
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return references;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The envelope fields for the preceding invoice references a decoder read, the
|
|
48
|
+
* inverse of {@link getPrecedingInvoiceReferences}: on a corrected invoice the
|
|
49
|
+
* first reference is the invoice it corrects and further ones are related
|
|
50
|
+
* documents it corrects; on a credit note every reference is a related
|
|
51
|
+
* document it corrects. Other documents keep no reference, as before.
|
|
52
|
+
*/
|
|
53
|
+
export const getPrecedingInvoiceFields = (
|
|
54
|
+
accountingDocType: TAccountingDocType,
|
|
55
|
+
references: TPrecedingInvoiceReference[],
|
|
56
|
+
): { correctedInvoice?: TCorrectedInvoiceReference; relatedDocuments?: TRelatedDocument[] } => {
|
|
57
|
+
const asRelated = (reference: TPrecedingInvoiceReference): TRelatedDocument => ({
|
|
58
|
+
relationType: 'corrects',
|
|
59
|
+
...reference,
|
|
60
|
+
});
|
|
61
|
+
if (references.length === 0) {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
if (accountingDocType === 'corrected-invoice') {
|
|
65
|
+
const [correctedInvoice, ...furtherReferences] = references;
|
|
66
|
+
return furtherReferences.length === 0
|
|
67
|
+
? { correctedInvoice }
|
|
68
|
+
: { correctedInvoice, relatedDocuments: furtherReferences.map(asRelated) };
|
|
69
|
+
}
|
|
70
|
+
if (accountingDocType === 'creditnote') {
|
|
71
|
+
return { relatedDocuments: references.map(asRelated) };
|
|
72
|
+
}
|
|
73
|
+
return {};
|
|
74
|
+
};
|
|
@@ -11,6 +11,7 @@ import { EN16931BusinessRulesValidator } from './en16931.business-rules.validato
|
|
|
11
11
|
import { CodeListValidator } from './codelist.validator.js';
|
|
12
12
|
import type { ValidationResult, ValidationOptions, ValidationReport } from './validation.types.js';
|
|
13
13
|
import type { EInvoice } from '../../einvoice.js';
|
|
14
|
+
import { UBL_CUSTOMIZATION_IDS } from '../ubl/ubl.types.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Main validator that combines all validation capabilities
|
|
@@ -196,9 +197,11 @@ export class MainValidator {
|
|
|
196
197
|
const profileId = invoice.metadata?.profileId || '';
|
|
197
198
|
const customizationId = invoice.metadata?.customizationId || '';
|
|
198
199
|
|
|
200
|
+
// XRechnung 3.0 (its extension and CVD identifiers begin with it), the identifier
|
|
201
|
+
// family of XRechnung 1.x and 2.x, and any identifier naming XRechnung
|
|
199
202
|
const xrechnungProfiles = [
|
|
200
|
-
|
|
201
|
-
'urn:
|
|
203
|
+
UBL_CUSTOMIZATION_IDS.XRECHNUNG,
|
|
204
|
+
'urn:xoev-de:kosit:standard:xrechnung_',
|
|
202
205
|
'xrechnung'
|
|
203
206
|
];
|
|
204
207
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { EInvoice } from '../../einvoice.js';
|
|
10
10
|
import type { ValidationResult } from './validation.types.js';
|
|
11
|
+
import { UBL_CUSTOMIZATION_IDS } from '../ubl/ubl.types.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* XRechnung-specific validator implementing German CIUS rules
|
|
@@ -62,10 +63,11 @@ export class XRechnungValidator {
|
|
|
62
63
|
const customizationId = invoice.metadata?.customizationId || '';
|
|
63
64
|
|
|
64
65
|
// XRechnung profile identifiers
|
|
66
|
+
// XRechnung 3.0 (its extension and CVD identifiers begin with it), the identifier
|
|
67
|
+
// family of XRechnung 1.x and 2.x, and any identifier naming XRechnung
|
|
65
68
|
const xrechnungProfiles = [
|
|
66
|
-
|
|
67
|
-
'urn:
|
|
68
|
-
'urn:cen.eu:en16931:2017:xrechnung',
|
|
69
|
+
UBL_CUSTOMIZATION_IDS.XRECHNUNG,
|
|
70
|
+
'urn:xoev-de:kosit:standard:xrechnung_',
|
|
69
71
|
'xrechnung'
|
|
70
72
|
];
|
|
71
73
|
|
package/ts/index.ts
CHANGED
|
@@ -74,6 +74,9 @@ import { ZUGFeRDV1Decoder } from './formats/cii/zugferd/zugferd.v1.decoder.js';
|
|
|
74
74
|
export type {
|
|
75
75
|
// Common interfaces
|
|
76
76
|
TInvoice,
|
|
77
|
+
TCorrectedInvoice,
|
|
78
|
+
TCorrectedInvoiceReference,
|
|
79
|
+
TInvoiceCorrection,
|
|
77
80
|
TCreditNote,
|
|
78
81
|
TDebitNote,
|
|
79
82
|
TSelfBilledInvoice,
|
package/ts/interfaces/common.ts
CHANGED
|
@@ -83,11 +83,16 @@ export interface IPdf {
|
|
|
83
83
|
// Re-export types from tsclass for convenience
|
|
84
84
|
import type {
|
|
85
85
|
TInvoice,
|
|
86
|
+
TCorrectedInvoice,
|
|
86
87
|
TDebitNote,
|
|
87
88
|
TSelfBilledInvoice,
|
|
88
89
|
} from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
89
90
|
|
|
90
91
|
export type { TInvoice } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
92
|
+
export type { TCorrectedInvoice } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
93
|
+
export type { TCorrectedInvoiceReference } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
94
|
+
export type { TInvoiceCorrection } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
95
|
+
export type { TRelatedDocument } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
91
96
|
export type { TCreditNote } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
92
97
|
export type { TDebitNote } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
93
98
|
export type { TSelfBilledInvoice } from '@tsclass/tsclass/dist_ts/finance/index.js';
|
|
@@ -100,7 +105,7 @@ export type { TAccountingDocEnvelope } from '@tsclass/tsclass/dist_ts/finance/in
|
|
|
100
105
|
* `Invoice` root and the CII type codes of the invoice family. Only a credit
|
|
101
106
|
* note has a document shape of its own.
|
|
102
107
|
*/
|
|
103
|
-
export type TInvoiceDocument = TInvoice | TDebitNote | TSelfBilledInvoice;
|
|
108
|
+
export type TInvoiceDocument = TInvoice | TCorrectedInvoice | TDebitNote | TSelfBilledInvoice;
|
|
104
109
|
export type { TContact } from '@tsclass/tsclass/dist_ts/business/index.js';
|
|
105
110
|
export type { TLetterEnvelope } from '@tsclass/tsclass/dist_ts/business/index.js';
|
|
106
111
|
export type { TDocumentEnvelope } from '@tsclass/tsclass/dist_ts/business/index.js';
|