@fin.cx/einvoice 8.3.1 → 10.0.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 +2 -2
- package/dist_ts/einvoice.d.ts +26 -0
- package/dist_ts/einvoice.js +61 -3
- package/dist_ts/formats/base/base.decoder.d.ts +18 -1
- package/dist_ts/formats/base/base.decoder.js +30 -17
- package/dist_ts/formats/cii/cii.decoder.d.ts +89 -6
- package/dist_ts/formats/cii/cii.decoder.js +125 -30
- package/dist_ts/formats/cii/cii.encoder.d.ts +71 -1
- package/dist_ts/formats/cii/cii.encoder.js +195 -12
- package/dist_ts/formats/cii/cii.types.d.ts +2 -5
- package/dist_ts/formats/cii/cii.types.js +7 -9
- package/dist_ts/formats/cii/cii.validator.d.ts +13 -6
- package/dist_ts/formats/cii/cii.validator.js +29 -30
- package/dist_ts/formats/cii/facturx/facturx.decoder.js +19 -3
- package/dist_ts/formats/cii/facturx/facturx.encoder.d.ts +0 -6
- package/dist_ts/formats/cii/facturx/facturx.encoder.js +17 -26
- package/dist_ts/formats/cii/facturx/facturx.types.d.ts +0 -5
- package/dist_ts/formats/cii/facturx/facturx.types.js +1 -8
- package/dist_ts/formats/cii/facturx/facturx.validator.d.ts +0 -5
- package/dist_ts/formats/cii/facturx/facturx.validator.js +5 -29
- package/dist_ts/formats/cii/zugferd/zugferd.decoder.js +19 -2
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.d.ts +0 -7
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.js +15 -68
- package/dist_ts/formats/cii/zugferd/zugferd.types.d.ts +0 -5
- package/dist_ts/formats/cii/zugferd/zugferd.types.js +1 -8
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.d.ts +26 -0
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.js +47 -1
- package/dist_ts/formats/cii/zugferd/zugferd.validator.js +6 -2
- package/dist_ts/formats/semantic/semantic.adapter.js +29 -20
- package/dist_ts/formats/semantic/semantic.validator.js +17 -2
- package/dist_ts/formats/ubl/en16931.ubl.validator.d.ts +0 -4
- package/dist_ts/formats/ubl/en16931.ubl.validator.js +5 -42
- package/dist_ts/formats/ubl/generic/ubl.encoder.js +29 -26
- package/dist_ts/formats/ubl/ubl.decoder.d.ts +4 -0
- package/dist_ts/formats/ubl/ubl.decoder.js +9 -1
- package/dist_ts/formats/ubl/ubl.encoder.js +13 -5
- package/dist_ts/formats/ubl/ubl.validator.d.ts +13 -0
- package/dist_ts/formats/ubl/ubl.validator.js +28 -1
- package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.js +14 -1
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.d.ts +0 -7
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.js +30 -45
- package/dist_ts/formats/ubl/xrechnung.validator.d.ts +5 -4
- package/dist_ts/formats/ubl/xrechnung.validator.js +71 -68
- package/dist_ts/formats/utils/date.value.d.ts +11 -0
- package/dist_ts/formats/utils/date.value.js +33 -1
- package/dist_ts/formats/utils/document.totals.d.ts +1 -3
- package/dist_ts/formats/utils/document.totals.js +1 -2
- package/dist_ts/formats/utils/format.detector.js +16 -10
- package/dist_ts/formats/utils/paid.amount.d.ts +44 -0
- package/dist_ts/formats/utils/paid.amount.js +124 -0
- package/dist_ts/formats/utils/party.contact.d.ts +16 -0
- package/dist_ts/formats/utils/party.contact.js +16 -0
- package/dist_ts/formats/utils/party.identifier.d.ts +28 -0
- package/dist_ts/formats/utils/party.identifier.js +49 -0
- package/dist_ts/formats/utils/peppol.profile.d.ts +10 -0
- package/dist_ts/formats/utils/peppol.profile.js +12 -0
- package/dist_ts/formats/utils/preceding.invoice.d.ts +12 -2
- package/dist_ts/formats/utils/preceding.invoice.js +22 -3
- package/dist_ts/formats/utils/seller.identifier.d.ts +46 -0
- package/dist_ts/formats/utils/seller.identifier.js +78 -0
- package/dist_ts/formats/utils/stated.values.d.ts +80 -0
- package/dist_ts/formats/utils/stated.values.js +418 -0
- package/dist_ts/formats/utils/vat.category.d.ts +30 -2
- package/dist_ts/formats/utils/vat.category.js +36 -6
- package/dist_ts/formats/utils/vat.id.d.ts +18 -0
- package/dist_ts/formats/utils/vat.id.js +22 -0
- package/dist_ts/formats/validation/conformance.harness.js +6 -6
- package/dist_ts/formats/validation/en16931.business-rules.validator.js +4 -19
- package/dist_ts/formats/validation/facturx.validator.js +6 -6
- package/dist_ts/formats/validation/integrated.validator.js +4 -13
- package/dist_ts/formats/validation/peppol.validator.js +6 -13
- package/dist_ts/formats/validation/validation.types.d.ts +5 -0
- package/dist_ts/formats/validation/validation.types.js +6 -1
- package/dist_ts/formats/validation/vat-categories.validator.d.ts +21 -42
- package/dist_ts/formats/validation/vat-categories.validator.js +137 -431
- package/dist_ts/formats/validation/xrechnung.validator.d.ts +11 -58
- package/dist_ts/formats/validation/xrechnung.validator.js +58 -324
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +1 -1
- package/dist_ts/interfaces/common.d.ts +1 -0
- package/dist_ts/interfaces/en16931-metadata.d.ts +0 -5
- package/dist_ts/interfaces/stated.values.d.ts +93 -0
- package/dist_ts/interfaces/stated.values.js +2 -0
- package/package.json +2 -2
- package/readme.md +182 -6
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/einvoice.ts +70 -2
- package/ts/formats/base/base.decoder.ts +32 -29
- package/ts/formats/cii/cii.decoder.ts +159 -32
- package/ts/formats/cii/cii.encoder.ts +210 -14
- package/ts/formats/cii/cii.types.ts +7 -9
- package/ts/formats/cii/cii.validator.ts +30 -32
- package/ts/formats/cii/facturx/facturx.decoder.ts +21 -2
- package/ts/formats/cii/facturx/facturx.encoder.ts +19 -26
- package/ts/formats/cii/facturx/facturx.types.ts +0 -9
- package/ts/formats/cii/facturx/facturx.validator.ts +5 -43
- package/ts/formats/cii/zugferd/zugferd.decoder.ts +21 -1
- package/ts/formats/cii/zugferd/zugferd.encoder.ts +16 -73
- package/ts/formats/cii/zugferd/zugferd.types.ts +0 -9
- package/ts/formats/cii/zugferd/zugferd.v1.decoder.ts +66 -0
- package/ts/formats/cii/zugferd/zugferd.validator.ts +5 -1
- package/ts/formats/semantic/semantic.adapter.ts +28 -19
- package/ts/formats/semantic/semantic.validator.ts +17 -1
- package/ts/formats/ubl/en16931.ubl.validator.ts +5 -64
- package/ts/formats/ubl/generic/ubl.encoder.ts +31 -25
- package/ts/formats/ubl/ubl.decoder.ts +12 -0
- package/ts/formats/ubl/ubl.encoder.ts +12 -4
- package/ts/formats/ubl/ubl.validator.ts +29 -0
- package/ts/formats/ubl/xrechnung/xrechnung.decoder.ts +13 -0
- package/ts/formats/ubl/xrechnung/xrechnung.encoder.ts +33 -45
- package/ts/formats/ubl/xrechnung.validator.ts +75 -127
- package/ts/formats/utils/date.value.ts +33 -0
- package/ts/formats/utils/document.totals.ts +1 -4
- package/ts/formats/utils/format.detector.ts +15 -9
- package/ts/formats/utils/paid.amount.ts +160 -0
- package/ts/formats/utils/party.contact.ts +30 -0
- package/ts/formats/utils/party.identifier.ts +61 -0
- package/ts/formats/utils/peppol.profile.ts +13 -0
- package/ts/formats/utils/preceding.invoice.ts +23 -2
- package/ts/formats/utils/seller.identifier.ts +102 -0
- package/ts/formats/utils/stated.values.ts +499 -0
- package/ts/formats/utils/vat.category.ts +47 -5
- package/ts/formats/utils/vat.id.ts +24 -0
- package/ts/formats/validation/conformance.harness.ts +5 -5
- package/ts/formats/validation/en16931.business-rules.validator.ts +3 -26
- package/ts/formats/validation/facturx.validator.ts +5 -5
- package/ts/formats/validation/integrated.validator.ts +3 -16
- package/ts/formats/validation/peppol.validator.ts +5 -16
- package/ts/formats/validation/validation.types.ts +7 -1
- package/ts/formats/validation/vat-categories.validator.ts +179 -761
- package/ts/formats/validation/xrechnung.validator.ts +61 -382
- package/ts/index.ts +9 -0
- package/ts/interfaces/common.ts +1 -0
- package/ts/interfaces/en16931-metadata.ts +3 -8
- package/ts/interfaces/stated.values.ts +94 -0
- package/ts/readme.md +1 -1
- package/dist_ts/formats/utils/eu.memberstates.d.ts +0 -11
- package/dist_ts/formats/utils/eu.memberstates.js +0 -16
- package/ts/formats/utils/eu.memberstates.ts +0 -16
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { CIIBaseEncoder } from '../cii.encoder.js';
|
|
2
2
|
import type { TAccountingDoc, TCreditNote, TInvoiceDocument } from '../../../interfaces/common.js';
|
|
3
|
-
import { FACTURX_PROFILE_IDS } from './facturx.types.js';
|
|
4
3
|
import { DOMParser, XMLSerializer } from '../../../plugins.js';
|
|
5
4
|
import { getDocumentTypeCode } from '../../utils/document.typecode.js';
|
|
6
5
|
import { computeDocumentTotals } from '../../utils/document.totals.js';
|
|
6
|
+
import { getPaymentTotals } from '../../utils/paid.amount.js';
|
|
7
7
|
import { toPlainDecimalString } from '../../utils/number.text.js';
|
|
8
8
|
import { resolveCountryCode } from '../../utils/country.code.js';
|
|
9
|
-
import {
|
|
9
|
+
import { getWritableDueDate } from '../../utils/date.value.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Encoder for Factur-X invoice format
|
|
@@ -93,15 +93,7 @@ export class FacturXEncoder extends CIIBaseEncoder {
|
|
|
93
93
|
// Add ID element with profile
|
|
94
94
|
const idElement = doc.createElement('ram:ID');
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
let profileId = FACTURX_PROFILE_IDS.EN16931;
|
|
98
|
-
if (this.profile === 'BASIC') {
|
|
99
|
-
profileId = FACTURX_PROFILE_IDS.BASIC;
|
|
100
|
-
} else if (this.profile === 'MINIMUM') {
|
|
101
|
-
profileId = FACTURX_PROFILE_IDS.MINIMUM;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
idElement.textContent = profileId;
|
|
96
|
+
idElement.textContent = this.getProfileId();
|
|
105
97
|
guidelineElement.appendChild(idElement);
|
|
106
98
|
}
|
|
107
99
|
|
|
@@ -208,9 +200,14 @@ export class FacturXEncoder extends CIIBaseEncoder {
|
|
|
208
200
|
const agreementElement = doc.createElement('ram:ApplicableHeaderTradeAgreement');
|
|
209
201
|
transactionElement.appendChild(agreementElement);
|
|
210
202
|
|
|
203
|
+
// Buyer reference (BT-10)
|
|
204
|
+
this.addBuyerReference(doc, agreementElement, invoice);
|
|
205
|
+
|
|
211
206
|
// Add seller
|
|
212
207
|
const sellerElement = doc.createElement('ram:SellerTradeParty');
|
|
213
208
|
this.addPartyInfo(doc, sellerElement, invoice.from, 'seller');
|
|
209
|
+
// Seller electronic address (BT-34)
|
|
210
|
+
this.addSellerElectronicAddress(doc, sellerElement, invoice);
|
|
214
211
|
agreementElement.appendChild(sellerElement);
|
|
215
212
|
|
|
216
213
|
// Add buyer
|
|
@@ -227,6 +224,9 @@ export class FacturXEncoder extends CIIBaseEncoder {
|
|
|
227
224
|
* @param partyRole Whether the party is the seller or the buyer
|
|
228
225
|
*/
|
|
229
226
|
private addPartyInfo(doc: Document, partyElement: Element, party: any, partyRole: 'seller' | 'buyer'): void {
|
|
227
|
+
// Party identifiers (BT-29 seller, BT-46 buyer)
|
|
228
|
+
this.addPartyIdentifiers(doc, partyElement, party);
|
|
229
|
+
|
|
230
230
|
// Add name
|
|
231
231
|
const nameElement = doc.createElement('ram:Name');
|
|
232
232
|
nameElement.textContent = party.name;
|
|
@@ -380,6 +380,9 @@ export class FacturXEncoder extends CIIBaseEncoder {
|
|
|
380
380
|
|
|
381
381
|
settlementElement.appendChild(paymentTermsElement);
|
|
382
382
|
|
|
383
|
+
// Invoicing period (BG-14)
|
|
384
|
+
this.addInvoicingPeriod(doc, settlementElement, invoice);
|
|
385
|
+
|
|
383
386
|
// Add totals, in the order of the CII schema
|
|
384
387
|
const monetarySummationElement = doc.createElement('ram:SpecifiedTradeSettlementHeaderMonetarySummation');
|
|
385
388
|
const appendAmount = (name: string, value: { toFixed(decimalPlaces: number): string }, withCurrency = false) => {
|
|
@@ -394,7 +397,11 @@ export class FacturXEncoder extends CIIBaseEncoder {
|
|
|
394
397
|
appendAmount('ram:TaxBasisTotalAmount', totals.taxBasisTotal); // BT-109
|
|
395
398
|
appendAmount('ram:TaxTotalAmount', totals.taxTotal, true); // BT-110
|
|
396
399
|
appendAmount('ram:GrandTotalAmount', totals.grandTotal); // BT-112
|
|
397
|
-
|
|
400
|
+
const payment = getPaymentTotals(invoice, totals);
|
|
401
|
+
if (payment.paidAmount) {
|
|
402
|
+
appendAmount('ram:TotalPrepaidAmount', payment.paidAmount); // BT-113
|
|
403
|
+
}
|
|
404
|
+
appendAmount('ram:DuePayableAmount', payment.duePayable); // BT-115
|
|
398
405
|
|
|
399
406
|
settlementElement.appendChild(monetarySummationElement);
|
|
400
407
|
}
|
|
@@ -500,18 +507,4 @@ export class FacturXEncoder extends CIIBaseEncoder {
|
|
|
500
507
|
}
|
|
501
508
|
}
|
|
502
509
|
}
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* Formats a date as YYYYMMDD
|
|
506
|
-
* @param timestamp Timestamp to format
|
|
507
|
-
* @returns Formatted date string
|
|
508
|
-
*/
|
|
509
|
-
private formatDateYYYYMMDD(timestamp: number, field: string): string {
|
|
510
|
-
const date = getWritableDate(timestamp, field, 'cii');
|
|
511
|
-
// the UTC fields: a calendar day is its UTC midnight, whatever the server's zone
|
|
512
|
-
const year = date.getUTCFullYear();
|
|
513
|
-
const month = (date.getUTCMonth() + 1).toString().padStart(2, '0');
|
|
514
|
-
const day = date.getUTCDate().toString().padStart(2, '0');
|
|
515
|
-
return `${year}${month}${day}`;
|
|
516
|
-
}
|
|
517
510
|
}
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { CIIProfile, CII_PROFILE_IDS } from '../cii.types.js';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Factur-X specific constants and types
|
|
5
3
|
*/
|
|
6
4
|
|
|
7
|
-
// Factur-X profile IDs
|
|
8
|
-
export const FACTURX_PROFILE_IDS = {
|
|
9
|
-
MINIMUM: CII_PROFILE_IDS.FACTURX_MINIMUM,
|
|
10
|
-
BASIC: CII_PROFILE_IDS.FACTURX_BASIC,
|
|
11
|
-
EN16931: CII_PROFILE_IDS.FACTURX_EN16931
|
|
12
|
-
};
|
|
13
|
-
|
|
14
5
|
// Factur-X PDF attachment filename
|
|
15
6
|
export const FACTURX_ATTACHMENT_FILENAME = 'factur-x.xml';
|
|
16
7
|
|
|
@@ -59,8 +59,8 @@ export class FacturXValidator extends CIIBaseValidator {
|
|
|
59
59
|
|
|
60
60
|
let valid = true;
|
|
61
61
|
|
|
62
|
-
// BR-
|
|
63
|
-
valid = this.
|
|
62
|
+
// BR-CO-10 to BR-CO-17: the stated totals, VAT breakdown and line amounts agree with each other
|
|
63
|
+
valid = this.validateStatedTotals() && valid;
|
|
64
64
|
|
|
65
65
|
// BR-CO-3: Value added tax point date (BT-7) and Value added tax point date code (BT-8) are mutually exclusive
|
|
66
66
|
valid = this.validateMutuallyExclusiveFields() && valid;
|
|
@@ -70,6 +70,9 @@ export class FacturXValidator extends CIIBaseValidator {
|
|
|
70
70
|
// and/or the Seller tax representative VAT identifier (BT-63).
|
|
71
71
|
valid = this.validateSellerVatIdentifier() && valid;
|
|
72
72
|
|
|
73
|
+
// BR-CO-26: the seller states a seller, legal registration or VAT identifier
|
|
74
|
+
valid = this.validateSellerIdentifier() && valid;
|
|
75
|
+
|
|
73
76
|
// BR-23: every line has a unit code
|
|
74
77
|
valid = this.validateLineUnitCodePresence() && valid;
|
|
75
78
|
|
|
@@ -79,47 +82,6 @@ export class FacturXValidator extends CIIBaseValidator {
|
|
|
79
82
|
return valid;
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
/**
|
|
83
|
-
* Validates amount calculations in the invoice
|
|
84
|
-
* @returns True if amount validation passed
|
|
85
|
-
*/
|
|
86
|
-
private validateAmounts(): boolean {
|
|
87
|
-
if (!this.doc) return false;
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
// Extract amounts
|
|
91
|
-
const totalAmount = this.getNumber(
|
|
92
|
-
'//ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:GrandTotalAmount'
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const paidAmount = this.getNumber(
|
|
96
|
-
'//ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:TotalPrepaidAmount'
|
|
97
|
-
) || 0;
|
|
98
|
-
|
|
99
|
-
const dueAmount = this.getNumber(
|
|
100
|
-
'//ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:DuePayableAmount'
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
// Calculate expected due amount
|
|
104
|
-
const expectedDueAmount = totalAmount - paidAmount;
|
|
105
|
-
|
|
106
|
-
// Compare with a small tolerance for rounding errors
|
|
107
|
-
if (Math.abs(dueAmount - expectedDueAmount) > 0.01) {
|
|
108
|
-
this.addError(
|
|
109
|
-
'BR-16',
|
|
110
|
-
`Amount due for payment (${dueAmount}) must equal Invoice total amount with VAT (${totalAmount}) - Paid amount (${paidAmount})`,
|
|
111
|
-
'//ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation'
|
|
112
|
-
);
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return true;
|
|
117
|
-
} catch (error) {
|
|
118
|
-
this.addError('FX-AMOUNT', `Error validating amounts: ${error}`, '/');
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
85
|
/**
|
|
124
86
|
* Validates mutually exclusive fields
|
|
125
87
|
* @returns True if validation passed
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
import { business, finance } from '../../../plugins.js';
|
|
9
9
|
import { EN16931Validator } from '../../validation/en16931.validator.js';
|
|
10
10
|
import { getPrecedingInvoiceFields } from '../../utils/preceding.invoice.js';
|
|
11
|
+
import { readPaidAmount } from '../../utils/paid.amount.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Decoder for ZUGFeRD invoice format
|
|
@@ -87,6 +88,14 @@ export class ZUGFeRDDecoder extends CIIBaseDecoder {
|
|
|
87
88
|
// Reverse charge: every line has the VAT category AE
|
|
88
89
|
const reverseCharge = this.isReverseChargeDocument();
|
|
89
90
|
|
|
91
|
+
// the invoicing period (BG-14) and the seller electronic address (BT-34), when stated
|
|
92
|
+
const invoicingPeriod = this.invoicingPeriodFields(this.extractInvoicingPeriod());
|
|
93
|
+
// the buyer reference (BT-10), when stated
|
|
94
|
+
const buyerReference = this.extractBuyerReference();
|
|
95
|
+
const electronicAddress = this.extractSellerElectronicAddress();
|
|
96
|
+
|
|
97
|
+
const paidAmount = readPaidAmount(this.getText('//ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:TotalPrepaidAmount'), 'zugferd');
|
|
98
|
+
|
|
90
99
|
// Create the common invoice data
|
|
91
100
|
const invoiceData = {
|
|
92
101
|
type: 'accounting-doc' as const,
|
|
@@ -113,8 +122,15 @@ export class ZUGFeRDDecoder extends CIIBaseDecoder {
|
|
|
113
122
|
notes: notes,
|
|
114
123
|
// the day of supply as the document states it (BT-72)
|
|
115
124
|
...(deliveryDate === undefined ? {} : { deliveryDate }),
|
|
125
|
+
...invoicingPeriod,
|
|
126
|
+
// the specification identifier (BT-24), with the metadata of a one-date period
|
|
127
|
+
...this.metadataFields(invoicingPeriod),
|
|
128
|
+
...(buyerReference === undefined ? {} : { buyerReference }),
|
|
129
|
+
...(electronicAddress === undefined ? {} : { electronicAddress }),
|
|
116
130
|
objectActions: [],
|
|
117
131
|
...getPrecedingInvoiceFields(accountingDocType, this.extractPrecedingInvoiceReferences()),
|
|
132
|
+
// the paid amount (BT-113); the amount due (BT-115) follows from it and the totals
|
|
133
|
+
...(paidAmount === undefined ? {} : { paidAmount }),
|
|
118
134
|
};
|
|
119
135
|
|
|
120
136
|
// Validate mandatory EN16931 fields unless validation is skipped
|
|
@@ -166,6 +182,9 @@ export class ZUGFeRDDecoder extends CIIBaseDecoder {
|
|
|
166
182
|
// the tax registration identifier (BT-32 for the seller), the Steuernummer: scheme FC
|
|
167
183
|
const taxNumber = this.getText(`${partyXPath}/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="FC"]`) || '';
|
|
168
184
|
|
|
185
|
+
// the party identifiers (BT-29 seller, BT-46 buyer)
|
|
186
|
+
const additionalIdentifiers = this.extractPartyIdentifiers(partyXPath);
|
|
187
|
+
|
|
169
188
|
// Create contact object
|
|
170
189
|
return {
|
|
171
190
|
type: 'company',
|
|
@@ -179,7 +198,8 @@ export class ZUGFeRDDecoder extends CIIBaseDecoder {
|
|
|
179
198
|
registrationId: registrationId,
|
|
180
199
|
registrationName: '',
|
|
181
200
|
...(taxNumber ? { taxNumber } : {})
|
|
182
|
-
}
|
|
201
|
+
},
|
|
202
|
+
...(additionalIdentifiers.length > 0 ? { additionalIdentifiers } : {})
|
|
183
203
|
} as business.TContact;
|
|
184
204
|
}
|
|
185
205
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { CIIBaseEncoder } from '../cii.encoder.js';
|
|
2
2
|
import type { TAccountingDoc, TCreditNote, TInvoiceDocument } from '../../../interfaces/common.js';
|
|
3
|
-
import { ZUGFERD_PROFILE_IDS } from './zugferd.types.js';
|
|
4
|
-
import { CIIProfile } from '../cii.types.js';
|
|
5
3
|
import { DOMParser, XMLSerializer } from '../../../plugins.js';
|
|
6
4
|
import { getDocumentTypeCode } from '../../utils/document.typecode.js';
|
|
7
|
-
import {
|
|
5
|
+
import { getWritableDueDate } from '../../utils/date.value.js';
|
|
8
6
|
import { getPaymentTermsNote } from '../../utils/payment.terms.js';
|
|
9
7
|
import { computeDocumentTotals } from '../../utils/document.totals.js';
|
|
8
|
+
import { getPaymentTotals } from '../../utils/paid.amount.js';
|
|
10
9
|
import { toPlainDecimalString } from '../../utils/number.text.js';
|
|
11
10
|
import { resolveCountryCode } from '../../utils/country.code.js';
|
|
12
11
|
|
|
@@ -14,12 +13,6 @@ import { resolveCountryCode } from '../../utils/country.code.js';
|
|
|
14
13
|
* Encoder for ZUGFeRD invoice format
|
|
15
14
|
*/
|
|
16
15
|
export class ZUGFeRDEncoder extends CIIBaseEncoder {
|
|
17
|
-
constructor() {
|
|
18
|
-
super();
|
|
19
|
-
// Set default profile to BASIC
|
|
20
|
-
this.profile = CIIProfile.BASIC;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
16
|
/**
|
|
24
17
|
* Encodes a credit note into ZUGFeRD XML
|
|
25
18
|
* @param creditNote Credit note to encode
|
|
@@ -101,15 +94,7 @@ export class ZUGFeRDEncoder extends CIIBaseEncoder {
|
|
|
101
94
|
// Add ID element with profile
|
|
102
95
|
const idElement = doc.createElement('ram:ID');
|
|
103
96
|
|
|
104
|
-
|
|
105
|
-
let profileId = ZUGFERD_PROFILE_IDS.BASIC;
|
|
106
|
-
if (this.profile === CIIProfile.COMFORT) {
|
|
107
|
-
profileId = ZUGFERD_PROFILE_IDS.COMFORT;
|
|
108
|
-
} else if (this.profile === CIIProfile.EXTENDED) {
|
|
109
|
-
profileId = ZUGFERD_PROFILE_IDS.EXTENDED;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
idElement.textContent = profileId;
|
|
97
|
+
idElement.textContent = this.getProfileId();
|
|
113
98
|
guidelineElement.appendChild(idElement);
|
|
114
99
|
}
|
|
115
100
|
|
|
@@ -216,12 +201,8 @@ export class ZUGFeRDEncoder extends CIIBaseEncoder {
|
|
|
216
201
|
const agreementElement = doc.createElement('ram:ApplicableHeaderTradeAgreement');
|
|
217
202
|
transactionElement.appendChild(agreementElement);
|
|
218
203
|
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
const buyerRefElement = doc.createElement('ram:BuyerReference');
|
|
222
|
-
buyerRefElement.textContent = invoice.buyerReference;
|
|
223
|
-
agreementElement.appendChild(buyerRefElement);
|
|
224
|
-
}
|
|
204
|
+
// Buyer reference (BT-10)
|
|
205
|
+
this.addBuyerReference(doc, agreementElement, invoice);
|
|
225
206
|
|
|
226
207
|
// Add seller
|
|
227
208
|
const sellerElement = doc.createElement('ram:SellerTradeParty');
|
|
@@ -229,14 +210,7 @@ export class ZUGFeRDEncoder extends CIIBaseEncoder {
|
|
|
229
210
|
|
|
230
211
|
// Seller electronic address (BT-34): ram:URIUniversalCommunication/ram:URIID of the party; a
|
|
231
212
|
// trade contact (ram:DefinedTradeContact) has no URIID
|
|
232
|
-
|
|
233
|
-
const communicationElement = doc.createElement('ram:URIUniversalCommunication');
|
|
234
|
-
const uriElement = doc.createElement('ram:URIID');
|
|
235
|
-
uriElement.setAttribute('schemeID', invoice.electronicAddress.scheme);
|
|
236
|
-
uriElement.textContent = invoice.electronicAddress.value;
|
|
237
|
-
communicationElement.appendChild(uriElement);
|
|
238
|
-
sellerElement.appendChild(communicationElement);
|
|
239
|
-
}
|
|
213
|
+
this.addSellerElectronicAddress(doc, sellerElement, invoice);
|
|
240
214
|
|
|
241
215
|
agreementElement.appendChild(sellerElement);
|
|
242
216
|
|
|
@@ -254,6 +228,9 @@ export class ZUGFeRDEncoder extends CIIBaseEncoder {
|
|
|
254
228
|
* @param partyRole Whether the party is the seller or the buyer
|
|
255
229
|
*/
|
|
256
230
|
private addPartyInfo(doc: Document, partyElement: Element, party: any, partyRole: 'seller' | 'buyer'): void {
|
|
231
|
+
// Party identifiers (BT-29 seller, BT-46 buyer)
|
|
232
|
+
this.addPartyIdentifiers(doc, partyElement, party);
|
|
233
|
+
|
|
257
234
|
// Add name
|
|
258
235
|
const nameElement = doc.createElement('ram:Name');
|
|
259
236
|
nameElement.textContent = party.name;
|
|
@@ -442,31 +419,7 @@ export class ZUGFeRDEncoder extends CIIBaseEncoder {
|
|
|
442
419
|
this.addTaxDetails(doc, settlementElement, invoice);
|
|
443
420
|
|
|
444
421
|
// Invoicing period (BG-14): in the header settlement, where the CII schema puts it
|
|
445
|
-
|
|
446
|
-
const periodElement = doc.createElement('ram:BillingSpecifiedPeriod');
|
|
447
|
-
|
|
448
|
-
// Start date
|
|
449
|
-
if (invoice.periodOfPerformance.from !== undefined) {
|
|
450
|
-
const startDateElement = doc.createElement('ram:StartDateTime');
|
|
451
|
-
const startDateStringElement = doc.createElement('udt:DateTimeString');
|
|
452
|
-
startDateStringElement.setAttribute('format', '102'); // YYYYMMDD format
|
|
453
|
-
startDateStringElement.textContent = this.formatDateYYYYMMDD(invoice.periodOfPerformance.from, 'BT-73 invoicing period start date');
|
|
454
|
-
startDateElement.appendChild(startDateStringElement);
|
|
455
|
-
periodElement.appendChild(startDateElement);
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// End date
|
|
459
|
-
if (invoice.periodOfPerformance.to !== undefined) {
|
|
460
|
-
const endDateElement = doc.createElement('ram:EndDateTime');
|
|
461
|
-
const endDateStringElement = doc.createElement('udt:DateTimeString');
|
|
462
|
-
endDateStringElement.setAttribute('format', '102'); // YYYYMMDD format
|
|
463
|
-
endDateStringElement.textContent = this.formatDateYYYYMMDD(invoice.periodOfPerformance.to, 'BT-74 invoicing period end date');
|
|
464
|
-
endDateElement.appendChild(endDateStringElement);
|
|
465
|
-
periodElement.appendChild(endDateElement);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
settlementElement.appendChild(periodElement);
|
|
469
|
-
}
|
|
422
|
+
this.addInvoicingPeriod(doc, settlementElement, invoice);
|
|
470
423
|
|
|
471
424
|
// Add totals
|
|
472
425
|
this.addMonetarySummation(doc, settlementElement, invoice);
|
|
@@ -554,7 +507,11 @@ export class ZUGFeRDEncoder extends CIIBaseEncoder {
|
|
|
554
507
|
appendAmount('ram:TaxBasisTotalAmount', totals.taxBasisTotal); // BT-109
|
|
555
508
|
appendAmount('ram:TaxTotalAmount', totals.taxTotal, true); // BT-110
|
|
556
509
|
appendAmount('ram:GrandTotalAmount', totals.grandTotal); // BT-112
|
|
557
|
-
|
|
510
|
+
const payment = getPaymentTotals(invoice, totals);
|
|
511
|
+
if (payment.paidAmount) {
|
|
512
|
+
appendAmount('ram:TotalPrepaidAmount', payment.paidAmount); // BT-113
|
|
513
|
+
}
|
|
514
|
+
appendAmount('ram:DuePayableAmount', payment.duePayable); // BT-115
|
|
558
515
|
|
|
559
516
|
settlementElement.appendChild(monetarySummationElement);
|
|
560
517
|
}
|
|
@@ -658,18 +615,4 @@ export class ZUGFeRDEncoder extends CIIBaseEncoder {
|
|
|
658
615
|
}
|
|
659
616
|
}
|
|
660
617
|
}
|
|
661
|
-
|
|
662
|
-
/**
|
|
663
|
-
* Formats a date as YYYYMMDD
|
|
664
|
-
* @param timestamp Timestamp to format
|
|
665
|
-
* @returns Formatted date string
|
|
666
|
-
*/
|
|
667
|
-
private formatDateYYYYMMDD(timestamp: number, field: string): string {
|
|
668
|
-
const date = getWritableDate(timestamp, field, 'cii');
|
|
669
|
-
// the UTC fields: a calendar day is its UTC midnight, whatever the server's zone
|
|
670
|
-
const year = date.getUTCFullYear();
|
|
671
|
-
const month = (date.getUTCMonth() + 1).toString().padStart(2, '0');
|
|
672
|
-
const day = date.getUTCDate().toString().padStart(2, '0');
|
|
673
|
-
return `${year}${month}${day}`;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
618
|
+
}
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { CIIProfile, CII_PROFILE_IDS } from '../cii.types.js';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* ZUGFeRD specific constants and types
|
|
5
3
|
*/
|
|
6
4
|
|
|
7
|
-
// ZUGFeRD profile IDs
|
|
8
|
-
export const ZUGFERD_PROFILE_IDS = {
|
|
9
|
-
BASIC: CII_PROFILE_IDS.ZUGFERD_BASIC,
|
|
10
|
-
COMFORT: CII_PROFILE_IDS.ZUGFERD_COMFORT,
|
|
11
|
-
EXTENDED: CII_PROFILE_IDS.ZUGFERD_EXTENDED
|
|
12
|
-
};
|
|
13
|
-
|
|
14
5
|
// ZUGFeRD PDF attachment filename
|
|
15
6
|
export const ZUGFERD_ATTACHMENT_FILENAME = 'zugferd-invoice.xml';
|
|
16
7
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CIIBaseDecoder } from '../cii.decoder.js';
|
|
2
|
+
import type { ICIIInvoicingPeriod } from '../cii.decoder.js';
|
|
2
3
|
import type {
|
|
3
4
|
TAccountingDocEnvelope,
|
|
4
5
|
TAccountingDocType,
|
|
@@ -8,6 +9,8 @@ import type {
|
|
|
8
9
|
import { ZUGFERD_V1_NAMESPACES } from '../cii.types.js';
|
|
9
10
|
import { business, finance, xpath } from '../../../plugins.js';
|
|
10
11
|
import { EN16931Validator } from '../../validation/en16931.validator.js';
|
|
12
|
+
import { readPaidAmount } from '../../utils/paid.amount.js';
|
|
13
|
+
import type { IEInvoiceStatedValues } from '../../../interfaces/stated.values.js';
|
|
11
14
|
|
|
12
15
|
/** XPath selection with the ZUGFeRD v1 namespaces */
|
|
13
16
|
const zugferdV1Select = xpath.useNamespaces({
|
|
@@ -68,6 +71,38 @@ export class ZUGFeRDV1Decoder extends CIIBaseDecoder {
|
|
|
68
71
|
return dueDate ? this.parseRequiredCIIDate(dueDate, this.v1Text(`${dueDatePath}/@format`)) : undefined;
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Reads the buyer reference of the v1 header trade agreement
|
|
76
|
+
* (`ram:ApplicableSupplyChainTradeAgreement/ram:BuyerReference`); undefined
|
|
77
|
+
* when the document states none.
|
|
78
|
+
*/
|
|
79
|
+
protected override extractBuyerReference(): string | undefined {
|
|
80
|
+
return (
|
|
81
|
+
this.v1Text('/rsm:CrossIndustryDocument/rsm:SpecifiedSupplyChainTradeTransaction/ram:ApplicableSupplyChainTradeAgreement/ram:BuyerReference') ||
|
|
82
|
+
undefined
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Reads the identifier of the v1 document context
|
|
88
|
+
* (`rsm:SpecifiedExchangedDocumentContext/ram:GuidelineSpecifiedDocumentContextParameter/ram:ID`);
|
|
89
|
+
* undefined when the document states none.
|
|
90
|
+
*/
|
|
91
|
+
protected override extractSpecificationIdentifier(): string | undefined {
|
|
92
|
+
return (
|
|
93
|
+
this.v1Text('/rsm:CrossIndustryDocument/rsm:SpecifiedExchangedDocumentContext/ram:GuidelineSpecifiedDocumentContextParameter/ram:ID') ||
|
|
94
|
+
undefined
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* ZUGFeRD 1.0 predates EN 16931 and has no business terms to read the stated
|
|
100
|
+
* values by; a v1 document has none
|
|
101
|
+
*/
|
|
102
|
+
protected override readStatedValues(): IEInvoiceStatedValues | undefined {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
71
106
|
/** The trimmed text of the first node a v1 path selects, or '' */
|
|
72
107
|
private v1Text(path: string): string {
|
|
73
108
|
return String(zugferdV1Select(`string(${path})`, this.doc)).trim();
|
|
@@ -89,6 +124,19 @@ export class ZUGFeRDV1Decoder extends CIIBaseDecoder {
|
|
|
89
124
|
return this.parseRequiredCIIDate(deliveryDate, format);
|
|
90
125
|
}
|
|
91
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Reads the invoicing period of the v1 header settlement
|
|
129
|
+
* (`ram:ApplicableSupplyChainTradeSettlement/ram:BillingSpecifiedPeriod`).
|
|
130
|
+
* A ZUGFeRD 1.0 trade party has no electronic address, so a v1 document has
|
|
131
|
+
* no seller electronic address (BT-34).
|
|
132
|
+
*/
|
|
133
|
+
protected override extractInvoicingPeriod(): ICIIInvoicingPeriod {
|
|
134
|
+
return this.readInvoicingPeriod(
|
|
135
|
+
'/rsm:CrossIndustryDocument/rsm:SpecifiedSupplyChainTradeTransaction/ram:ApplicableSupplyChainTradeSettlement/ram:BillingSpecifiedPeriod',
|
|
136
|
+
(path) => this.v1Text(path),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
92
140
|
/**
|
|
93
141
|
* Decodes a ZUGFeRD v1 credit note
|
|
94
142
|
* @returns Promise resolving to a TCreditNote object
|
|
@@ -163,6 +211,19 @@ export class ZUGFeRDV1Decoder extends CIIBaseDecoder {
|
|
|
163
211
|
// Reverse charge: every line has the VAT category AE
|
|
164
212
|
const reverseCharge = this.isReverseChargeDocument();
|
|
165
213
|
|
|
214
|
+
// the invoicing period (BG-14), when stated
|
|
215
|
+
const invoicingPeriod = this.invoicingPeriodFields(this.extractInvoicingPeriod());
|
|
216
|
+
// the buyer reference (BT-10), when stated
|
|
217
|
+
const buyerReference = this.extractBuyerReference();
|
|
218
|
+
|
|
219
|
+
// the paid amount (BT-113) of the v1 header settlement, read with the v1 namespaces
|
|
220
|
+
const paidAmount = readPaidAmount(
|
|
221
|
+
this.v1Text(
|
|
222
|
+
'/rsm:CrossIndustryDocument/rsm:SpecifiedSupplyChainTradeTransaction/ram:ApplicableSupplyChainTradeSettlement/ram:SpecifiedTradeSettlementMonetarySummation/ram:TotalPrepaidAmount',
|
|
223
|
+
),
|
|
224
|
+
'zugferd',
|
|
225
|
+
);
|
|
226
|
+
|
|
166
227
|
// Create the common invoice data
|
|
167
228
|
const invoiceData = {
|
|
168
229
|
type: 'accounting-doc' as const,
|
|
@@ -189,6 +250,11 @@ export class ZUGFeRDV1Decoder extends CIIBaseDecoder {
|
|
|
189
250
|
notes: notes,
|
|
190
251
|
// the day of supply as the document states it (BT-72), never the issue date in its place
|
|
191
252
|
...(deliveryDate === undefined ? {} : { deliveryDate }),
|
|
253
|
+
...invoicingPeriod,
|
|
254
|
+
// the specification identifier (BT-24), with the metadata of a one-date period
|
|
255
|
+
...this.metadataFields(invoicingPeriod),
|
|
256
|
+
...(buyerReference === undefined ? {} : { buyerReference }),
|
|
257
|
+
...(paidAmount === undefined ? {} : { paidAmount }),
|
|
192
258
|
objectActions: []
|
|
193
259
|
};
|
|
194
260
|
|
|
@@ -24,9 +24,13 @@ export class ZUGFeRDValidator extends CIIBaseValidator {
|
|
|
24
24
|
* @returns True if business validation passed
|
|
25
25
|
*/
|
|
26
26
|
protected validateBusinessRules(): boolean {
|
|
27
|
+
// BR-CO-10 to BR-CO-17: the stated totals, VAT breakdown and line amounts agree with each other
|
|
28
|
+
const totalsAgree = this.validateStatedTotals();
|
|
29
|
+
// BR-CO-26: the seller states a seller, legal registration or VAT identifier
|
|
30
|
+
const sellerIdentified = this.validateSellerIdentifier();
|
|
27
31
|
// BR-23: every line has a unit code
|
|
28
32
|
const linesHaveUnits = this.validateLineUnitCodePresence();
|
|
29
33
|
// BR-CL-23: unit codes of UN/ECE Recommendation 20 with the Recommendation 21 extension
|
|
30
|
-
return this.validateUnitCodes() && linesHaveUnits;
|
|
34
|
+
return this.validateUnitCodes() && linesHaveUnits && sellerIdentified && totalsAgree;
|
|
31
35
|
}
|
|
32
36
|
}
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { EInvoice } from '../../einvoice.js';
|
|
7
7
|
import { getAccountingDocType, getDocumentTypeCode } from '../utils/document.typecode.js';
|
|
8
|
+
import { computeDocumentTotals } from '../utils/document.totals.js';
|
|
9
|
+
import { getPaymentTotals } from '../utils/paid.amount.js';
|
|
8
10
|
import type {
|
|
9
11
|
EN16931SemanticModel,
|
|
10
12
|
Seller,
|
|
@@ -43,14 +45,15 @@ export class SemanticModelAdapter {
|
|
|
43
45
|
},
|
|
44
46
|
|
|
45
47
|
// Process metadata
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
// the specification identifier (BT-24) is customizationId, the business process type (BT-23) profileId
|
|
49
|
+
processControl: invoice.metadata?.customizationId ? {
|
|
50
|
+
...(invoice.metadata.profileId ? { businessProcessType: invoice.metadata.profileId } : {}),
|
|
51
|
+
specificationIdentifier: invoice.metadata.customizationId
|
|
49
52
|
} : undefined,
|
|
50
53
|
|
|
51
54
|
// References
|
|
52
55
|
references: {
|
|
53
|
-
buyerReference: invoice.
|
|
56
|
+
buyerReference: invoice.buyerReference,
|
|
54
57
|
projectReference: invoice.metadata?.extensions?.projectReference,
|
|
55
58
|
contractReference: invoice.metadata?.extensions?.contractReference,
|
|
56
59
|
purchaseOrderReference: invoice.metadata?.extensions?.purchaseOrderReference,
|
|
@@ -132,24 +135,27 @@ export class SemanticModelAdapter {
|
|
|
132
135
|
invoice.from = this.reverseMapSeller(model.seller);
|
|
133
136
|
invoice.to = this.reverseMapBuyer(model.buyer);
|
|
134
137
|
invoice.items = this.reverseMapInvoiceLines(model.invoiceLines);
|
|
138
|
+
// the paid amount (BT-113); a stated zero is nothing paid
|
|
139
|
+
if (model.documentTotals?.prepaidAmount) {
|
|
140
|
+
invoice.paidAmount = model.documentTotals.prepaidAmount;
|
|
141
|
+
}
|
|
135
142
|
|
|
136
143
|
// Set metadata
|
|
137
144
|
if (model.processControl) {
|
|
138
145
|
invoice.metadata = {
|
|
139
146
|
...invoice.metadata,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
...invoice.metadata?.extensions,
|
|
143
|
-
businessProcessId: model.processControl.businessProcessType
|
|
144
|
-
}
|
|
147
|
+
customizationId: model.processControl.specificationIdentifier,
|
|
148
|
+
...(model.processControl.businessProcessType ? { profileId: model.processControl.businessProcessType } : {}),
|
|
145
149
|
};
|
|
146
150
|
}
|
|
147
151
|
|
|
148
|
-
// Set references
|
|
152
|
+
// Set references; the buyer reference (BT-10) is the envelope's
|
|
149
153
|
if (model.references) {
|
|
154
|
+
if (model.references.buyerReference) {
|
|
155
|
+
invoice.buyerReference = model.references.buyerReference;
|
|
156
|
+
}
|
|
150
157
|
invoice.metadata = {
|
|
151
158
|
...invoice.metadata,
|
|
152
|
-
buyerReference: model.references.buyerReference,
|
|
153
159
|
extensions: {
|
|
154
160
|
...invoice.metadata?.extensions,
|
|
155
161
|
contractReference: model.references.contractReference,
|
|
@@ -251,8 +257,8 @@ export class SemanticModelAdapter {
|
|
|
251
257
|
tradingName: contact.tradingName,
|
|
252
258
|
identifier: contact.registrationDetails?.registrationId,
|
|
253
259
|
legalRegistrationIdentifier: contact.registrationDetails?.registrationId,
|
|
254
|
-
vatIdentifier: contact.registrationDetails?.vatId ||
|
|
255
|
-
taxRegistrationIdentifier: contact.
|
|
260
|
+
vatIdentifier: contact.registrationDetails?.vatId || undefined,
|
|
261
|
+
taxRegistrationIdentifier: contact.registrationDetails?.taxNumber || undefined,
|
|
256
262
|
additionalLegalInfo: contact.description,
|
|
257
263
|
electronicAddress: contact.email || contact.contact?.email
|
|
258
264
|
};
|
|
@@ -260,7 +266,8 @@ export class SemanticModelAdapter {
|
|
|
260
266
|
return {
|
|
261
267
|
name: contact.name || `${contact.firstName || ''} ${contact.lastName || ''}`.trim(),
|
|
262
268
|
identifier: contact.registrationDetails?.registrationId,
|
|
263
|
-
vatIdentifier: contact.registrationDetails?.vatId ||
|
|
269
|
+
vatIdentifier: contact.registrationDetails?.vatId || undefined,
|
|
270
|
+
taxRegistrationIdentifier: contact.registrationDetails?.taxNumber || undefined,
|
|
264
271
|
electronicAddress: contact.email
|
|
265
272
|
};
|
|
266
273
|
}
|
|
@@ -277,14 +284,14 @@ export class SemanticModelAdapter {
|
|
|
277
284
|
tradingName: contact.tradingName,
|
|
278
285
|
identifier: contact.registrationDetails?.registrationId,
|
|
279
286
|
legalRegistrationIdentifier: contact.registrationDetails?.registrationId,
|
|
280
|
-
vatIdentifier: contact.registrationDetails?.vatId ||
|
|
287
|
+
vatIdentifier: contact.registrationDetails?.vatId || undefined,
|
|
281
288
|
electronicAddress: contact.email || contact.contact?.email
|
|
282
289
|
};
|
|
283
290
|
} else {
|
|
284
291
|
return {
|
|
285
292
|
name: contact.name || `${contact.firstName || ''} ${contact.lastName || ''}`.trim(),
|
|
286
293
|
identifier: contact.registrationDetails?.registrationId,
|
|
287
|
-
vatIdentifier: contact.registrationDetails?.vatId ||
|
|
294
|
+
vatIdentifier: contact.registrationDetails?.vatId || undefined,
|
|
288
295
|
electronicAddress: contact.email
|
|
289
296
|
};
|
|
290
297
|
}
|
|
@@ -405,9 +412,10 @@ export class SemanticModelAdapter {
|
|
|
405
412
|
chargeTotalAmount: invoice.metadata?.extensions?.documentCharges?.reduce(
|
|
406
413
|
(sum: number, c: { amount: number }) => sum + c.amount, 0
|
|
407
414
|
),
|
|
408
|
-
|
|
415
|
+
// the paid amount (BT-113) of the envelope; the amount due (BT-115) is the gross total less it
|
|
416
|
+
prepaidAmount: invoice.paidAmount,
|
|
409
417
|
roundingAmount: invoice.metadata?.extensions?.roundingAmount,
|
|
410
|
-
payableAmount: invoice.
|
|
418
|
+
payableAmount: getPaymentTotals(invoice, computeDocumentTotals(invoice)).duePayable.toNumber()
|
|
411
419
|
};
|
|
412
420
|
}
|
|
413
421
|
|
|
@@ -502,7 +510,8 @@ export class SemanticModelAdapter {
|
|
|
502
510
|
registrationDetails: {
|
|
503
511
|
vatId: seller.vatIdentifier || '',
|
|
504
512
|
registrationId: seller.identifier || seller.legalRegistrationIdentifier || '',
|
|
505
|
-
registrationName: seller.name
|
|
513
|
+
registrationName: seller.name,
|
|
514
|
+
...(seller.taxRegistrationIdentifier ? { taxNumber: seller.taxRegistrationIdentifier } : {})
|
|
506
515
|
},
|
|
507
516
|
status: 'active',
|
|
508
517
|
foundedDate: {
|