@fin.cx/einvoice 5.0.2
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.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.decoder.d.ts +40 -0
- package/dist_ts/classes.decoder.js +320 -0
- package/dist_ts/classes.encoder.d.ts +51 -0
- package/dist_ts/classes.encoder.js +293 -0
- package/dist_ts/classes.xinvoice.d.ts +136 -0
- package/dist_ts/classes.xinvoice.js +352 -0
- package/dist_ts/einvoice.d.ts +217 -0
- package/dist_ts/einvoice.js +505 -0
- package/dist_ts/errors.d.ts +121 -0
- package/dist_ts/errors.js +241 -0
- package/dist_ts/formats/base/base.decoder.d.ts +32 -0
- package/dist_ts/formats/base/base.decoder.js +52 -0
- package/dist_ts/formats/base/base.encoder.d.ts +13 -0
- package/dist_ts/formats/base/base.encoder.js +7 -0
- package/dist_ts/formats/base/base.validator.d.ts +44 -0
- package/dist_ts/formats/base/base.validator.js +39 -0
- package/dist_ts/formats/base.decoder.d.ts +19 -0
- package/dist_ts/formats/base.decoder.js +130 -0
- package/dist_ts/formats/base.validator.d.ts +44 -0
- package/dist_ts/formats/base.validator.js +39 -0
- package/dist_ts/formats/cii/cii.decoder.d.ts +61 -0
- package/dist_ts/formats/cii/cii.decoder.js +111 -0
- package/dist_ts/formats/cii/cii.encoder.d.ts +43 -0
- package/dist_ts/formats/cii/cii.encoder.js +48 -0
- package/dist_ts/formats/cii/cii.types.d.ts +31 -0
- package/dist_ts/formats/cii/cii.types.js +40 -0
- package/dist_ts/formats/cii/cii.validator.d.ts +56 -0
- package/dist_ts/formats/cii/cii.validator.js +146 -0
- package/dist_ts/formats/cii/facturx/facturx.decoder.d.ts +43 -0
- package/dist_ts/formats/cii/facturx/facturx.decoder.js +207 -0
- package/dist_ts/formats/cii/facturx/facturx.encoder.d.ts +82 -0
- package/dist_ts/formats/cii/facturx/facturx.encoder.js +400 -0
- package/dist_ts/formats/cii/facturx/facturx.types.d.ts +10 -0
- package/dist_ts/formats/cii/facturx/facturx.types.js +15 -0
- package/dist_ts/formats/cii/facturx/facturx.validator.d.ts +32 -0
- package/dist_ts/formats/cii/facturx/facturx.validator.js +138 -0
- package/dist_ts/formats/cii/zugferd/zugferd.decoder.d.ts +43 -0
- package/dist_ts/formats/cii/zugferd/zugferd.decoder.js +218 -0
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.d.ts +97 -0
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.js +550 -0
- package/dist_ts/formats/cii/zugferd/zugferd.types.d.ts +10 -0
- package/dist_ts/formats/cii/zugferd/zugferd.types.js +15 -0
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.d.ts +49 -0
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.js +229 -0
- package/dist_ts/formats/cii/zugferd/zugferd.validator.d.ts +16 -0
- package/dist_ts/formats/cii/zugferd/zugferd.validator.js +29 -0
- package/dist_ts/formats/decoder.factory.d.ts +15 -0
- package/dist_ts/formats/decoder.factory.js +46 -0
- package/dist_ts/formats/factories/decoder.factory.d.ts +13 -0
- package/dist_ts/formats/factories/decoder.factory.js +56 -0
- package/dist_ts/formats/factories/encoder.factory.d.ts +14 -0
- package/dist_ts/formats/factories/encoder.factory.js +40 -0
- package/dist_ts/formats/factories/validator.factory.d.ts +12 -0
- package/dist_ts/formats/factories/validator.factory.js +110 -0
- package/dist_ts/formats/factorx.decoder.d.ts +18 -0
- package/dist_ts/formats/factorx.decoder.js +178 -0
- package/dist_ts/formats/factorx.encoder.d.ts +51 -0
- package/dist_ts/formats/factorx.encoder.js +293 -0
- package/dist_ts/formats/facturx.decoder.d.ts +18 -0
- package/dist_ts/formats/facturx.decoder.js +210 -0
- package/dist_ts/formats/facturx.encoder.d.ts +51 -0
- package/dist_ts/formats/facturx.encoder.js +293 -0
- package/dist_ts/formats/facturx.validator.d.ts +67 -0
- package/dist_ts/formats/facturx.validator.js +266 -0
- package/dist_ts/formats/pdf/extractors/associated.extractor.d.ts +14 -0
- package/dist_ts/formats/pdf/extractors/associated.extractor.js +68 -0
- package/dist_ts/formats/pdf/extractors/base.extractor.d.ts +92 -0
- package/dist_ts/formats/pdf/extractors/base.extractor.js +319 -0
- package/dist_ts/formats/pdf/extractors/index.d.ts +4 -0
- package/dist_ts/formats/pdf/extractors/index.js +5 -0
- package/dist_ts/formats/pdf/extractors/standard.extractor.d.ts +13 -0
- package/dist_ts/formats/pdf/extractors/standard.extractor.js +74 -0
- package/dist_ts/formats/pdf/extractors/text.extractor.d.ts +45 -0
- package/dist_ts/formats/pdf/extractors/text.extractor.js +151 -0
- package/dist_ts/formats/pdf/pdf.embedder.d.ts +69 -0
- package/dist_ts/formats/pdf/pdf.embedder.js +183 -0
- package/dist_ts/formats/pdf/pdf.extractor.d.ts +49 -0
- package/dist_ts/formats/pdf/pdf.extractor.js +98 -0
- package/dist_ts/formats/pdf/robust-pdf.extractor.d.ts +40 -0
- package/dist_ts/formats/pdf/robust-pdf.extractor.js +324 -0
- package/dist_ts/formats/ubl/en16931.ubl.validator.d.ts +18 -0
- package/dist_ts/formats/ubl/en16931.ubl.validator.js +169 -0
- package/dist_ts/formats/ubl/generic/ubl.encoder.d.ts +151 -0
- package/dist_ts/formats/ubl/generic/ubl.encoder.js +892 -0
- package/dist_ts/formats/ubl/ubl.decoder.d.ts +61 -0
- package/dist_ts/formats/ubl/ubl.decoder.js +95 -0
- package/dist_ts/formats/ubl/ubl.encoder.d.ts +38 -0
- package/dist_ts/formats/ubl/ubl.encoder.js +46 -0
- package/dist_ts/formats/ubl/ubl.types.d.ts +16 -0
- package/dist_ts/formats/ubl/ubl.types.js +21 -0
- package/dist_ts/formats/ubl/ubl.validator.d.ts +50 -0
- package/dist_ts/formats/ubl/ubl.validator.js +112 -0
- package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.d.ts +34 -0
- package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.js +424 -0
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.d.ts +75 -0
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.js +555 -0
- package/dist_ts/formats/ubl/xrechnung.validator.d.ts +15 -0
- package/dist_ts/formats/ubl/xrechnung.validator.js +107 -0
- package/dist_ts/formats/ubl.validator.d.ts +82 -0
- package/dist_ts/formats/ubl.validator.js +306 -0
- package/dist_ts/formats/utils/format.detector.d.ts +62 -0
- package/dist_ts/formats/utils/format.detector.js +249 -0
- package/dist_ts/formats/validation/en16931.validator.d.ts +23 -0
- package/dist_ts/formats/validation/en16931.validator.js +119 -0
- package/dist_ts/formats/validator.factory.d.ts +18 -0
- package/dist_ts/formats/validator.factory.js +78 -0
- package/dist_ts/formats/xinvoice.decoder.d.ts +28 -0
- package/dist_ts/formats/xinvoice.decoder.js +332 -0
- package/dist_ts/formats/xinvoice.encoder.d.ts +19 -0
- package/dist_ts/formats/xinvoice.encoder.js +282 -0
- package/dist_ts/index.d.ts +51 -0
- package/dist_ts/index.js +90 -0
- package/dist_ts/interfaces/common.d.ts +79 -0
- package/dist_ts/interfaces/common.js +24 -0
- package/dist_ts/interfaces.d.ts +87 -0
- package/dist_ts/interfaces.js +23 -0
- package/dist_ts/plugins.d.ts +14 -0
- package/dist_ts/plugins.js +31 -0
- package/npmextra.json +35 -0
- package/package.json +71 -0
- package/readme.hints.md +1107 -0
- package/readme.howtofixtests.md +38 -0
- package/readme.literature.md +1 -0
- package/readme.md +998 -0
- package/readme.plan.md +481 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/einvoice.ts +603 -0
- package/ts/errors.ts +341 -0
- package/ts/formats/base/base.decoder.ts +68 -0
- package/ts/formats/base/base.encoder.ts +14 -0
- package/ts/formats/base/base.validator.ts +64 -0
- package/ts/formats/cii/cii.decoder.ts +139 -0
- package/ts/formats/cii/cii.encoder.ts +64 -0
- package/ts/formats/cii/cii.types.ts +44 -0
- package/ts/formats/cii/cii.validator.ts +171 -0
- package/ts/formats/cii/facturx/facturx.decoder.ts +243 -0
- package/ts/formats/cii/facturx/facturx.encoder.ts +483 -0
- package/ts/formats/cii/facturx/facturx.types.ts +18 -0
- package/ts/formats/cii/facturx/facturx.validator.ts +180 -0
- package/ts/formats/cii/zugferd/zugferd.decoder.ts +256 -0
- package/ts/formats/cii/zugferd/zugferd.encoder.ts +661 -0
- package/ts/formats/cii/zugferd/zugferd.types.ts +18 -0
- package/ts/formats/cii/zugferd/zugferd.v1.decoder.ts +267 -0
- package/ts/formats/cii/zugferd/zugferd.validator.ts +31 -0
- package/ts/formats/factories/decoder.factory.ts +62 -0
- package/ts/formats/factories/encoder.factory.ts +47 -0
- package/ts/formats/factories/validator.factory.ts +134 -0
- package/ts/formats/pdf/extractors/associated.extractor.ts +78 -0
- package/ts/formats/pdf/extractors/base.extractor.ts +355 -0
- package/ts/formats/pdf/extractors/index.ts +4 -0
- package/ts/formats/pdf/extractors/standard.extractor.ts +86 -0
- package/ts/formats/pdf/extractors/text.extractor.ts +162 -0
- package/ts/formats/pdf/pdf.embedder.ts +242 -0
- package/ts/formats/pdf/pdf.extractor.ts +141 -0
- package/ts/formats/ubl/en16931.ubl.validator.ts +216 -0
- package/ts/formats/ubl/generic/ubl.encoder.ts +1041 -0
- package/ts/formats/ubl/ubl.decoder.ts +121 -0
- package/ts/formats/ubl/ubl.encoder.ts +63 -0
- package/ts/formats/ubl/ubl.types.ts +22 -0
- package/ts/formats/ubl/ubl.validator.ts +133 -0
- package/ts/formats/ubl/xrechnung/xrechnung.decoder.ts +471 -0
- package/ts/formats/ubl/xrechnung/xrechnung.encoder.ts +619 -0
- package/ts/formats/ubl/xrechnung.validator.ts +185 -0
- package/ts/formats/utils/format.detector.ts +306 -0
- package/ts/formats/validation/en16931.validator.ts +135 -0
- package/ts/index.ts +164 -0
- package/ts/interfaces/common.ts +90 -0
- package/ts/interfaces.ts +98 -0
- package/ts/plugins.ts +61 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { UBLBaseDecoder } from '../ubl.decoder.js';
|
|
2
|
+
import type { TInvoice, TCreditNote, TDebitNote } from '../../../interfaces/common.js';
|
|
3
|
+
import { business, finance } from '../../../plugins.js';
|
|
4
|
+
import { UBLDocumentType } from '../ubl.types.js';
|
|
5
|
+
import { EN16931Validator } from '../../validation/en16931.validator.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Decoder for XRechnung (UBL) format
|
|
9
|
+
* Implements decoding of XRechnung invoices to TInvoice
|
|
10
|
+
*/
|
|
11
|
+
export class XRechnungDecoder extends UBLBaseDecoder {
|
|
12
|
+
/**
|
|
13
|
+
* Decodes a UBL credit note
|
|
14
|
+
* @returns Promise resolving to a TCreditNote object
|
|
15
|
+
*/
|
|
16
|
+
protected async decodeCreditNote(): Promise<TCreditNote> {
|
|
17
|
+
// Extract common data
|
|
18
|
+
const commonData = await this.extractCommonData();
|
|
19
|
+
|
|
20
|
+
// Return the invoice data as a credit note
|
|
21
|
+
return {
|
|
22
|
+
...commonData,
|
|
23
|
+
accountingDocType: 'creditnote' as const
|
|
24
|
+
} as unknown as TCreditNote;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Decodes a UBL debit note (invoice)
|
|
29
|
+
* @returns Promise resolving to a TDebitNote object
|
|
30
|
+
*/
|
|
31
|
+
protected async decodeDebitNote(): Promise<TDebitNote> {
|
|
32
|
+
// Extract common data
|
|
33
|
+
const commonData = await this.extractCommonData();
|
|
34
|
+
|
|
35
|
+
// Return the invoice data as a debit note
|
|
36
|
+
return {
|
|
37
|
+
...commonData,
|
|
38
|
+
accountingDocType: 'debitnote' as const
|
|
39
|
+
} as unknown as TDebitNote;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Extracts common invoice data from XRechnung XML
|
|
44
|
+
* @returns Common invoice data
|
|
45
|
+
*/
|
|
46
|
+
private async extractCommonData(): Promise<Partial<TInvoice>> {
|
|
47
|
+
try {
|
|
48
|
+
// Default values
|
|
49
|
+
const invoiceId = this.getText('//cbc:ID', this.doc) || `INV-${Date.now()}`;
|
|
50
|
+
const issueDateText = this.getText('//cbc:IssueDate', this.doc);
|
|
51
|
+
const issueDate = issueDateText ? new Date(issueDateText).getTime() : Date.now();
|
|
52
|
+
const currencyCode = this.getText('//cbc:DocumentCurrencyCode', this.doc) || 'EUR';
|
|
53
|
+
|
|
54
|
+
// Extract payment terms
|
|
55
|
+
let dueInDays = 30; // Default
|
|
56
|
+
const dueDateText = this.getText('//cac:PaymentTerms/cbc:PaymentDueDate', this.doc);
|
|
57
|
+
if (dueDateText) {
|
|
58
|
+
const dueDateObj = new Date(dueDateText);
|
|
59
|
+
const issueDateObj = new Date(issueDate);
|
|
60
|
+
const diffTime = Math.abs(dueDateObj.getTime() - issueDateObj.getTime());
|
|
61
|
+
dueInDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Extract items
|
|
65
|
+
const items: finance.TAccountingDocItem[] = [];
|
|
66
|
+
const invoiceLines = this.select('//cac:InvoiceLine', this.doc);
|
|
67
|
+
|
|
68
|
+
if (invoiceLines && Array.isArray(invoiceLines)) {
|
|
69
|
+
for (let i = 0; i < invoiceLines.length; i++) {
|
|
70
|
+
const line = invoiceLines[i];
|
|
71
|
+
|
|
72
|
+
const position = i + 1;
|
|
73
|
+
const name = this.getText('./cac:Item/cbc:Name', line) || `Item ${position}`;
|
|
74
|
+
const description = this.getText('./cac:Item/cbc:Description', line) || '';
|
|
75
|
+
const articleNumber = this.getText('./cac:Item/cac:SellersItemIdentification/cbc:ID', line) || '';
|
|
76
|
+
const buyerItemID = this.getText('./cac:Item/cac:BuyersItemIdentification/cbc:ID', line) || '';
|
|
77
|
+
const standardItemID = this.getText('./cac:Item/cac:StandardItemIdentification/cbc:ID', line) || '';
|
|
78
|
+
const commodityClassification = this.getText('./cac:Item/cac:CommodityClassification/cbc:ItemClassificationCode', line) || '';
|
|
79
|
+
const unitType = this.getText('./cbc:InvoicedQuantity/@unitCode', line) || 'EA';
|
|
80
|
+
|
|
81
|
+
let unitQuantity = 1;
|
|
82
|
+
const quantityText = this.getText('./cbc:InvoicedQuantity', line);
|
|
83
|
+
if (quantityText) {
|
|
84
|
+
unitQuantity = parseFloat(quantityText) || 1;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let unitNetPrice = 0;
|
|
88
|
+
const priceText = this.getText('./cac:Price/cbc:PriceAmount', line);
|
|
89
|
+
if (priceText) {
|
|
90
|
+
unitNetPrice = parseFloat(priceText) || 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let vatPercentage = 0;
|
|
94
|
+
const percentText = this.getText('./cac:Item/cac:ClassifiedTaxCategory/cbc:Percent', line);
|
|
95
|
+
if (percentText) {
|
|
96
|
+
vatPercentage = parseFloat(percentText) || 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Create item with extended metadata
|
|
100
|
+
const item: finance.TAccountingDocItem & { metadata?: any } = {
|
|
101
|
+
position,
|
|
102
|
+
name,
|
|
103
|
+
articleNumber,
|
|
104
|
+
unitType,
|
|
105
|
+
unitQuantity,
|
|
106
|
+
unitNetPrice,
|
|
107
|
+
vatPercentage
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Extract order line reference
|
|
111
|
+
const orderLineReference = this.getText('./cac:OrderLineReference/cac:OrderReference/cbc:ID', line) || '';
|
|
112
|
+
const orderLineReferenceId = this.getText('./cac:OrderLineReference/cbc:LineID', line) || '';
|
|
113
|
+
|
|
114
|
+
// Extract additional item properties
|
|
115
|
+
const additionalProps: Record<string, string> = {};
|
|
116
|
+
const propNodes = this.select('./cac:Item/cac:AdditionalItemProperty', line);
|
|
117
|
+
if (propNodes && Array.isArray(propNodes)) {
|
|
118
|
+
for (const propNode of propNodes) {
|
|
119
|
+
const propName = this.getText('./cbc:Name', propNode);
|
|
120
|
+
const propValue = this.getText('./cbc:Value', propNode);
|
|
121
|
+
if (propName && propValue) {
|
|
122
|
+
additionalProps[propName] = propValue;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Store additional item data in metadata
|
|
128
|
+
if (description || buyerItemID || standardItemID || commodityClassification || orderLineReference || Object.keys(additionalProps).length > 0) {
|
|
129
|
+
item.metadata = {
|
|
130
|
+
description,
|
|
131
|
+
buyerItemID,
|
|
132
|
+
standardItemID,
|
|
133
|
+
commodityClassification,
|
|
134
|
+
orderLineReference,
|
|
135
|
+
orderLineReferenceId,
|
|
136
|
+
additionalProperties: additionalProps
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
items.push(item);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Extract business references
|
|
145
|
+
const buyerReference = this.getText('//cbc:BuyerReference', this.doc);
|
|
146
|
+
const orderReference = this.getText('//cac:OrderReference/cbc:ID', this.doc);
|
|
147
|
+
const contractReference = this.getText('//cac:ContractDocumentReference/cbc:ID', this.doc);
|
|
148
|
+
const projectReference = this.getText('//cac:ProjectReference/cbc:ID', this.doc);
|
|
149
|
+
|
|
150
|
+
// Extract payment information
|
|
151
|
+
const paymentMeansCode = this.getText('//cac:PaymentMeans/cbc:PaymentMeansCode', this.doc);
|
|
152
|
+
const paymentID = this.getText('//cac:PaymentMeans/cbc:PaymentID', this.doc);
|
|
153
|
+
const paymentDueDate = this.getText('//cac:PaymentMeans/cbc:PaymentDueDate', this.doc);
|
|
154
|
+
const iban = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:ID', this.doc);
|
|
155
|
+
const bic = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cac:FinancialInstitutionBranch/cbc:ID', this.doc);
|
|
156
|
+
const bankName = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cac:FinancialInstitutionBranch/cbc:Name', this.doc);
|
|
157
|
+
const accountName = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:Name', this.doc);
|
|
158
|
+
|
|
159
|
+
// Extract payment terms with discount
|
|
160
|
+
const paymentTermsNote = this.getText('//cac:PaymentTerms/cbc:Note', this.doc);
|
|
161
|
+
const discountPercent = this.getText('//cac:PaymentTerms/cbc:SettlementDiscountPercent', this.doc);
|
|
162
|
+
|
|
163
|
+
// Extract period information
|
|
164
|
+
const periodStart = this.getText('//cac:InvoicePeriod/cbc:StartDate', this.doc);
|
|
165
|
+
const periodEnd = this.getText('//cac:InvoicePeriod/cbc:EndDate', this.doc);
|
|
166
|
+
const deliveryDate = this.getText('//cac:Delivery/cbc:ActualDeliveryDate', this.doc);
|
|
167
|
+
|
|
168
|
+
// Extract notes (excluding PaymentTerms notes)
|
|
169
|
+
const allNotes: string[] = [];
|
|
170
|
+
const noteNodes = this.select('//cbc:Note[not(parent::cac:PaymentTerms)]', this.doc);
|
|
171
|
+
if (noteNodes && Array.isArray(noteNodes)) {
|
|
172
|
+
for (let i = 0; i < noteNodes.length; i++) {
|
|
173
|
+
const noteText = noteNodes[i].textContent || '';
|
|
174
|
+
if (noteText) {
|
|
175
|
+
allNotes.push(noteText);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Extract subject and notes separately
|
|
181
|
+
// If we have notes, the first one might be the subject
|
|
182
|
+
let subject = `Invoice ${invoiceId}`;
|
|
183
|
+
let notes = [...allNotes];
|
|
184
|
+
|
|
185
|
+
// If the first note doesn't look like a payment term or other standard note,
|
|
186
|
+
// treat it as the subject
|
|
187
|
+
if (allNotes.length > 0 && !allNotes[0].toLowerCase().includes('due in') &&
|
|
188
|
+
!allNotes[0].toLowerCase().includes('payment')) {
|
|
189
|
+
subject = allNotes[0];
|
|
190
|
+
notes = allNotes.slice(1); // Remove subject from notes
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Extract seller and buyer information
|
|
194
|
+
const seller = this.extractParty('//cac:AccountingSupplierParty/cac:Party');
|
|
195
|
+
const buyer = this.extractParty('//cac:AccountingCustomerParty/cac:Party');
|
|
196
|
+
|
|
197
|
+
// Create the common invoice data with metadata for business references
|
|
198
|
+
const invoiceData: any = {
|
|
199
|
+
type: 'accounting-doc' as const,
|
|
200
|
+
accountingDocType: 'invoice' as const,
|
|
201
|
+
id: invoiceId,
|
|
202
|
+
accountingDocId: invoiceId,
|
|
203
|
+
date: issueDate,
|
|
204
|
+
accountingDocStatus: 'issued' as const,
|
|
205
|
+
versionInfo: {
|
|
206
|
+
type: 'final',
|
|
207
|
+
version: '1.0.0'
|
|
208
|
+
},
|
|
209
|
+
language: 'en',
|
|
210
|
+
incidenceId: invoiceId,
|
|
211
|
+
from: seller,
|
|
212
|
+
to: buyer,
|
|
213
|
+
subject: subject,
|
|
214
|
+
items: items,
|
|
215
|
+
dueInDays: dueInDays,
|
|
216
|
+
reverseCharge: false,
|
|
217
|
+
currency: currencyCode as finance.TCurrency,
|
|
218
|
+
notes: notes,
|
|
219
|
+
objectActions: [],
|
|
220
|
+
metadata: {
|
|
221
|
+
format: 'xrechnung' as any,
|
|
222
|
+
version: '1.0.0',
|
|
223
|
+
extensions: {
|
|
224
|
+
businessReferences: {
|
|
225
|
+
buyerReference,
|
|
226
|
+
orderReference,
|
|
227
|
+
contractReference,
|
|
228
|
+
projectReference
|
|
229
|
+
},
|
|
230
|
+
paymentInformation: {
|
|
231
|
+
paymentMeansCode,
|
|
232
|
+
paymentID,
|
|
233
|
+
paymentDueDate,
|
|
234
|
+
iban,
|
|
235
|
+
bic,
|
|
236
|
+
bankName,
|
|
237
|
+
accountName,
|
|
238
|
+
paymentTermsNote,
|
|
239
|
+
discountPercent
|
|
240
|
+
},
|
|
241
|
+
dateInformation: {
|
|
242
|
+
periodStart,
|
|
243
|
+
periodEnd,
|
|
244
|
+
deliveryDate
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// Validate mandatory EN16931 fields unless validation is skipped
|
|
251
|
+
if (!this.skipValidation) {
|
|
252
|
+
EN16931Validator.validateMandatoryFields(invoiceData);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return invoiceData;
|
|
256
|
+
} catch (error) {
|
|
257
|
+
// Re-throw validation errors
|
|
258
|
+
if (error.message && error.message.includes('EN16931 validation failed')) {
|
|
259
|
+
throw error;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
console.error('Error extracting common data:', error);
|
|
263
|
+
// Return default data
|
|
264
|
+
return {
|
|
265
|
+
type: 'accounting-doc' as const,
|
|
266
|
+
accountingDocType: 'invoice' as const,
|
|
267
|
+
id: `INV-${Date.now()}`,
|
|
268
|
+
accountingDocId: `INV-${Date.now()}`,
|
|
269
|
+
date: Date.now(),
|
|
270
|
+
accountingDocStatus: 'issued' as const,
|
|
271
|
+
versionInfo: {
|
|
272
|
+
type: 'final',
|
|
273
|
+
version: '1.0.0'
|
|
274
|
+
},
|
|
275
|
+
language: 'en',
|
|
276
|
+
incidenceId: `INV-${Date.now()}`,
|
|
277
|
+
from: this.createEmptyContact(),
|
|
278
|
+
to: this.createEmptyContact(),
|
|
279
|
+
subject: 'Invoice',
|
|
280
|
+
items: [],
|
|
281
|
+
dueInDays: 30,
|
|
282
|
+
reverseCharge: false,
|
|
283
|
+
currency: 'EUR',
|
|
284
|
+
notes: [],
|
|
285
|
+
objectActions: []
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Extracts party information from XML
|
|
292
|
+
* @param partyPath XPath to the party element
|
|
293
|
+
* @returns TContact object
|
|
294
|
+
*/
|
|
295
|
+
private extractParty(partyPath: string): business.TContact {
|
|
296
|
+
try {
|
|
297
|
+
// Default values
|
|
298
|
+
let name = '';
|
|
299
|
+
let streetName = '';
|
|
300
|
+
let houseNumber = '0';
|
|
301
|
+
let city = '';
|
|
302
|
+
let postalCode = '';
|
|
303
|
+
let country = '';
|
|
304
|
+
let countryCode = '';
|
|
305
|
+
let vatId = '';
|
|
306
|
+
let registrationId = '';
|
|
307
|
+
let registrationName = '';
|
|
308
|
+
let contactPhone = '';
|
|
309
|
+
let contactEmail = '';
|
|
310
|
+
let contactName = '';
|
|
311
|
+
let gln = '';
|
|
312
|
+
const additionalIdentifiers: any[] = [];
|
|
313
|
+
|
|
314
|
+
// Try to extract party information
|
|
315
|
+
const partyNodes = this.select(partyPath, this.doc);
|
|
316
|
+
|
|
317
|
+
if (partyNodes && Array.isArray(partyNodes) && partyNodes.length > 0) {
|
|
318
|
+
const party = partyNodes[0];
|
|
319
|
+
|
|
320
|
+
// Extract GLN from EndpointID
|
|
321
|
+
const endpointId = this.getText('./cbc:EndpointID[@schemeID="0088"]', party);
|
|
322
|
+
if (endpointId) {
|
|
323
|
+
gln = endpointId;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Extract additional party identifications
|
|
327
|
+
const partyIdNodes = this.select('./cac:PartyIdentification', party);
|
|
328
|
+
if (partyIdNodes && Array.isArray(partyIdNodes)) {
|
|
329
|
+
for (const idNode of partyIdNodes) {
|
|
330
|
+
const idValue = this.getText('./cbc:ID', idNode);
|
|
331
|
+
const idElement = (idNode as Element).getElementsByTagName('cbc:ID')[0];
|
|
332
|
+
const schemeId = idElement?.getAttribute('schemeID');
|
|
333
|
+
if (idValue) {
|
|
334
|
+
additionalIdentifiers.push({
|
|
335
|
+
value: idValue,
|
|
336
|
+
scheme: schemeId || ''
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Extract name
|
|
343
|
+
name = this.getText('./cac:PartyName/cbc:Name', party) || '';
|
|
344
|
+
|
|
345
|
+
// Extract address
|
|
346
|
+
const addressNodes = this.select('./cac:PostalAddress', party);
|
|
347
|
+
if (addressNodes && Array.isArray(addressNodes) && addressNodes.length > 0) {
|
|
348
|
+
const address = addressNodes[0];
|
|
349
|
+
|
|
350
|
+
streetName = this.getText('./cbc:StreetName', address) || '';
|
|
351
|
+
houseNumber = this.getText('./cbc:BuildingNumber', address) || '0';
|
|
352
|
+
city = this.getText('./cbc:CityName', address) || '';
|
|
353
|
+
postalCode = this.getText('./cbc:PostalZone', address) || '';
|
|
354
|
+
|
|
355
|
+
const countryNodes = this.select('./cac:Country', address);
|
|
356
|
+
if (countryNodes && Array.isArray(countryNodes) && countryNodes.length > 0) {
|
|
357
|
+
const countryNode = countryNodes[0];
|
|
358
|
+
country = this.getText('./cbc:Name', countryNode) || '';
|
|
359
|
+
countryCode = this.getText('./cbc:IdentificationCode', countryNode) || '';
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Extract tax information
|
|
364
|
+
const taxSchemeNodes = this.select('./cac:PartyTaxScheme', party);
|
|
365
|
+
if (taxSchemeNodes && Array.isArray(taxSchemeNodes) && taxSchemeNodes.length > 0) {
|
|
366
|
+
vatId = this.getText('./cbc:CompanyID', taxSchemeNodes[0]) || '';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Extract registration information
|
|
370
|
+
const legalEntityNodes = this.select('./cac:PartyLegalEntity', party);
|
|
371
|
+
if (legalEntityNodes && Array.isArray(legalEntityNodes) && legalEntityNodes.length > 0) {
|
|
372
|
+
registrationId = this.getText('./cbc:CompanyID', legalEntityNodes[0]) || '';
|
|
373
|
+
registrationName = this.getText('./cbc:RegistrationName', legalEntityNodes[0]) || name;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Extract contact information
|
|
377
|
+
const contactNodes = this.select('./cac:Contact', party);
|
|
378
|
+
if (contactNodes && Array.isArray(contactNodes) && contactNodes.length > 0) {
|
|
379
|
+
const contact = contactNodes[0];
|
|
380
|
+
contactPhone = this.getText('./cbc:Telephone', contact) || '';
|
|
381
|
+
contactEmail = this.getText('./cbc:ElectronicMail', contact) || '';
|
|
382
|
+
contactName = this.getText('./cbc:Name', contact) || '';
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Create contact with additional metadata for contact information
|
|
387
|
+
const contact: business.TContact & { metadata?: any } = {
|
|
388
|
+
type: 'company',
|
|
389
|
+
name: name,
|
|
390
|
+
description: '',
|
|
391
|
+
address: {
|
|
392
|
+
streetName: streetName,
|
|
393
|
+
houseNumber: houseNumber,
|
|
394
|
+
city: city,
|
|
395
|
+
postalCode: postalCode,
|
|
396
|
+
country: country,
|
|
397
|
+
countryCode: countryCode
|
|
398
|
+
},
|
|
399
|
+
status: 'active',
|
|
400
|
+
foundedDate: {
|
|
401
|
+
year: 2000,
|
|
402
|
+
month: 1,
|
|
403
|
+
day: 1
|
|
404
|
+
},
|
|
405
|
+
registrationDetails: {
|
|
406
|
+
vatId: vatId,
|
|
407
|
+
registrationId: registrationId,
|
|
408
|
+
registrationName: registrationName
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
// Store contact information and additional identifiers in metadata if available
|
|
413
|
+
const metadata: any = {};
|
|
414
|
+
|
|
415
|
+
if (contactPhone || contactEmail || contactName) {
|
|
416
|
+
metadata.contactInformation = {
|
|
417
|
+
phone: contactPhone,
|
|
418
|
+
email: contactEmail,
|
|
419
|
+
name: contactName
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (gln) {
|
|
424
|
+
(contact as any).gln = gln;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (additionalIdentifiers.length > 0) {
|
|
428
|
+
(contact as any).additionalIdentifiers = additionalIdentifiers;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (Object.keys(metadata).length > 0) {
|
|
432
|
+
contact.metadata = metadata;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return contact;
|
|
436
|
+
} catch (error) {
|
|
437
|
+
console.error('Error extracting party information:', error);
|
|
438
|
+
return this.createEmptyContact();
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Creates an empty TContact object
|
|
444
|
+
* @returns Empty TContact object
|
|
445
|
+
*/
|
|
446
|
+
private createEmptyContact(): business.TContact {
|
|
447
|
+
return {
|
|
448
|
+
type: 'company',
|
|
449
|
+
name: '',
|
|
450
|
+
description: '',
|
|
451
|
+
address: {
|
|
452
|
+
streetName: '',
|
|
453
|
+
houseNumber: '0',
|
|
454
|
+
city: '',
|
|
455
|
+
country: '',
|
|
456
|
+
postalCode: ''
|
|
457
|
+
},
|
|
458
|
+
status: 'active',
|
|
459
|
+
foundedDate: {
|
|
460
|
+
year: 2000,
|
|
461
|
+
month: 1,
|
|
462
|
+
day: 1
|
|
463
|
+
},
|
|
464
|
+
registrationDetails: {
|
|
465
|
+
vatId: '',
|
|
466
|
+
registrationId: '',
|
|
467
|
+
registrationName: ''
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
}
|