@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,249 @@
|
|
|
1
|
+
import { InvoiceFormat } from '../../interfaces/common.js';
|
|
2
|
+
import { DOMParser, xpath } from '../../plugins.js';
|
|
3
|
+
import { CII_PROFILE_IDS, ZUGFERD_V1_NAMESPACES } from '../cii/cii.types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Utility class for detecting invoice formats
|
|
6
|
+
*/
|
|
7
|
+
export class FormatDetector {
|
|
8
|
+
/**
|
|
9
|
+
* Detects the format of an XML document
|
|
10
|
+
* @param xml XML content to analyze
|
|
11
|
+
* @returns Detected invoice format
|
|
12
|
+
*/
|
|
13
|
+
static detectFormat(xml) {
|
|
14
|
+
try {
|
|
15
|
+
// Quick check for empty or invalid XML
|
|
16
|
+
if (!xml || typeof xml !== 'string' || xml.trim().length === 0) {
|
|
17
|
+
return InvoiceFormat.UNKNOWN;
|
|
18
|
+
}
|
|
19
|
+
// Quick string-based pre-checks for performance
|
|
20
|
+
const quickCheck = FormatDetector.quickFormatCheck(xml);
|
|
21
|
+
if (quickCheck !== InvoiceFormat.UNKNOWN) {
|
|
22
|
+
return quickCheck;
|
|
23
|
+
}
|
|
24
|
+
// More thorough parsing-based checks
|
|
25
|
+
const doc = new DOMParser().parseFromString(xml, 'application/xml');
|
|
26
|
+
const root = doc.documentElement;
|
|
27
|
+
if (!root) {
|
|
28
|
+
return InvoiceFormat.UNKNOWN;
|
|
29
|
+
}
|
|
30
|
+
// UBL detection (Invoice or CreditNote root element)
|
|
31
|
+
if (FormatDetector.isUBLFormat(root)) {
|
|
32
|
+
// Check for XRechnung customization
|
|
33
|
+
if (FormatDetector.isXRechnungFormat(doc)) {
|
|
34
|
+
return InvoiceFormat.XRECHNUNG;
|
|
35
|
+
}
|
|
36
|
+
return InvoiceFormat.UBL;
|
|
37
|
+
}
|
|
38
|
+
// Factur-X/ZUGFeRD detection (CrossIndustryInvoice root element)
|
|
39
|
+
if (FormatDetector.isCIIFormat(root)) {
|
|
40
|
+
return FormatDetector.detectCIIFormat(doc, xml);
|
|
41
|
+
}
|
|
42
|
+
// ZUGFeRD v1 detection (CrossIndustryDocument root element)
|
|
43
|
+
if (FormatDetector.isZUGFeRDV1Format(root)) {
|
|
44
|
+
return InvoiceFormat.ZUGFERD;
|
|
45
|
+
}
|
|
46
|
+
// FatturaPA detection
|
|
47
|
+
if (FormatDetector.isFatturaPAFormat(root)) {
|
|
48
|
+
return InvoiceFormat.FATTURAPA;
|
|
49
|
+
}
|
|
50
|
+
return InvoiceFormat.UNKNOWN;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error('Error detecting format:', error);
|
|
54
|
+
return InvoiceFormat.UNKNOWN;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Performs a quick format check based on string content
|
|
59
|
+
* This is faster than full XML parsing for obvious cases
|
|
60
|
+
* @param xml XML string
|
|
61
|
+
* @returns Detected format or UNKNOWN if more analysis is needed
|
|
62
|
+
*/
|
|
63
|
+
static quickFormatCheck(xml) {
|
|
64
|
+
const lowerXml = xml.toLowerCase();
|
|
65
|
+
// Check for obvious Factur-X indicators
|
|
66
|
+
if (lowerXml.includes('factur-x.eu') ||
|
|
67
|
+
lowerXml.includes('factur-x.xml') ||
|
|
68
|
+
lowerXml.includes('factur-x:') ||
|
|
69
|
+
lowerXml.includes('urn:cen.eu:en16931:2017') && lowerXml.includes('factur-x')) {
|
|
70
|
+
return InvoiceFormat.FACTURX;
|
|
71
|
+
}
|
|
72
|
+
// Check for obvious ZUGFeRD indicators
|
|
73
|
+
if (lowerXml.includes('zugferd:') ||
|
|
74
|
+
lowerXml.includes('zugferd-invoice.xml') ||
|
|
75
|
+
lowerXml.includes('urn:ferd:') ||
|
|
76
|
+
lowerXml.includes('urn:zugferd')) {
|
|
77
|
+
return InvoiceFormat.ZUGFERD;
|
|
78
|
+
}
|
|
79
|
+
// Check for obvious XRechnung indicators
|
|
80
|
+
if (lowerXml.includes('xrechnung') ||
|
|
81
|
+
lowerXml.includes('urn:xoev-de:kosit:standard:xrechnung')) {
|
|
82
|
+
return InvoiceFormat.XRECHNUNG;
|
|
83
|
+
}
|
|
84
|
+
// Check for obvious FatturaPA indicators
|
|
85
|
+
if (lowerXml.includes('fatturapa') ||
|
|
86
|
+
lowerXml.includes('fattura elettronica') ||
|
|
87
|
+
lowerXml.includes('fatturaelettronica')) {
|
|
88
|
+
return InvoiceFormat.FATTURAPA;
|
|
89
|
+
}
|
|
90
|
+
// Need more analysis
|
|
91
|
+
return InvoiceFormat.UNKNOWN;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Checks if the document is a UBL format
|
|
95
|
+
* @param root Root element
|
|
96
|
+
* @returns True if it's a UBL format
|
|
97
|
+
*/
|
|
98
|
+
static isUBLFormat(root) {
|
|
99
|
+
return (root.nodeName === 'Invoice' ||
|
|
100
|
+
root.nodeName === 'CreditNote' ||
|
|
101
|
+
root.nodeName === 'ubl:Invoice' ||
|
|
102
|
+
root.nodeName === 'ubl:CreditNote' ||
|
|
103
|
+
root.nodeName.endsWith(':Invoice') ||
|
|
104
|
+
root.nodeName.endsWith(':CreditNote'));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Checks if the document is an XRechnung format
|
|
108
|
+
* @param doc XML document
|
|
109
|
+
* @returns True if it's an XRechnung format
|
|
110
|
+
*/
|
|
111
|
+
static isXRechnungFormat(doc) {
|
|
112
|
+
try {
|
|
113
|
+
// Set up namespaces for XPath queries
|
|
114
|
+
const namespaces = {
|
|
115
|
+
'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
|
|
116
|
+
'ubl': 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2'
|
|
117
|
+
};
|
|
118
|
+
// Create XPath selector with namespaces
|
|
119
|
+
const select = xpath.useNamespaces(namespaces);
|
|
120
|
+
// Use getElementsByTagName directly for more reliable results
|
|
121
|
+
const customizationNodes = doc.getElementsByTagName('cbc:CustomizationID');
|
|
122
|
+
// Check if any CustomizationID node contains "xrechnung"
|
|
123
|
+
for (let i = 0; i < customizationNodes.length; i++) {
|
|
124
|
+
const node = customizationNodes[i];
|
|
125
|
+
if (node.textContent && node.textContent.includes('xrechnung')) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
console.warn('Error checking for XRechnung format:', error);
|
|
133
|
+
// If direct DOM access fails, try a string-based approach
|
|
134
|
+
const xmlStr = new XMLSerializer().serializeToString(doc);
|
|
135
|
+
return xmlStr.includes('xrechnung') || xmlStr.includes('XRechnung');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Checks if the document is a CII format (Factur-X/ZUGFeRD v2+)
|
|
140
|
+
* @param root Root element
|
|
141
|
+
* @returns True if it's a CII format
|
|
142
|
+
*/
|
|
143
|
+
static isCIIFormat(root) {
|
|
144
|
+
return (root.nodeName === 'rsm:CrossIndustryInvoice' ||
|
|
145
|
+
root.nodeName === 'CrossIndustryInvoice' ||
|
|
146
|
+
root.nodeName.endsWith(':CrossIndustryInvoice'));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Checks if the document is a ZUGFeRD v1 format
|
|
150
|
+
* @param root Root element
|
|
151
|
+
* @returns True if it's a ZUGFeRD v1 format
|
|
152
|
+
*/
|
|
153
|
+
static isZUGFeRDV1Format(root) {
|
|
154
|
+
return (root.nodeName === 'rsm:CrossIndustryDocument' ||
|
|
155
|
+
root.nodeName === 'CrossIndustryDocument' ||
|
|
156
|
+
root.nodeName === 'ram:CrossIndustryDocument' ||
|
|
157
|
+
root.nodeName.endsWith(':CrossIndustryDocument'));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Checks if the document is a FatturaPA format
|
|
161
|
+
* @param root Root element
|
|
162
|
+
* @returns True if it's a FatturaPA format
|
|
163
|
+
*/
|
|
164
|
+
static isFatturaPAFormat(root) {
|
|
165
|
+
return (root.nodeName === 'FatturaElettronica' ||
|
|
166
|
+
(root.getAttribute('xmlns') && root.getAttribute('xmlns').includes('fatturapa.gov.it')));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Detects the specific CII format (Factur-X vs ZUGFeRD)
|
|
170
|
+
* @param doc XML document
|
|
171
|
+
* @param xml Original XML string for fallback checks
|
|
172
|
+
* @returns Detected format
|
|
173
|
+
*/
|
|
174
|
+
static detectCIIFormat(doc, xml) {
|
|
175
|
+
try {
|
|
176
|
+
// Use direct DOM traversal instead of XPath for more reliable behavior
|
|
177
|
+
const contextNodes = doc.getElementsByTagNameNS('urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100', 'ExchangedDocumentContext');
|
|
178
|
+
if (contextNodes.length === 0) {
|
|
179
|
+
// Try without namespace
|
|
180
|
+
const noNsContextNodes = doc.getElementsByTagName('ExchangedDocumentContext');
|
|
181
|
+
if (noNsContextNodes.length === 0) {
|
|
182
|
+
// Fallback to string-based detection
|
|
183
|
+
return FormatDetector.detectCIIFormatFromString(xml);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Loop through all potential context nodes
|
|
187
|
+
const allContextNodes = [...Array.from(contextNodes), ...Array.from(doc.getElementsByTagName('ExchangedDocumentContext'))];
|
|
188
|
+
for (const contextNode of allContextNodes) {
|
|
189
|
+
// Find guideline parameter
|
|
190
|
+
const guidelineNodes = contextNode.getElementsByTagName('ram:GuidelineSpecifiedDocumentContextParameter');
|
|
191
|
+
if (guidelineNodes.length === 0) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
for (const guidelineNode of Array.from(guidelineNodes)) {
|
|
195
|
+
// Find ID element
|
|
196
|
+
const idNodes = guidelineNode.getElementsByTagName('ram:ID');
|
|
197
|
+
if (idNodes.length === 0) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
for (const idNode of Array.from(idNodes)) {
|
|
201
|
+
const profileText = idNode.textContent || '';
|
|
202
|
+
// Check for ZUGFeRD profiles (v1 and v2)
|
|
203
|
+
if (profileText.includes('zugferd') ||
|
|
204
|
+
profileText.includes('urn:ferd:') ||
|
|
205
|
+
profileText === CII_PROFILE_IDS.ZUGFERD_BASIC ||
|
|
206
|
+
profileText === CII_PROFILE_IDS.ZUGFERD_COMFORT ||
|
|
207
|
+
profileText === CII_PROFILE_IDS.ZUGFERD_EXTENDED ||
|
|
208
|
+
profileText === CII_PROFILE_IDS.ZUGFERD_V1_BASIC ||
|
|
209
|
+
profileText === CII_PROFILE_IDS.ZUGFERD_V1_COMFORT ||
|
|
210
|
+
profileText === CII_PROFILE_IDS.ZUGFERD_V1_EXTENDED) {
|
|
211
|
+
return InvoiceFormat.ZUGFERD;
|
|
212
|
+
}
|
|
213
|
+
// Check for Factur-X profiles
|
|
214
|
+
if (profileText.includes('factur-x') ||
|
|
215
|
+
profileText === CII_PROFILE_IDS.FACTURX_MINIMUM ||
|
|
216
|
+
profileText === CII_PROFILE_IDS.FACTURX_BASIC ||
|
|
217
|
+
profileText === CII_PROFILE_IDS.FACTURX_EN16931) {
|
|
218
|
+
return InvoiceFormat.FACTURX;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// If we reach here, fall back to string checking
|
|
224
|
+
return FormatDetector.detectCIIFormatFromString(xml);
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
console.warn('Error detecting CII format, falling back to generic CII:', error);
|
|
228
|
+
return FormatDetector.detectCIIFormatFromString(xml);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Fallback method to detect CII format from string content
|
|
233
|
+
* @param xml XML string
|
|
234
|
+
* @returns Detected format
|
|
235
|
+
*/
|
|
236
|
+
static detectCIIFormatFromString(xml) {
|
|
237
|
+
// Check for Factur-X indicators
|
|
238
|
+
if (xml.includes('factur-x') || xml.includes('Factur-X')) {
|
|
239
|
+
return InvoiceFormat.FACTURX;
|
|
240
|
+
}
|
|
241
|
+
// Check for ZUGFeRD indicators
|
|
242
|
+
if (xml.includes('zugferd') || xml.includes('ZUGFeRD')) {
|
|
243
|
+
return InvoiceFormat.ZUGFERD;
|
|
244
|
+
}
|
|
245
|
+
// Generic CII if we can't determine more specifically
|
|
246
|
+
return InvoiceFormat.CII;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybWF0LmRldGVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvZm9ybWF0cy91dGlscy9mb3JtYXQuZGV0ZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzNELE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTdFOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGNBQWM7SUFDekI7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBVztRQUNwQyxJQUFJLENBQUM7WUFDSCx1Q0FBdUM7WUFDdkMsSUFBSSxDQUFDLEdBQUcsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDL0QsT0FBTyxhQUFhLENBQUMsT0FBTyxDQUFDO1lBQy9CLENBQUM7WUFFRCxnREFBZ0Q7WUFDaEQsTUFBTSxVQUFVLEdBQUcsY0FBYyxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3hELElBQUksVUFBVSxLQUFLLGFBQWEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDekMsT0FBTyxVQUFVLENBQUM7WUFDcEIsQ0FBQztZQUVELHFDQUFxQztZQUNyQyxNQUFNLEdBQUcsR0FBRyxJQUFJLFNBQVMsRUFBRSxDQUFDLGVBQWUsQ0FBQyxHQUFHLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztZQUNwRSxNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsZUFBZSxDQUFDO1lBRWpDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDVixPQUFPLGFBQWEsQ0FBQyxPQUFPLENBQUM7WUFDL0IsQ0FBQztZQUVELHFEQUFx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
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EN16931 mandatory field validator
|
|
3
|
+
* Validates that invoices contain the minimum required fields per the EN16931 standard
|
|
4
|
+
*/
|
|
5
|
+
export declare class EN16931Validator {
|
|
6
|
+
/**
|
|
7
|
+
* Valid ISO 4217 currency codes (common subset)
|
|
8
|
+
*/
|
|
9
|
+
private static readonly VALID_CURRENCIES;
|
|
10
|
+
/**
|
|
11
|
+
* Validates that an invoice object contains all mandatory EN16931 fields
|
|
12
|
+
* @param invoice The invoice object to validate
|
|
13
|
+
* @throws Error if mandatory fields are missing
|
|
14
|
+
*/
|
|
15
|
+
static validateMandatoryFields(invoice: any): void;
|
|
16
|
+
/**
|
|
17
|
+
* Validates mandatory fields for a parsed XML structure
|
|
18
|
+
* @param doc The parsed XML document
|
|
19
|
+
* @param format The invoice format
|
|
20
|
+
* @throws Error if mandatory fields are missing in XML
|
|
21
|
+
*/
|
|
22
|
+
static validateXmlMandatoryFields(doc: Document, format: string): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EN16931 mandatory field validator
|
|
3
|
+
* Validates that invoices contain the minimum required fields per the EN16931 standard
|
|
4
|
+
*/
|
|
5
|
+
export class EN16931Validator {
|
|
6
|
+
/**
|
|
7
|
+
* Valid ISO 4217 currency codes (common subset)
|
|
8
|
+
*/
|
|
9
|
+
static { this.VALID_CURRENCIES = [
|
|
10
|
+
'AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN',
|
|
11
|
+
'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL',
|
|
12
|
+
'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY',
|
|
13
|
+
'COP', 'CRC', 'CUC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD',
|
|
14
|
+
'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GGP', 'GHS',
|
|
15
|
+
'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF',
|
|
16
|
+
'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD',
|
|
17
|
+
'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD', 'KZT',
|
|
18
|
+
'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD',
|
|
19
|
+
'MMK', 'MNT', 'MOP', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN',
|
|
20
|
+
'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK',
|
|
21
|
+
'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR',
|
|
22
|
+
'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SPL', 'SRD',
|
|
23
|
+
'STN', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD',
|
|
24
|
+
'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VEF', 'VND',
|
|
25
|
+
'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW',
|
|
26
|
+
'ZWD'
|
|
27
|
+
]; }
|
|
28
|
+
/**
|
|
29
|
+
* Validates that an invoice object contains all mandatory EN16931 fields
|
|
30
|
+
* @param invoice The invoice object to validate
|
|
31
|
+
* @throws Error if mandatory fields are missing
|
|
32
|
+
*/
|
|
33
|
+
static validateMandatoryFields(invoice) {
|
|
34
|
+
const errors = [];
|
|
35
|
+
// BR-01: Invoice number is mandatory
|
|
36
|
+
if (!invoice.id && !invoice.accountingDocId && !invoice.invoiceId) {
|
|
37
|
+
errors.push('BR-01: Invoice number is mandatory');
|
|
38
|
+
}
|
|
39
|
+
// BR-02: Invoice issue date is mandatory
|
|
40
|
+
if (!invoice.date && !invoice.issueDate) {
|
|
41
|
+
errors.push('BR-02: Invoice issue date is mandatory');
|
|
42
|
+
}
|
|
43
|
+
// BR-06: Seller name is mandatory
|
|
44
|
+
if (!invoice.from?.name) {
|
|
45
|
+
errors.push('BR-06: Seller name is mandatory');
|
|
46
|
+
}
|
|
47
|
+
// BR-07: Buyer name is mandatory
|
|
48
|
+
if (!invoice.to?.name) {
|
|
49
|
+
errors.push('BR-07: Buyer name is mandatory');
|
|
50
|
+
}
|
|
51
|
+
// BR-16: Invoice line is mandatory (at least one)
|
|
52
|
+
if (!invoice.items || invoice.items.length === 0) {
|
|
53
|
+
errors.push('BR-16: At least one invoice line is mandatory');
|
|
54
|
+
}
|
|
55
|
+
// BR-03: Invoice type code is mandatory
|
|
56
|
+
if (!invoice.accountingDocType) {
|
|
57
|
+
errors.push('BR-03: Invoice type code is mandatory');
|
|
58
|
+
}
|
|
59
|
+
// BR-05: Invoice currency code is mandatory
|
|
60
|
+
if (!invoice.currency) {
|
|
61
|
+
errors.push('BR-05: Invoice currency code is mandatory');
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Validate currency format
|
|
65
|
+
if (!this.VALID_CURRENCIES.includes(invoice.currency.toUpperCase())) {
|
|
66
|
+
errors.push(`Invalid currency code: ${invoice.currency}. Must be a valid ISO 4217 currency code`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// BR-08: Seller postal address is mandatory
|
|
70
|
+
if (!invoice.from?.address?.city || !invoice.from?.address?.postalCode || (!invoice.from?.address?.countryCode && !invoice.from?.address?.country)) {
|
|
71
|
+
errors.push('BR-08: Seller postal address (city, postal code, country) is mandatory');
|
|
72
|
+
}
|
|
73
|
+
// BR-10: Buyer postal address is mandatory
|
|
74
|
+
if (!invoice.to?.address?.city || !invoice.to?.address?.postalCode || (!invoice.to?.address?.countryCode && !invoice.to?.address?.country)) {
|
|
75
|
+
errors.push('BR-10: Buyer postal address (city, postal code, country) is mandatory');
|
|
76
|
+
}
|
|
77
|
+
if (errors.length > 0) {
|
|
78
|
+
throw new Error(`EN16931 validation failed:\n${errors.join('\n')}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Validates mandatory fields for a parsed XML structure
|
|
83
|
+
* @param doc The parsed XML document
|
|
84
|
+
* @param format The invoice format
|
|
85
|
+
* @throws Error if mandatory fields are missing in XML
|
|
86
|
+
*/
|
|
87
|
+
static validateXmlMandatoryFields(doc, format) {
|
|
88
|
+
const errors = [];
|
|
89
|
+
if (format === 'ubl' || format === 'xrechnung') {
|
|
90
|
+
// Check for UBL mandatory fields
|
|
91
|
+
const id = doc.getElementsByTagName('cbc:ID')[0]?.textContent;
|
|
92
|
+
if (!id) {
|
|
93
|
+
errors.push('BR-01: Invoice ID is missing in XML');
|
|
94
|
+
}
|
|
95
|
+
const issueDate = doc.getElementsByTagName('cbc:IssueDate')[0]?.textContent;
|
|
96
|
+
if (!issueDate) {
|
|
97
|
+
errors.push('BR-02: Invoice issue date is missing in XML');
|
|
98
|
+
}
|
|
99
|
+
const sellerName = doc.querySelector('AccountingSupplierParty PartyName Name')?.textContent ||
|
|
100
|
+
doc.querySelector('AccountingSupplierParty PartyLegalEntity RegistrationName')?.textContent;
|
|
101
|
+
if (!sellerName) {
|
|
102
|
+
errors.push('BR-06: Seller name is missing in XML');
|
|
103
|
+
}
|
|
104
|
+
const buyerName = doc.querySelector('AccountingCustomerParty PartyName Name')?.textContent ||
|
|
105
|
+
doc.querySelector('AccountingCustomerParty PartyLegalEntity RegistrationName')?.textContent;
|
|
106
|
+
if (!buyerName) {
|
|
107
|
+
errors.push('BR-07: Buyer name is missing in XML');
|
|
108
|
+
}
|
|
109
|
+
const invoiceLines = doc.getElementsByTagName('InvoiceLine');
|
|
110
|
+
if (invoiceLines.length === 0) {
|
|
111
|
+
errors.push('BR-16: No invoice lines found in XML');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (errors.length > 0) {
|
|
115
|
+
throw new Error(`EN16931 XML validation failed:\n${errors.join('\n')}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW4xNjkzMS52YWxpZGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9mb3JtYXRzL3ZhbGlkYXRpb24vZW4xNjkzMS52YWxpZGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLGdCQUFnQjtJQUMzQjs7T0FFRzthQUNxQixxQkFBZ0IsR0FBRztRQUN6QyxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLO1FBQ3BFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUs7UUFDcEUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSztRQUNwRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLO1FBQ3BFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUs7UUFDcEUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSztRQUNwRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLO1FBQ3BFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUs7UUFDcEUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSztRQUNwRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLO1FBQ3BFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUs7UUFDcEUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSztRQUNwRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLO1FBQ3BFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUs7UUFDcEUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSztRQUNwRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVB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
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BaseValidator } from './base.validator.js';
|
|
2
|
+
/**
|
|
3
|
+
* Factory to create the appropriate validator based on the XML format
|
|
4
|
+
*/
|
|
5
|
+
export declare class ValidatorFactory {
|
|
6
|
+
/**
|
|
7
|
+
* Creates a validator for the specified XML content
|
|
8
|
+
* @param xml XML content to validate
|
|
9
|
+
* @returns Appropriate validator instance
|
|
10
|
+
*/
|
|
11
|
+
static createValidator(xml: string): BaseValidator;
|
|
12
|
+
/**
|
|
13
|
+
* Detects the invoice format from XML content
|
|
14
|
+
* @param xml XML content to analyze
|
|
15
|
+
* @returns Detected invoice format
|
|
16
|
+
*/
|
|
17
|
+
private static detectFormat;
|
|
18
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { InvoiceFormat } from '../interfaces.js';
|
|
2
|
+
import { BaseValidator } from './base.validator.js';
|
|
3
|
+
import { FacturXValidator } from './facturx.validator.js';
|
|
4
|
+
import { UBLValidator } from './ubl.validator.js';
|
|
5
|
+
import { DOMParser } from 'xmldom';
|
|
6
|
+
/**
|
|
7
|
+
* Factory to create the appropriate validator based on the XML format
|
|
8
|
+
*/
|
|
9
|
+
export class ValidatorFactory {
|
|
10
|
+
/**
|
|
11
|
+
* Creates a validator for the specified XML content
|
|
12
|
+
* @param xml XML content to validate
|
|
13
|
+
* @returns Appropriate validator instance
|
|
14
|
+
*/
|
|
15
|
+
static createValidator(xml) {
|
|
16
|
+
const format = ValidatorFactory.detectFormat(xml);
|
|
17
|
+
switch (format) {
|
|
18
|
+
case InvoiceFormat.UBL:
|
|
19
|
+
case InvoiceFormat.XRECHNUNG:
|
|
20
|
+
return new UBLValidator(xml);
|
|
21
|
+
case InvoiceFormat.CII:
|
|
22
|
+
case InvoiceFormat.ZUGFERD:
|
|
23
|
+
case InvoiceFormat.FACTURX:
|
|
24
|
+
return new FacturXValidator(xml);
|
|
25
|
+
// FatturaPA and other formats would be implemented here
|
|
26
|
+
default:
|
|
27
|
+
throw new Error(`Unsupported invoice format: ${format}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Detects the invoice format from XML content
|
|
32
|
+
* @param xml XML content to analyze
|
|
33
|
+
* @returns Detected invoice format
|
|
34
|
+
*/
|
|
35
|
+
static detectFormat(xml) {
|
|
36
|
+
try {
|
|
37
|
+
const doc = new DOMParser().parseFromString(xml, 'application/xml');
|
|
38
|
+
const root = doc.documentElement;
|
|
39
|
+
if (!root) {
|
|
40
|
+
return InvoiceFormat.UNKNOWN;
|
|
41
|
+
}
|
|
42
|
+
// UBL detection (Invoice or CreditNote root element)
|
|
43
|
+
if (root.nodeName === 'Invoice' || root.nodeName === 'CreditNote') {
|
|
44
|
+
// Check if it's XRechnung by looking at CustomizationID
|
|
45
|
+
const customizationNodes = root.getElementsByTagName('cbc:CustomizationID');
|
|
46
|
+
if (customizationNodes.length > 0) {
|
|
47
|
+
const customizationId = customizationNodes[0].textContent || '';
|
|
48
|
+
if (customizationId.includes('xrechnung') || customizationId.includes('XRechnung')) {
|
|
49
|
+
return InvoiceFormat.XRECHNUNG;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return InvoiceFormat.UBL;
|
|
53
|
+
}
|
|
54
|
+
// Factur-X/ZUGFeRD detection (CrossIndustryInvoice root element)
|
|
55
|
+
if (root.nodeName === 'rsm:CrossIndustryInvoice' || root.nodeName === 'CrossIndustryInvoice') {
|
|
56
|
+
// Check for profile to determine if it's Factur-X or ZUGFeRD
|
|
57
|
+
const profileNodes = root.getElementsByTagName('ram:ID');
|
|
58
|
+
for (let i = 0; i < profileNodes.length; i++) {
|
|
59
|
+
const profileText = profileNodes[i].textContent || '';
|
|
60
|
+
if (profileText.includes('factur-x') || profileText.includes('Factur-X')) {
|
|
61
|
+
return InvoiceFormat.FACTURX;
|
|
62
|
+
}
|
|
63
|
+
if (profileText.includes('zugferd') || profileText.includes('ZUGFeRD')) {
|
|
64
|
+
return InvoiceFormat.ZUGFERD;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// If no specific profile found, default to CII
|
|
68
|
+
return InvoiceFormat.CII;
|
|
69
|
+
}
|
|
70
|
+
// FatturaPA detection would be implemented here
|
|
71
|
+
return InvoiceFormat.UNKNOWN;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return InvoiceFormat.UNKNOWN;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmZhY3RvcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9mb3JtYXRzL3ZhbGlkYXRvci5mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUVqRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDMUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFbkM7O0dBRUc7QUFDSCxNQUFNLE9BQU8sZ0JBQWdCO0lBQzNCOzs7O09BSUc7SUFDSSxNQUFNLENBQUMsZUFBZSxDQUFDLEdBQVc7UUFDdkMsTUFBTSxNQUFNLEdBQUcsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRWxELFFBQVEsTUFBTSxFQUFFLENBQUM7WUFDZixLQUFLLGFBQWEsQ0FBQyxHQUFHLENBQUM7WUFDdkIsS0FBSyxhQUFhLENBQUMsU0FBUztnQkFDMUIsT0FBTyxJQUFJLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUUvQixLQUFLLGFBQWEsQ0FBQyxHQUFHLENBQUM7WUFDdkIsS0FBSyxhQUFhLENBQUMsT0FBTyxDQUFDO1lBQzNCLEtBQUssYUFBYSxDQUFDLE9BQU87Z0JBQ3hCLE9BQU8sSUFBSSxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUVuQyx3REFBd0Q7WUFFeEQ7Z0JBQ0UsTUFBTSxJQUFJLEtBQUssQ0FBQywrQkFBK0IsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUM3RCxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQVc7UUFDckMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxHQUFHLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQyxlQUFlLENBQUMsR0FBRyxFQUFFLGlCQUFpQixDQUFDLENBQUM7WUFDcEUsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLGVBQWUsQ0FBQztZQUVqQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ1YsT0FBTyxhQUFhLENBQUMsT0FBTyxDQUFDO1lBQy9CLENBQUM7WUFFRCxxREFBcUQ7WUFDckQsSUFBSSxJQUFJLENBQUMsUUFBUSxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsUUFBUSxLQUFLLFlBQVksRUFBRSxDQUFDO2dCQUNsRSx3REFBd0Q7Z0JBQ3hELE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLHFCQUFxQixDQUFDLENBQUM7Z0JBQzVFLElBQUksa0JBQWtCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUNsQyxNQUFNLGVBQWUsR0FBRyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDO29CQUNoRSxJQUFJLGVBQWUsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLElBQUksZUFBZSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO3dCQUNuRixPQUFPLGFBQWEsQ0FBQyxTQUFTLENBQUM7b0JBQ2pDLENBQUM7Z0JBQ0gsQ0FBQztnQkFFRCxPQUFPLGFBQWEsQ0FBQyxHQUFHLENBQUM7WUFDM0IsQ0FBQztZQUVELGlFQUFpRTtZQUNqRSxJQUFJLElBQUksQ0FBQyxRQUFRLEtBQUssMEJBQTBCLElBQUksSUFBSSxDQUFDLFFBQVEsS0FBSyxzQkFBc0IsRUFBRSxDQUFDO2dCQUM3Riw2REFBNkQ7Z0JBQzdELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDekQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFlBQVksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztvQkFDN0MsTUFBTSxXQUFXLEdBQUcsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsSUFBSSxFQUFFLENBQUM7b0JBRXRELElBQUksV0FBVyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsSUFBSSxXQUFXLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7d0JBQ3pFLE9BQU8sYUFBYSxDQUFDLE9BQU8sQ0FBQztvQkFDL0IsQ0FBQztvQkFFRCxJQUFJLFdBQVcsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksV0FBVyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO3dCQUN2RSxPQUFPLGFBQWEsQ0FBQyxPQUFPLENBQUM7b0JBQy9CLENBQUM7Z0JBQ0gsQ0FBQztnQkFFRCwrQ0FBK0M7Z0JBQy9DLE9BQU8sYUFBYSxDQUFDLEdBQUcsQ0FBQztZQUMzQixDQUFDO1lBRUQsZ0RBQWdEO1lBRWhELE9BQU8sYUFBYSxDQUFDLE9BQU8sQ0FBQztRQUMvQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sYUFBYSxDQUFDLE9BQU8sQ0FBQztRQUMvQixDQUFDO0lBQ0gsQ0FBQztDQUNGIn0=
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { BaseDecoder } from './base.decoder.js';
|
|
3
|
+
/**
|
|
4
|
+
* A decoder specifically for XInvoice/XRechnung format.
|
|
5
|
+
* XRechnung is the German implementation of the European standard EN16931
|
|
6
|
+
* for electronic invoices to the German public sector.
|
|
7
|
+
*/
|
|
8
|
+
export declare class XInvoiceDecoder extends BaseDecoder {
|
|
9
|
+
private xmlDoc;
|
|
10
|
+
private namespaces;
|
|
11
|
+
constructor(xmlString: string);
|
|
12
|
+
/**
|
|
13
|
+
* Set up namespaces from the document
|
|
14
|
+
*/
|
|
15
|
+
private setupNamespaces;
|
|
16
|
+
/**
|
|
17
|
+
* Extract element text by tag name with namespace awareness
|
|
18
|
+
*/
|
|
19
|
+
private getElementText;
|
|
20
|
+
/**
|
|
21
|
+
* Converts XInvoice/XRechnung XML to a structured letter object
|
|
22
|
+
*/
|
|
23
|
+
getLetterData(): Promise<plugins.tsclass.business.ILetter>;
|
|
24
|
+
/**
|
|
25
|
+
* Extracts invoice items from XInvoice document
|
|
26
|
+
*/
|
|
27
|
+
private extractInvoiceItems;
|
|
28
|
+
}
|