@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,661 @@
|
|
|
1
|
+
import { CIIBaseEncoder } from '../cii.encoder.js';
|
|
2
|
+
import type { TInvoice, TCreditNote, TDebitNote } from '../../../interfaces/common.js';
|
|
3
|
+
import { ZUGFERD_PROFILE_IDS } from './zugferd.types.js';
|
|
4
|
+
import { CIIProfile } from '../cii.types.js';
|
|
5
|
+
import { DOMParser, XMLSerializer } from '../../../plugins.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Encoder for ZUGFeRD invoice format
|
|
9
|
+
*/
|
|
10
|
+
export class ZUGFeRDEncoder extends CIIBaseEncoder {
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
// Set default profile to BASIC
|
|
14
|
+
this.profile = CIIProfile.BASIC;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Encodes a credit note into ZUGFeRD XML
|
|
19
|
+
* @param creditNote Credit note to encode
|
|
20
|
+
* @returns ZUGFeRD XML string
|
|
21
|
+
*/
|
|
22
|
+
protected async encodeCreditNote(creditNote: TCreditNote): Promise<string> {
|
|
23
|
+
// Create base XML
|
|
24
|
+
const xmlDoc = this.createBaseXml();
|
|
25
|
+
|
|
26
|
+
// Set document type code to credit note (381)
|
|
27
|
+
this.setDocumentTypeCode(xmlDoc, '381');
|
|
28
|
+
|
|
29
|
+
// Add common invoice data
|
|
30
|
+
this.addCommonInvoiceData(xmlDoc, creditNote as unknown as TInvoice);
|
|
31
|
+
|
|
32
|
+
// Serialize to string
|
|
33
|
+
return new XMLSerializer().serializeToString(xmlDoc);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Encodes a debit note (invoice) into ZUGFeRD XML
|
|
38
|
+
* @param debitNote Debit note to encode
|
|
39
|
+
* @returns ZUGFeRD XML string
|
|
40
|
+
*/
|
|
41
|
+
protected async encodeDebitNote(debitNote: TDebitNote): Promise<string> {
|
|
42
|
+
// Create base XML
|
|
43
|
+
const xmlDoc = this.createBaseXml();
|
|
44
|
+
|
|
45
|
+
// Set document type code to invoice (380)
|
|
46
|
+
this.setDocumentTypeCode(xmlDoc, '380');
|
|
47
|
+
|
|
48
|
+
// Add common invoice data
|
|
49
|
+
this.addCommonInvoiceData(xmlDoc, debitNote as unknown as TInvoice);
|
|
50
|
+
|
|
51
|
+
// Serialize to string
|
|
52
|
+
return new XMLSerializer().serializeToString(xmlDoc);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Creates a base ZUGFeRD XML document
|
|
57
|
+
* @returns XML document with basic structure
|
|
58
|
+
*/
|
|
59
|
+
private createBaseXml(): Document {
|
|
60
|
+
// Create XML document from template
|
|
61
|
+
const xmlString = this.createXmlRoot();
|
|
62
|
+
const doc = new DOMParser().parseFromString(xmlString, 'application/xml');
|
|
63
|
+
|
|
64
|
+
// Add ZUGFeRD profile
|
|
65
|
+
this.addProfile(doc);
|
|
66
|
+
|
|
67
|
+
return doc;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Adds ZUGFeRD profile information to the XML document
|
|
72
|
+
* @param doc XML document
|
|
73
|
+
*/
|
|
74
|
+
private addProfile(doc: Document): void {
|
|
75
|
+
// Get root element
|
|
76
|
+
const root = doc.documentElement;
|
|
77
|
+
|
|
78
|
+
// Create context element if it doesn't exist
|
|
79
|
+
let contextElement = root.getElementsByTagName('rsm:ExchangedDocumentContext')[0];
|
|
80
|
+
if (!contextElement) {
|
|
81
|
+
contextElement = doc.createElement('rsm:ExchangedDocumentContext');
|
|
82
|
+
root.appendChild(contextElement);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Create guideline parameter element
|
|
86
|
+
const guidelineElement = doc.createElement('ram:GuidelineSpecifiedDocumentContextParameter');
|
|
87
|
+
contextElement.appendChild(guidelineElement);
|
|
88
|
+
|
|
89
|
+
// Add ID element with profile
|
|
90
|
+
const idElement = doc.createElement('ram:ID');
|
|
91
|
+
|
|
92
|
+
// Set profile based on the selected profile
|
|
93
|
+
let profileId = ZUGFERD_PROFILE_IDS.BASIC;
|
|
94
|
+
if (this.profile === CIIProfile.COMFORT) {
|
|
95
|
+
profileId = ZUGFERD_PROFILE_IDS.COMFORT;
|
|
96
|
+
} else if (this.profile === CIIProfile.EXTENDED) {
|
|
97
|
+
profileId = ZUGFERD_PROFILE_IDS.EXTENDED;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
idElement.textContent = profileId;
|
|
101
|
+
guidelineElement.appendChild(idElement);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Sets the document type code in the XML document
|
|
106
|
+
* @param doc XML document
|
|
107
|
+
* @param typeCode Document type code (380 for invoice, 381 for credit note)
|
|
108
|
+
*/
|
|
109
|
+
private setDocumentTypeCode(doc: Document, typeCode: string): void {
|
|
110
|
+
// Get root element
|
|
111
|
+
const root = doc.documentElement;
|
|
112
|
+
|
|
113
|
+
// Create document element if it doesn't exist
|
|
114
|
+
let documentElement = root.getElementsByTagName('rsm:ExchangedDocument')[0];
|
|
115
|
+
if (!documentElement) {
|
|
116
|
+
documentElement = doc.createElement('rsm:ExchangedDocument');
|
|
117
|
+
root.appendChild(documentElement);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Add type code element
|
|
121
|
+
const typeCodeElement = doc.createElement('ram:TypeCode');
|
|
122
|
+
typeCodeElement.textContent = typeCode;
|
|
123
|
+
documentElement.appendChild(typeCodeElement);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Adds common invoice data to the XML document
|
|
128
|
+
* @param doc XML document
|
|
129
|
+
* @param invoice Invoice data
|
|
130
|
+
*/
|
|
131
|
+
private addCommonInvoiceData(doc: Document, invoice: TInvoice): void {
|
|
132
|
+
// Get root element
|
|
133
|
+
const root = doc.documentElement;
|
|
134
|
+
|
|
135
|
+
// Get document element or create it
|
|
136
|
+
let documentElement = root.getElementsByTagName('rsm:ExchangedDocument')[0];
|
|
137
|
+
if (!documentElement) {
|
|
138
|
+
documentElement = doc.createElement('rsm:ExchangedDocument');
|
|
139
|
+
root.appendChild(documentElement);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Add ID element
|
|
143
|
+
const idElement = doc.createElement('ram:ID');
|
|
144
|
+
idElement.textContent = invoice.id;
|
|
145
|
+
documentElement.appendChild(idElement);
|
|
146
|
+
|
|
147
|
+
// Add issue date element
|
|
148
|
+
const issueDateElement = doc.createElement('ram:IssueDateTime');
|
|
149
|
+
const dateStringElement = doc.createElement('udt:DateTimeString');
|
|
150
|
+
dateStringElement.setAttribute('format', '102'); // YYYYMMDD format
|
|
151
|
+
dateStringElement.textContent = this.formatDateYYYYMMDD(invoice.date);
|
|
152
|
+
issueDateElement.appendChild(dateStringElement);
|
|
153
|
+
documentElement.appendChild(issueDateElement);
|
|
154
|
+
|
|
155
|
+
// Add notes - include subject as first note if it exists
|
|
156
|
+
const allNotes: string[] = [];
|
|
157
|
+
if (invoice.subject && invoice.subject.trim()) {
|
|
158
|
+
allNotes.push(invoice.subject);
|
|
159
|
+
}
|
|
160
|
+
if (invoice.notes && invoice.notes.length > 0) {
|
|
161
|
+
allNotes.push(...invoice.notes);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Write all notes
|
|
165
|
+
for (const note of allNotes) {
|
|
166
|
+
const noteElement = doc.createElement('ram:IncludedNote');
|
|
167
|
+
const contentElement = doc.createElement('ram:Content');
|
|
168
|
+
contentElement.textContent = note;
|
|
169
|
+
noteElement.appendChild(contentElement);
|
|
170
|
+
documentElement.appendChild(noteElement);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Create transaction element if it doesn't exist
|
|
174
|
+
let transactionElement = root.getElementsByTagName('rsm:SupplyChainTradeTransaction')[0];
|
|
175
|
+
if (!transactionElement) {
|
|
176
|
+
transactionElement = doc.createElement('rsm:SupplyChainTradeTransaction');
|
|
177
|
+
root.appendChild(transactionElement);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Add agreement section with seller and buyer
|
|
181
|
+
this.addAgreementSection(doc, transactionElement, invoice);
|
|
182
|
+
|
|
183
|
+
// Add delivery section
|
|
184
|
+
this.addDeliverySection(doc, transactionElement, invoice);
|
|
185
|
+
|
|
186
|
+
// Add settlement section with payment terms and totals
|
|
187
|
+
this.addSettlementSection(doc, transactionElement, invoice);
|
|
188
|
+
|
|
189
|
+
// Add line items
|
|
190
|
+
this.addLineItems(doc, transactionElement, invoice);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Adds agreement section with seller and buyer information
|
|
195
|
+
* @param doc XML document
|
|
196
|
+
* @param transactionElement Transaction element
|
|
197
|
+
* @param invoice Invoice data
|
|
198
|
+
*/
|
|
199
|
+
private addAgreementSection(doc: Document, transactionElement: Element, invoice: TInvoice): void {
|
|
200
|
+
// Create agreement element
|
|
201
|
+
const agreementElement = doc.createElement('ram:ApplicableHeaderTradeAgreement');
|
|
202
|
+
transactionElement.appendChild(agreementElement);
|
|
203
|
+
|
|
204
|
+
// Add buyer reference if available
|
|
205
|
+
if (invoice.buyerReference) {
|
|
206
|
+
const buyerRefElement = doc.createElement('ram:BuyerReference');
|
|
207
|
+
buyerRefElement.textContent = invoice.buyerReference;
|
|
208
|
+
agreementElement.appendChild(buyerRefElement);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Add seller
|
|
212
|
+
const sellerElement = doc.createElement('ram:SellerTradeParty');
|
|
213
|
+
this.addPartyInfo(doc, sellerElement, invoice.from);
|
|
214
|
+
|
|
215
|
+
// Add seller electronic address if available
|
|
216
|
+
if (invoice.electronicAddress && invoice.from.type === 'company') {
|
|
217
|
+
const contactElement = doc.createElement('ram:DefinedTradeContact');
|
|
218
|
+
const uriElement = doc.createElement('ram:URIID');
|
|
219
|
+
uriElement.setAttribute('schemeID', invoice.electronicAddress.scheme);
|
|
220
|
+
uriElement.textContent = invoice.electronicAddress.value;
|
|
221
|
+
contactElement.appendChild(uriElement);
|
|
222
|
+
sellerElement.appendChild(contactElement);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
agreementElement.appendChild(sellerElement);
|
|
226
|
+
|
|
227
|
+
// Add buyer
|
|
228
|
+
const buyerElement = doc.createElement('ram:BuyerTradeParty');
|
|
229
|
+
this.addPartyInfo(doc, buyerElement, invoice.to);
|
|
230
|
+
agreementElement.appendChild(buyerElement);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Adds party information to an element
|
|
235
|
+
* @param doc XML document
|
|
236
|
+
* @param partyElement Party element
|
|
237
|
+
* @param party Party data
|
|
238
|
+
*/
|
|
239
|
+
private addPartyInfo(doc: Document, partyElement: Element, party: any): void {
|
|
240
|
+
// Add name
|
|
241
|
+
const nameElement = doc.createElement('ram:Name');
|
|
242
|
+
nameElement.textContent = party.name;
|
|
243
|
+
partyElement.appendChild(nameElement);
|
|
244
|
+
|
|
245
|
+
// Add postal address
|
|
246
|
+
const addressElement = doc.createElement('ram:PostalTradeAddress');
|
|
247
|
+
|
|
248
|
+
// Add address line 1 (street)
|
|
249
|
+
if (party.address.streetName) {
|
|
250
|
+
const line1Element = doc.createElement('ram:LineOne');
|
|
251
|
+
line1Element.textContent = party.address.streetName;
|
|
252
|
+
addressElement.appendChild(line1Element);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Add address line 2 (house number) if present
|
|
256
|
+
if (party.address.houseNumber && party.address.houseNumber !== '0') {
|
|
257
|
+
const line2Element = doc.createElement('ram:LineTwo');
|
|
258
|
+
line2Element.textContent = party.address.houseNumber;
|
|
259
|
+
addressElement.appendChild(line2Element);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Add postal code
|
|
263
|
+
if (party.address.postalCode) {
|
|
264
|
+
const postalCodeElement = doc.createElement('ram:PostcodeCode');
|
|
265
|
+
postalCodeElement.textContent = party.address.postalCode;
|
|
266
|
+
addressElement.appendChild(postalCodeElement);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Add city
|
|
270
|
+
if (party.address.city) {
|
|
271
|
+
const cityElement = doc.createElement('ram:CityName');
|
|
272
|
+
cityElement.textContent = party.address.city;
|
|
273
|
+
addressElement.appendChild(cityElement);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Add country
|
|
277
|
+
if (party.address.country || party.address.countryCode) {
|
|
278
|
+
const countryElement = doc.createElement('ram:CountryID');
|
|
279
|
+
countryElement.textContent = party.address.countryCode || party.address.country;
|
|
280
|
+
addressElement.appendChild(countryElement);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
partyElement.appendChild(addressElement);
|
|
284
|
+
|
|
285
|
+
// Add VAT ID if available
|
|
286
|
+
if (party.registrationDetails && party.registrationDetails.vatId) {
|
|
287
|
+
const taxRegistrationElement = doc.createElement('ram:SpecifiedTaxRegistration');
|
|
288
|
+
const taxIdElement = doc.createElement('ram:ID');
|
|
289
|
+
taxIdElement.setAttribute('schemeID', 'VA');
|
|
290
|
+
taxIdElement.textContent = party.registrationDetails.vatId;
|
|
291
|
+
taxRegistrationElement.appendChild(taxIdElement);
|
|
292
|
+
partyElement.appendChild(taxRegistrationElement);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Add registration ID if available
|
|
296
|
+
if (party.registrationDetails && party.registrationDetails.registrationId) {
|
|
297
|
+
const regRegistrationElement = doc.createElement('ram:SpecifiedTaxRegistration');
|
|
298
|
+
const regIdElement = doc.createElement('ram:ID');
|
|
299
|
+
regIdElement.setAttribute('schemeID', 'FC');
|
|
300
|
+
regIdElement.textContent = party.registrationDetails.registrationId;
|
|
301
|
+
regRegistrationElement.appendChild(regIdElement);
|
|
302
|
+
partyElement.appendChild(regRegistrationElement);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Adds delivery section with delivery information
|
|
308
|
+
* @param doc XML document
|
|
309
|
+
* @param transactionElement Transaction element
|
|
310
|
+
* @param invoice Invoice data
|
|
311
|
+
*/
|
|
312
|
+
private addDeliverySection(doc: Document, transactionElement: Element, invoice: TInvoice): void {
|
|
313
|
+
// Create delivery element
|
|
314
|
+
const deliveryElement = doc.createElement('ram:ApplicableHeaderTradeDelivery');
|
|
315
|
+
transactionElement.appendChild(deliveryElement);
|
|
316
|
+
|
|
317
|
+
// Add delivery date if available
|
|
318
|
+
if (invoice.deliveryDate) {
|
|
319
|
+
const deliveryDateElement = doc.createElement('ram:ActualDeliverySupplyChainEvent');
|
|
320
|
+
const occurrenceDateElement = doc.createElement('ram:OccurrenceDateTime');
|
|
321
|
+
const dateStringElement = doc.createElement('udt:DateTimeString');
|
|
322
|
+
dateStringElement.setAttribute('format', '102'); // YYYYMMDD format
|
|
323
|
+
dateStringElement.textContent = this.formatDateYYYYMMDD(invoice.deliveryDate);
|
|
324
|
+
occurrenceDateElement.appendChild(dateStringElement);
|
|
325
|
+
deliveryDateElement.appendChild(occurrenceDateElement);
|
|
326
|
+
deliveryElement.appendChild(deliveryDateElement);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Add period of performance if available
|
|
330
|
+
if (invoice.periodOfPerformance) {
|
|
331
|
+
const periodElement = doc.createElement('ram:BillingSpecifiedPeriod');
|
|
332
|
+
|
|
333
|
+
// Start date
|
|
334
|
+
if (invoice.periodOfPerformance.from) {
|
|
335
|
+
const startDateElement = doc.createElement('ram:StartDateTime');
|
|
336
|
+
const startDateStringElement = doc.createElement('udt:DateTimeString');
|
|
337
|
+
startDateStringElement.setAttribute('format', '102'); // YYYYMMDD format
|
|
338
|
+
startDateStringElement.textContent = this.formatDateYYYYMMDD(invoice.periodOfPerformance.from);
|
|
339
|
+
startDateElement.appendChild(startDateStringElement);
|
|
340
|
+
periodElement.appendChild(startDateElement);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// End date
|
|
344
|
+
if (invoice.periodOfPerformance.to) {
|
|
345
|
+
const endDateElement = doc.createElement('ram:EndDateTime');
|
|
346
|
+
const endDateStringElement = doc.createElement('udt:DateTimeString');
|
|
347
|
+
endDateStringElement.setAttribute('format', '102'); // YYYYMMDD format
|
|
348
|
+
endDateStringElement.textContent = this.formatDateYYYYMMDD(invoice.periodOfPerformance.to);
|
|
349
|
+
endDateElement.appendChild(endDateStringElement);
|
|
350
|
+
periodElement.appendChild(endDateElement);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
deliveryElement.appendChild(periodElement);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Adds settlement section with payment terms and totals
|
|
359
|
+
* @param doc XML document
|
|
360
|
+
* @param transactionElement Transaction element
|
|
361
|
+
* @param invoice Invoice data
|
|
362
|
+
*/
|
|
363
|
+
private addSettlementSection(doc: Document, transactionElement: Element, invoice: TInvoice): void {
|
|
364
|
+
// Create settlement element
|
|
365
|
+
const settlementElement = doc.createElement('ram:ApplicableHeaderTradeSettlement');
|
|
366
|
+
transactionElement.appendChild(settlementElement);
|
|
367
|
+
|
|
368
|
+
// Add currency
|
|
369
|
+
const currencyElement = doc.createElement('ram:InvoiceCurrencyCode');
|
|
370
|
+
currencyElement.textContent = invoice.currency;
|
|
371
|
+
settlementElement.appendChild(currencyElement);
|
|
372
|
+
|
|
373
|
+
// Add payment terms
|
|
374
|
+
const paymentTermsElement = doc.createElement('ram:SpecifiedTradePaymentTerms');
|
|
375
|
+
|
|
376
|
+
// Add payment instructions if available
|
|
377
|
+
if (invoice.paymentOptions) {
|
|
378
|
+
// Add payment instructions as description - this is generic enough to work with any payment type
|
|
379
|
+
const descriptionElement = doc.createElement('ram:Description');
|
|
380
|
+
descriptionElement.textContent = `Due in ${invoice.dueInDays} days. ${invoice.paymentOptions.description || ''}`;
|
|
381
|
+
paymentTermsElement.appendChild(descriptionElement);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Add due date
|
|
385
|
+
const dueDateElement = doc.createElement('ram:DueDateDateTime');
|
|
386
|
+
const dateStringElement = doc.createElement('udt:DateTimeString');
|
|
387
|
+
dateStringElement.setAttribute('format', '102'); // YYYYMMDD format
|
|
388
|
+
|
|
389
|
+
// Calculate due date
|
|
390
|
+
const dueDate = new Date(invoice.date);
|
|
391
|
+
dueDate.setDate(dueDate.getDate() + invoice.dueInDays);
|
|
392
|
+
|
|
393
|
+
dateStringElement.textContent = this.formatDateYYYYMMDD(dueDate.getTime());
|
|
394
|
+
dueDateElement.appendChild(dateStringElement);
|
|
395
|
+
paymentTermsElement.appendChild(dueDateElement);
|
|
396
|
+
|
|
397
|
+
settlementElement.appendChild(paymentTermsElement);
|
|
398
|
+
|
|
399
|
+
// Add payment means if available (using a generic approach)
|
|
400
|
+
if (invoice.paymentOptions) {
|
|
401
|
+
const paymentMeansElement = doc.createElement('ram:SpecifiedTradeSettlementPaymentMeans');
|
|
402
|
+
|
|
403
|
+
// Payment type code (58 for SEPA transfer as default)
|
|
404
|
+
const typeCodeElement = doc.createElement('ram:TypeCode');
|
|
405
|
+
typeCodeElement.textContent = '58';
|
|
406
|
+
paymentMeansElement.appendChild(typeCodeElement);
|
|
407
|
+
|
|
408
|
+
// Description (optional)
|
|
409
|
+
if (invoice.paymentOptions.description) {
|
|
410
|
+
const infoElement = doc.createElement('ram:Information');
|
|
411
|
+
infoElement.textContent = invoice.paymentOptions.description;
|
|
412
|
+
paymentMeansElement.appendChild(infoElement);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// If payment details are available in a standard format
|
|
416
|
+
if (invoice.paymentOptions.sepaConnection.iban) {
|
|
417
|
+
// Payee account
|
|
418
|
+
const payeeAccountElement = doc.createElement('ram:PayeePartyCreditorFinancialAccount');
|
|
419
|
+
const ibanElement = doc.createElement('ram:IBANID');
|
|
420
|
+
ibanElement.textContent = invoice.paymentOptions.sepaConnection.iban;
|
|
421
|
+
payeeAccountElement.appendChild(ibanElement);
|
|
422
|
+
paymentMeansElement.appendChild(payeeAccountElement);
|
|
423
|
+
|
|
424
|
+
// Payee financial institution if BIC available
|
|
425
|
+
if (invoice.paymentOptions.sepaConnection.bic) {
|
|
426
|
+
const institutionElement = doc.createElement('ram:PayeeSpecifiedCreditorFinancialInstitution');
|
|
427
|
+
const bicElement = doc.createElement('ram:BICID');
|
|
428
|
+
bicElement.textContent = invoice.paymentOptions.sepaConnection.bic;
|
|
429
|
+
institutionElement.appendChild(bicElement);
|
|
430
|
+
paymentMeansElement.appendChild(institutionElement);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
settlementElement.appendChild(paymentMeansElement);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Add tax details
|
|
438
|
+
this.addTaxDetails(doc, settlementElement, invoice);
|
|
439
|
+
|
|
440
|
+
// Add totals
|
|
441
|
+
this.addMonetarySummation(doc, settlementElement, invoice);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Adds tax details to the settlement section
|
|
446
|
+
* @param doc XML document
|
|
447
|
+
* @param settlementElement Settlement element
|
|
448
|
+
* @param invoice Invoice data
|
|
449
|
+
*/
|
|
450
|
+
private addTaxDetails(doc: Document, settlementElement: Element, invoice: TInvoice): void {
|
|
451
|
+
// Calculate tax categories and totals
|
|
452
|
+
const taxCategories = new Map<number, number>(); // Map of VAT rate to net amount
|
|
453
|
+
|
|
454
|
+
// Calculate from items
|
|
455
|
+
if (invoice.items) {
|
|
456
|
+
for (const item of invoice.items) {
|
|
457
|
+
const itemNetAmount = item.unitNetPrice * item.unitQuantity;
|
|
458
|
+
const vatRate = item.vatPercentage;
|
|
459
|
+
|
|
460
|
+
const currentAmount = taxCategories.get(vatRate) || 0;
|
|
461
|
+
taxCategories.set(vatRate, currentAmount + itemNetAmount);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Add each tax category
|
|
466
|
+
for (const [rate, baseAmount] of taxCategories.entries()) {
|
|
467
|
+
const taxElement = doc.createElement('ram:ApplicableTradeTax');
|
|
468
|
+
|
|
469
|
+
// Calculate tax amount
|
|
470
|
+
const taxAmount = baseAmount * (rate / 100);
|
|
471
|
+
|
|
472
|
+
// Add calculated amount
|
|
473
|
+
const calculatedAmountElement = doc.createElement('ram:CalculatedAmount');
|
|
474
|
+
calculatedAmountElement.textContent = taxAmount.toFixed(2);
|
|
475
|
+
taxElement.appendChild(calculatedAmountElement);
|
|
476
|
+
|
|
477
|
+
// Add type code (VAT)
|
|
478
|
+
const typeCodeElement = doc.createElement('ram:TypeCode');
|
|
479
|
+
typeCodeElement.textContent = 'VAT';
|
|
480
|
+
taxElement.appendChild(typeCodeElement);
|
|
481
|
+
|
|
482
|
+
// Add basis amount
|
|
483
|
+
const basisAmountElement = doc.createElement('ram:BasisAmount');
|
|
484
|
+
basisAmountElement.textContent = baseAmount.toFixed(2);
|
|
485
|
+
taxElement.appendChild(basisAmountElement);
|
|
486
|
+
|
|
487
|
+
// Add category code
|
|
488
|
+
const categoryCodeElement = doc.createElement('ram:CategoryCode');
|
|
489
|
+
categoryCodeElement.textContent = invoice.reverseCharge ? 'AE' : 'S';
|
|
490
|
+
taxElement.appendChild(categoryCodeElement);
|
|
491
|
+
|
|
492
|
+
// Add rate
|
|
493
|
+
const rateElement = doc.createElement('ram:RateApplicablePercent');
|
|
494
|
+
rateElement.textContent = rate.toString();
|
|
495
|
+
taxElement.appendChild(rateElement);
|
|
496
|
+
|
|
497
|
+
settlementElement.appendChild(taxElement);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Adds monetary summation to the settlement section
|
|
503
|
+
* @param doc XML document
|
|
504
|
+
* @param settlementElement Settlement element
|
|
505
|
+
* @param invoice Invoice data
|
|
506
|
+
*/
|
|
507
|
+
private addMonetarySummation(doc: Document, settlementElement: Element, invoice: TInvoice): void {
|
|
508
|
+
const monetarySummationElement = doc.createElement('ram:SpecifiedTradeSettlementHeaderMonetarySummation');
|
|
509
|
+
|
|
510
|
+
// Calculate totals
|
|
511
|
+
let totalNetAmount = 0;
|
|
512
|
+
let totalTaxAmount = 0;
|
|
513
|
+
|
|
514
|
+
// Calculate from items
|
|
515
|
+
if (invoice.items) {
|
|
516
|
+
for (const item of invoice.items) {
|
|
517
|
+
const itemNetAmount = item.unitNetPrice * item.unitQuantity;
|
|
518
|
+
const itemTaxAmount = itemNetAmount * (item.vatPercentage / 100);
|
|
519
|
+
|
|
520
|
+
totalNetAmount += itemNetAmount;
|
|
521
|
+
totalTaxAmount += itemTaxAmount;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const totalGrossAmount = totalNetAmount + totalTaxAmount;
|
|
526
|
+
|
|
527
|
+
// Add line total amount
|
|
528
|
+
const lineTotalElement = doc.createElement('ram:LineTotalAmount');
|
|
529
|
+
lineTotalElement.textContent = totalNetAmount.toFixed(2);
|
|
530
|
+
monetarySummationElement.appendChild(lineTotalElement);
|
|
531
|
+
|
|
532
|
+
// Add tax total amount
|
|
533
|
+
const taxTotalElement = doc.createElement('ram:TaxTotalAmount');
|
|
534
|
+
taxTotalElement.textContent = totalTaxAmount.toFixed(2);
|
|
535
|
+
taxTotalElement.setAttribute('currencyID', invoice.currency);
|
|
536
|
+
monetarySummationElement.appendChild(taxTotalElement);
|
|
537
|
+
|
|
538
|
+
// Add grand total amount
|
|
539
|
+
const grandTotalElement = doc.createElement('ram:GrandTotalAmount');
|
|
540
|
+
grandTotalElement.textContent = totalGrossAmount.toFixed(2);
|
|
541
|
+
monetarySummationElement.appendChild(grandTotalElement);
|
|
542
|
+
|
|
543
|
+
// Add due payable amount
|
|
544
|
+
const duePayableElement = doc.createElement('ram:DuePayableAmount');
|
|
545
|
+
duePayableElement.textContent = totalGrossAmount.toFixed(2);
|
|
546
|
+
monetarySummationElement.appendChild(duePayableElement);
|
|
547
|
+
|
|
548
|
+
settlementElement.appendChild(monetarySummationElement);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Adds line items to the XML document
|
|
553
|
+
* @param doc XML document
|
|
554
|
+
* @param transactionElement Transaction element
|
|
555
|
+
* @param invoice Invoice data
|
|
556
|
+
*/
|
|
557
|
+
private addLineItems(doc: Document, transactionElement: Element, invoice: TInvoice): void {
|
|
558
|
+
// Add each line item
|
|
559
|
+
if (invoice.items) {
|
|
560
|
+
for (const item of invoice.items) {
|
|
561
|
+
// Create line item element
|
|
562
|
+
const lineItemElement = doc.createElement('ram:IncludedSupplyChainTradeLineItem');
|
|
563
|
+
|
|
564
|
+
// Add line ID
|
|
565
|
+
const lineIdElement = doc.createElement('ram:AssociatedDocumentLineDocument');
|
|
566
|
+
const lineIdValueElement = doc.createElement('ram:LineID');
|
|
567
|
+
lineIdValueElement.textContent = item.position.toString();
|
|
568
|
+
lineIdElement.appendChild(lineIdValueElement);
|
|
569
|
+
lineItemElement.appendChild(lineIdElement);
|
|
570
|
+
|
|
571
|
+
// Add product information
|
|
572
|
+
const productElement = doc.createElement('ram:SpecifiedTradeProduct');
|
|
573
|
+
|
|
574
|
+
// Add name
|
|
575
|
+
const nameElement = doc.createElement('ram:Name');
|
|
576
|
+
nameElement.textContent = item.name;
|
|
577
|
+
productElement.appendChild(nameElement);
|
|
578
|
+
|
|
579
|
+
// Add article number if available
|
|
580
|
+
if (item.articleNumber) {
|
|
581
|
+
const articleNumberElement = doc.createElement('ram:SellerAssignedID');
|
|
582
|
+
articleNumberElement.textContent = item.articleNumber;
|
|
583
|
+
productElement.appendChild(articleNumberElement);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
lineItemElement.appendChild(productElement);
|
|
587
|
+
|
|
588
|
+
// Add agreement information (price)
|
|
589
|
+
const agreementElement = doc.createElement('ram:SpecifiedLineTradeAgreement');
|
|
590
|
+
const priceElement = doc.createElement('ram:NetPriceProductTradePrice');
|
|
591
|
+
const chargeAmountElement = doc.createElement('ram:ChargeAmount');
|
|
592
|
+
chargeAmountElement.textContent = item.unitNetPrice.toFixed(2);
|
|
593
|
+
priceElement.appendChild(chargeAmountElement);
|
|
594
|
+
agreementElement.appendChild(priceElement);
|
|
595
|
+
lineItemElement.appendChild(agreementElement);
|
|
596
|
+
|
|
597
|
+
// Add delivery information (quantity)
|
|
598
|
+
const deliveryElement = doc.createElement('ram:SpecifiedLineTradeDelivery');
|
|
599
|
+
const quantityElement = doc.createElement('ram:BilledQuantity');
|
|
600
|
+
quantityElement.textContent = item.unitQuantity.toString();
|
|
601
|
+
quantityElement.setAttribute('unitCode', item.unitType);
|
|
602
|
+
deliveryElement.appendChild(quantityElement);
|
|
603
|
+
lineItemElement.appendChild(deliveryElement);
|
|
604
|
+
|
|
605
|
+
// Add settlement information (tax)
|
|
606
|
+
const settlementElement = doc.createElement('ram:SpecifiedLineTradeSettlement');
|
|
607
|
+
|
|
608
|
+
// Add tax information
|
|
609
|
+
const taxElement = doc.createElement('ram:ApplicableTradeTax');
|
|
610
|
+
|
|
611
|
+
// Add tax type code
|
|
612
|
+
const taxTypeCodeElement = doc.createElement('ram:TypeCode');
|
|
613
|
+
taxTypeCodeElement.textContent = 'VAT';
|
|
614
|
+
taxElement.appendChild(taxTypeCodeElement);
|
|
615
|
+
|
|
616
|
+
// Add tax category code
|
|
617
|
+
const taxCategoryCodeElement = doc.createElement('ram:CategoryCode');
|
|
618
|
+
taxCategoryCodeElement.textContent = invoice.reverseCharge ? 'AE' : 'S';
|
|
619
|
+
taxElement.appendChild(taxCategoryCodeElement);
|
|
620
|
+
|
|
621
|
+
// Add tax rate
|
|
622
|
+
const taxRateElement = doc.createElement('ram:RateApplicablePercent');
|
|
623
|
+
taxRateElement.textContent = item.vatPercentage.toString();
|
|
624
|
+
taxElement.appendChild(taxRateElement);
|
|
625
|
+
|
|
626
|
+
settlementElement.appendChild(taxElement);
|
|
627
|
+
|
|
628
|
+
// Add monetary summation
|
|
629
|
+
const monetarySummationElement = doc.createElement('ram:SpecifiedLineTradeSettlementMonetarySummation');
|
|
630
|
+
|
|
631
|
+
// Calculate item total
|
|
632
|
+
const itemNetAmount = item.unitNetPrice * item.unitQuantity;
|
|
633
|
+
|
|
634
|
+
// Add line total amount
|
|
635
|
+
const lineTotalElement = doc.createElement('ram:LineTotalAmount');
|
|
636
|
+
lineTotalElement.textContent = itemNetAmount.toFixed(2);
|
|
637
|
+
monetarySummationElement.appendChild(lineTotalElement);
|
|
638
|
+
|
|
639
|
+
settlementElement.appendChild(monetarySummationElement);
|
|
640
|
+
|
|
641
|
+
lineItemElement.appendChild(settlementElement);
|
|
642
|
+
|
|
643
|
+
// Add line item to transaction
|
|
644
|
+
transactionElement.appendChild(lineItemElement);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Formats a date as YYYYMMDD
|
|
651
|
+
* @param timestamp Timestamp to format
|
|
652
|
+
* @returns Formatted date string
|
|
653
|
+
*/
|
|
654
|
+
private formatDateYYYYMMDD(timestamp: number): string {
|
|
655
|
+
const date = new Date(timestamp);
|
|
656
|
+
const year = date.getFullYear();
|
|
657
|
+
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
658
|
+
const day = date.getDate().toString().padStart(2, '0');
|
|
659
|
+
return `${year}${month}${day}`;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CIIProfile, CII_PROFILE_IDS } from '../cii.types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ZUGFeRD specific constants and types
|
|
5
|
+
*/
|
|
6
|
+
|
|
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
|
+
// ZUGFeRD PDF attachment filename
|
|
15
|
+
export const ZUGFERD_ATTACHMENT_FILENAME = 'zugferd-invoice.xml';
|
|
16
|
+
|
|
17
|
+
// ZUGFeRD PDF attachment description
|
|
18
|
+
export const ZUGFERD_ATTACHMENT_DESCRIPTION = 'ZUGFeRD XML Invoice';
|