@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,107 @@
|
|
|
1
|
+
import { EN16931UBLValidator } from './en16931.ubl.validator.js';
|
|
2
|
+
/**
|
|
3
|
+
* XRechnung-specific validator that extends EN16931 validation
|
|
4
|
+
* Implements additional German CIUS (Core Invoice Usage Specification) rules
|
|
5
|
+
*/
|
|
6
|
+
export class XRechnungValidator extends EN16931UBLValidator {
|
|
7
|
+
/**
|
|
8
|
+
* Validates XRechnung-specific structure requirements
|
|
9
|
+
*/
|
|
10
|
+
validateStructure() {
|
|
11
|
+
// First validate EN16931 structure
|
|
12
|
+
let valid = super.validateStructure();
|
|
13
|
+
// XRechnung-specific: Check for proper customization ID
|
|
14
|
+
const customizationID = this.getText('//cbc:CustomizationID');
|
|
15
|
+
if (!customizationID || !customizationID.includes('xrechnung')) {
|
|
16
|
+
this.addError('XRECH-STRUCT-1', 'XRechnung customization ID is missing or invalid', '//cbc:CustomizationID');
|
|
17
|
+
valid = false;
|
|
18
|
+
}
|
|
19
|
+
return valid;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validates XRechnung-specific business rules
|
|
23
|
+
*/
|
|
24
|
+
validateBusinessRules() {
|
|
25
|
+
// First validate EN16931 business rules
|
|
26
|
+
let valid = super.validateBusinessRules();
|
|
27
|
+
// BR-DE-1: Payment terms (BT-20) or Payment due date (BT-9) shall be provided.
|
|
28
|
+
if (!this.exists('//cbc:PaymentDueDate') && !this.exists('//cac:PaymentTerms/cbc:Note')) {
|
|
29
|
+
this.addError('BR-DE-1', 'Payment terms or Payment due date shall be provided', '//cac:PaymentTerms');
|
|
30
|
+
valid = false;
|
|
31
|
+
}
|
|
32
|
+
// BR-DE-2: The element "Buyer reference" (BT-10) shall be provided.
|
|
33
|
+
if (!this.exists('//cbc:BuyerReference')) {
|
|
34
|
+
this.addError('BR-DE-2', 'Buyer reference is required in XRechnung', '//cbc:BuyerReference');
|
|
35
|
+
valid = false;
|
|
36
|
+
}
|
|
37
|
+
// BR-DE-5: In Germany, the element "Seller VAT identifier" (BT-31) shall be provided.
|
|
38
|
+
const sellerCountry = this.getText('//cac:AccountingSupplierParty//cac:PostalAddress//cac:Country/cbc:IdentificationCode');
|
|
39
|
+
if (sellerCountry === 'DE' && !this.exists('//cac:AccountingSupplierParty//cac:PartyTaxScheme[cac:TaxScheme/cbc:ID="VAT"]/cbc:CompanyID')) {
|
|
40
|
+
this.addError('BR-DE-5', 'Seller VAT identifier is required for German sellers', '//cac:AccountingSupplierParty//cac:PartyTaxScheme');
|
|
41
|
+
valid = false;
|
|
42
|
+
}
|
|
43
|
+
// BR-DE-6: In Germany, the element "Buyer VAT identifier" (BT-48) shall be provided.
|
|
44
|
+
const buyerCountry = this.getText('//cac:AccountingCustomerParty//cac:PostalAddress//cac:Country/cbc:IdentificationCode');
|
|
45
|
+
if (buyerCountry === 'DE' && !this.exists('//cac:AccountingCustomerParty//cac:PartyTaxScheme[cac:TaxScheme/cbc:ID="VAT"]/cbc:CompanyID')) {
|
|
46
|
+
this.addError('BR-DE-6', 'Buyer VAT identifier is required for German buyers', '//cac:AccountingCustomerParty//cac:PartyTaxScheme');
|
|
47
|
+
valid = false;
|
|
48
|
+
}
|
|
49
|
+
// BR-DE-7: The element "Seller city" (BT-37) shall be provided.
|
|
50
|
+
if (!this.exists('//cac:AccountingSupplierParty//cac:PostalAddress/cbc:CityName')) {
|
|
51
|
+
this.addError('BR-DE-7', 'Seller city is required', '//cac:AccountingSupplierParty//cac:PostalAddress');
|
|
52
|
+
valid = false;
|
|
53
|
+
}
|
|
54
|
+
// BR-DE-8: The element "Seller post code" (BT-38) shall be provided.
|
|
55
|
+
if (!this.exists('//cac:AccountingSupplierParty//cac:PostalAddress/cbc:PostalZone')) {
|
|
56
|
+
this.addError('BR-DE-8', 'Seller post code is required', '//cac:AccountingSupplierParty//cac:PostalAddress');
|
|
57
|
+
valid = false;
|
|
58
|
+
}
|
|
59
|
+
// BR-DE-9: The element "Buyer city" (BT-52) shall be provided.
|
|
60
|
+
if (!this.exists('//cac:AccountingCustomerParty//cac:PostalAddress/cbc:CityName')) {
|
|
61
|
+
this.addError('BR-DE-9', 'Buyer city is required', '//cac:AccountingCustomerParty//cac:PostalAddress');
|
|
62
|
+
valid = false;
|
|
63
|
+
}
|
|
64
|
+
// BR-DE-10: The element "Buyer post code" (BT-53) shall be provided.
|
|
65
|
+
if (!this.exists('//cac:AccountingCustomerParty//cac:PostalAddress/cbc:PostalZone')) {
|
|
66
|
+
this.addError('BR-DE-10', 'Buyer post code is required', '//cac:AccountingCustomerParty//cac:PostalAddress');
|
|
67
|
+
valid = false;
|
|
68
|
+
}
|
|
69
|
+
// BR-DE-11: The element "Seller contact telephone number" (BT-42) shall be provided.
|
|
70
|
+
if (!this.exists('//cac:AccountingSupplierParty//cac:Contact/cbc:Telephone')) {
|
|
71
|
+
this.addError('BR-DE-11', 'Seller contact telephone number is required', '//cac:AccountingSupplierParty//cac:Contact');
|
|
72
|
+
valid = false;
|
|
73
|
+
}
|
|
74
|
+
// BR-DE-12: The element "Seller contact email address" (BT-43) shall be provided.
|
|
75
|
+
if (!this.exists('//cac:AccountingSupplierParty//cac:Contact/cbc:ElectronicMail')) {
|
|
76
|
+
this.addError('BR-DE-12', 'Seller contact email address is required', '//cac:AccountingSupplierParty//cac:Contact');
|
|
77
|
+
valid = false;
|
|
78
|
+
}
|
|
79
|
+
// BR-DE-13: The element "Buyer electronic address" (BT-49) shall be provided.
|
|
80
|
+
if (!this.exists('//cac:AccountingCustomerParty//cac:Party/cbc:EndpointID')) {
|
|
81
|
+
this.addError('BR-DE-13', 'Buyer electronic address (EndpointID) is required', '//cac:AccountingCustomerParty//cac:Party');
|
|
82
|
+
valid = false;
|
|
83
|
+
}
|
|
84
|
+
// BR-DE-14: The element "Payment means type code" (BT-81) shall be provided.
|
|
85
|
+
if (!this.exists('//cac:PaymentMeans/cbc:PaymentMeansCode')) {
|
|
86
|
+
this.addError('BR-DE-14', 'Payment means type code is required', '//cac:PaymentMeans');
|
|
87
|
+
valid = false;
|
|
88
|
+
}
|
|
89
|
+
// BR-DE-15: The element "Invoice line identifier" (BT-126) shall be provided.
|
|
90
|
+
const invoiceLines = this.select('//cac:InvoiceLine | //cac:CreditNoteLine', this.doc);
|
|
91
|
+
for (let i = 0; i < invoiceLines.length; i++) {
|
|
92
|
+
const line = invoiceLines[i];
|
|
93
|
+
if (!this.exists('./cbc:ID', line)) {
|
|
94
|
+
this.addError('BR-DE-15', `Invoice line ${i + 1} is missing identifier`, `//cac:InvoiceLine[${i + 1}]`);
|
|
95
|
+
valid = false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// German VAT ID format validation
|
|
99
|
+
const supplierVatId = this.getText('//cac:AccountingSupplierParty//cbc:CompanyID[../cac:TaxScheme/cbc:ID="VAT"]');
|
|
100
|
+
if (supplierVatId && supplierVatId.startsWith('DE') && !/^DE[0-9]{9}$/.test(supplierVatId)) {
|
|
101
|
+
this.addError('BR-DE-VAT', 'German VAT ID format is invalid (must be DE followed by 9 digits)', '//cac:AccountingSupplierParty//cbc:CompanyID');
|
|
102
|
+
valid = false;
|
|
103
|
+
}
|
|
104
|
+
return valid;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieHJlY2hudW5nLnZhbGlkYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2Zvcm1hdHMvdWJsL3hyZWNobnVuZy52YWxpZGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFakU7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLGtCQUFtQixTQUFRLG1CQUFtQjtJQUN6RDs7T0FFRztJQUNPLGlCQUFpQjtRQUN6QixtQ0FBbUM7UUFDbkMsSUFBSSxLQUFLLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFFdEMsd0RBQXdEO1FBQ3hELE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsdUJBQXVCLENBQUMsQ0FBQztRQUM5RCxJQUFJLENBQUMsZUFBZSxJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1lBQy9ELElBQUksQ0FBQyxRQUFRLENBQ1gsZ0JBQWdCLEVBQ2hCLGtEQUFrRCxFQUNsRCx1QkFBdUIsQ0FDeEIsQ0FBQztZQUNGLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDaEIsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ08scUJBQXFCO1FBQzdCLHdDQUF3QztRQUN4QyxJQUFJLEtBQUssR0FBRyxLQUFLLENBQUMscUJBQXFCLEVBQUUsQ0FBQztRQUUxQywrRUFBK0U7UUFDL0UsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsNkJBQTZCLENBQUMsRUFBRSxDQUFDO1lBQ3hGLElBQUksQ0FBQyxRQUFRLENBQ1gsU0FBUyxFQUNULHFEQUFxRCxFQUNyRCxvQkFBb0IsQ0FDckIsQ0FBQztZQUNGLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDaEIsQ0FBQztR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
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { BaseValidator } from './base.validator.js';
|
|
2
|
+
import { ValidationLevel } from '../interfaces.js';
|
|
3
|
+
import type { ValidationResult } from '../interfaces.js';
|
|
4
|
+
/**
|
|
5
|
+
* Validator for UBL (Universal Business Language) invoice format
|
|
6
|
+
* Implements validation rules according to EN16931 and UBL 2.1 specification
|
|
7
|
+
*/
|
|
8
|
+
export declare class UBLValidator extends BaseValidator {
|
|
9
|
+
private static NS_INVOICE;
|
|
10
|
+
private static NS_CAC;
|
|
11
|
+
private static NS_CBC;
|
|
12
|
+
private xmlDoc;
|
|
13
|
+
private customizationId;
|
|
14
|
+
constructor(xml: string);
|
|
15
|
+
/**
|
|
16
|
+
* Validates the UBL invoice against the specified level
|
|
17
|
+
* @param level Validation level
|
|
18
|
+
* @returns Validation result
|
|
19
|
+
*/
|
|
20
|
+
validate(level?: ValidationLevel): ValidationResult;
|
|
21
|
+
/**
|
|
22
|
+
* Validates XML against schema
|
|
23
|
+
* @returns True if schema validation passed
|
|
24
|
+
*/
|
|
25
|
+
protected validateSchema(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Validates structure of the XML document
|
|
28
|
+
* @returns True if structure validation passed
|
|
29
|
+
*/
|
|
30
|
+
private validateStructure;
|
|
31
|
+
/**
|
|
32
|
+
* Validates business rules
|
|
33
|
+
* @returns True if business rule validation passed
|
|
34
|
+
*/
|
|
35
|
+
protected validateBusinessRules(): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Gets the root node name (Invoice or CreditNote)
|
|
38
|
+
* @returns Root node name
|
|
39
|
+
*/
|
|
40
|
+
private getRootNodeName;
|
|
41
|
+
/**
|
|
42
|
+
* Detects UBL customization ID from the XML
|
|
43
|
+
*/
|
|
44
|
+
private detectCustomizationId;
|
|
45
|
+
/**
|
|
46
|
+
* Checks if invoice is an XRechnung
|
|
47
|
+
* @returns True if XRechnung customization ID is present
|
|
48
|
+
*/
|
|
49
|
+
private isXRechnung;
|
|
50
|
+
/**
|
|
51
|
+
* Validates amount calculations in the invoice
|
|
52
|
+
* @returns True if amount validation passed
|
|
53
|
+
*/
|
|
54
|
+
private validateAmounts;
|
|
55
|
+
/**
|
|
56
|
+
* Validates mutually exclusive fields
|
|
57
|
+
* @returns True if validation passed
|
|
58
|
+
*/
|
|
59
|
+
private validateMutuallyExclusiveFields;
|
|
60
|
+
/**
|
|
61
|
+
* Validates seller VAT identifier requirements
|
|
62
|
+
* @returns True if validation passed
|
|
63
|
+
*/
|
|
64
|
+
private validateSellerVatIdentifier;
|
|
65
|
+
/**
|
|
66
|
+
* Validates XRechnung specific rules
|
|
67
|
+
* @returns True if validation passed
|
|
68
|
+
*/
|
|
69
|
+
private validateXRechnungRules;
|
|
70
|
+
/**
|
|
71
|
+
* Helper method to check if a node exists
|
|
72
|
+
* @param xpathExpression XPath to check
|
|
73
|
+
* @returns True if node exists
|
|
74
|
+
*/
|
|
75
|
+
private exists;
|
|
76
|
+
/**
|
|
77
|
+
* Helper method to get a number value from XPath
|
|
78
|
+
* @param xpathExpression XPath to get number from
|
|
79
|
+
* @returns Number value or NaN if not found
|
|
80
|
+
*/
|
|
81
|
+
private getNumberValue;
|
|
82
|
+
}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { BaseValidator } from './base.validator.js';
|
|
2
|
+
import { ValidationLevel } from '../interfaces.js';
|
|
3
|
+
import * as xpath from 'xpath';
|
|
4
|
+
import { DOMParser } from 'xmldom';
|
|
5
|
+
/**
|
|
6
|
+
* Validator for UBL (Universal Business Language) invoice format
|
|
7
|
+
* Implements validation rules according to EN16931 and UBL 2.1 specification
|
|
8
|
+
*/
|
|
9
|
+
export class UBLValidator extends BaseValidator {
|
|
10
|
+
// XML namespaces for UBL
|
|
11
|
+
static { this.NS_INVOICE = 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2'; }
|
|
12
|
+
static { this.NS_CAC = 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2'; }
|
|
13
|
+
static { this.NS_CBC = 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2'; }
|
|
14
|
+
constructor(xml) {
|
|
15
|
+
super(xml);
|
|
16
|
+
// XML document for processing
|
|
17
|
+
this.xmlDoc = null;
|
|
18
|
+
// UBL profile or customization ID
|
|
19
|
+
this.customizationId = '';
|
|
20
|
+
try {
|
|
21
|
+
// Parse XML document
|
|
22
|
+
this.xmlDoc = new DOMParser().parseFromString(xml, 'application/xml');
|
|
23
|
+
// Determine UBL customization ID (e.g. EN16931, XRechnung)
|
|
24
|
+
this.detectCustomizationId();
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
this.addError('UBL-PARSE', `Failed to parse XML: ${error}`, '/');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validates the UBL invoice against the specified level
|
|
32
|
+
* @param level Validation level
|
|
33
|
+
* @returns Validation result
|
|
34
|
+
*/
|
|
35
|
+
validate(level = ValidationLevel.SYNTAX) {
|
|
36
|
+
// Reset errors
|
|
37
|
+
this.errors = [];
|
|
38
|
+
// Check if document was parsed successfully
|
|
39
|
+
if (!this.xmlDoc) {
|
|
40
|
+
return {
|
|
41
|
+
valid: false,
|
|
42
|
+
errors: this.errors,
|
|
43
|
+
level: level
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// Perform validation based on level
|
|
47
|
+
let valid = true;
|
|
48
|
+
if (level === ValidationLevel.SYNTAX) {
|
|
49
|
+
valid = this.validateSchema();
|
|
50
|
+
}
|
|
51
|
+
else if (level === ValidationLevel.SEMANTIC) {
|
|
52
|
+
valid = this.validateSchema() && this.validateStructure();
|
|
53
|
+
}
|
|
54
|
+
else if (level === ValidationLevel.BUSINESS) {
|
|
55
|
+
valid = this.validateSchema() &&
|
|
56
|
+
this.validateStructure() &&
|
|
57
|
+
this.validateBusinessRules();
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
valid,
|
|
61
|
+
errors: this.errors,
|
|
62
|
+
level
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Validates XML against schema
|
|
67
|
+
* @returns True if schema validation passed
|
|
68
|
+
*/
|
|
69
|
+
validateSchema() {
|
|
70
|
+
// Basic schema validation (simplified for now)
|
|
71
|
+
if (!this.xmlDoc)
|
|
72
|
+
return false;
|
|
73
|
+
// Check for root element
|
|
74
|
+
const root = this.xmlDoc.documentElement;
|
|
75
|
+
if (!root || (root.nodeName !== 'Invoice' && root.nodeName !== 'CreditNote')) {
|
|
76
|
+
this.addError('UBL-SCHEMA-1', 'Root element must be Invoice or CreditNote', '/');
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
// Check for required namespaces
|
|
80
|
+
if (!root.lookupNamespaceURI('cac') || !root.lookupNamespaceURI('cbc')) {
|
|
81
|
+
this.addError('UBL-SCHEMA-2', 'Required namespaces cac and cbc must be declared', '/');
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validates structure of the XML document
|
|
88
|
+
* @returns True if structure validation passed
|
|
89
|
+
*/
|
|
90
|
+
validateStructure() {
|
|
91
|
+
if (!this.xmlDoc)
|
|
92
|
+
return false;
|
|
93
|
+
let valid = true;
|
|
94
|
+
// Check for required main sections
|
|
95
|
+
const sections = [
|
|
96
|
+
'cbc:ID',
|
|
97
|
+
'cbc:IssueDate',
|
|
98
|
+
'cac:AccountingSupplierParty',
|
|
99
|
+
'cac:AccountingCustomerParty',
|
|
100
|
+
'cac:LegalMonetaryTotal'
|
|
101
|
+
];
|
|
102
|
+
for (const section of sections) {
|
|
103
|
+
if (!this.exists(`/${this.getRootNodeName()}/${section}`)) {
|
|
104
|
+
this.addError('UBL-STRUCT-1', `Required section ${section} is missing`, `/${this.getRootNodeName()}`);
|
|
105
|
+
valid = false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Check for TaxTotal section
|
|
109
|
+
if (this.exists(`/${this.getRootNodeName()}/cac:TaxTotal`)) {
|
|
110
|
+
const taxSubsections = [
|
|
111
|
+
'cbc:TaxAmount',
|
|
112
|
+
'cac:TaxSubtotal'
|
|
113
|
+
];
|
|
114
|
+
for (const subsection of taxSubsections) {
|
|
115
|
+
if (!this.exists(`/${this.getRootNodeName()}/cac:TaxTotal/${subsection}`)) {
|
|
116
|
+
this.addError('UBL-STRUCT-2', `Required subsection ${subsection} is missing`, `/${this.getRootNodeName()}/cac:TaxTotal`);
|
|
117
|
+
valid = false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return valid;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Validates business rules
|
|
125
|
+
* @returns True if business rule validation passed
|
|
126
|
+
*/
|
|
127
|
+
validateBusinessRules() {
|
|
128
|
+
if (!this.xmlDoc)
|
|
129
|
+
return false;
|
|
130
|
+
let valid = true;
|
|
131
|
+
// BR-16: Amount due for payment (BT-115) = Invoice total amount with VAT (BT-112) - Paid amount (BT-113)
|
|
132
|
+
valid = this.validateAmounts() && valid;
|
|
133
|
+
// BR-CO-3: Value added tax point date (BT-7) and Value added tax point date code (BT-8) are mutually exclusive
|
|
134
|
+
valid = this.validateMutuallyExclusiveFields() && valid;
|
|
135
|
+
// BR-S-1: An Invoice that contains a line where the VAT category code is "Standard rated"
|
|
136
|
+
// shall contain the Seller VAT Identifier or the Seller tax representative VAT identifier
|
|
137
|
+
valid = this.validateSellerVatIdentifier() && valid;
|
|
138
|
+
// XRechnung specific rules when customization ID matches
|
|
139
|
+
if (this.isXRechnung()) {
|
|
140
|
+
valid = this.validateXRechnungRules() && valid;
|
|
141
|
+
}
|
|
142
|
+
return valid;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Gets the root node name (Invoice or CreditNote)
|
|
146
|
+
* @returns Root node name
|
|
147
|
+
*/
|
|
148
|
+
getRootNodeName() {
|
|
149
|
+
if (!this.xmlDoc || !this.xmlDoc.documentElement)
|
|
150
|
+
return 'Invoice';
|
|
151
|
+
return this.xmlDoc.documentElement.nodeName;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Detects UBL customization ID from the XML
|
|
155
|
+
*/
|
|
156
|
+
detectCustomizationId() {
|
|
157
|
+
if (!this.xmlDoc)
|
|
158
|
+
return;
|
|
159
|
+
// Look for customization ID
|
|
160
|
+
const customizationNode = xpath.select1(`string(/${this.getRootNodeName()}/cbc:CustomizationID)`, this.xmlDoc);
|
|
161
|
+
if (customizationNode) {
|
|
162
|
+
this.customizationId = customizationNode.toString();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Checks if invoice is an XRechnung
|
|
167
|
+
* @returns True if XRechnung customization ID is present
|
|
168
|
+
*/
|
|
169
|
+
isXRechnung() {
|
|
170
|
+
return this.customizationId.includes('xrechnung') ||
|
|
171
|
+
this.customizationId.includes('XRechnung');
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Validates amount calculations in the invoice
|
|
175
|
+
* @returns True if amount validation passed
|
|
176
|
+
*/
|
|
177
|
+
validateAmounts() {
|
|
178
|
+
if (!this.xmlDoc)
|
|
179
|
+
return false;
|
|
180
|
+
try {
|
|
181
|
+
// Extract amounts
|
|
182
|
+
const totalAmount = this.getNumberValue(`/${this.getRootNodeName()}/cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount`);
|
|
183
|
+
const paidAmount = this.getNumberValue(`/${this.getRootNodeName()}/cac:LegalMonetaryTotal/cbc:PrepaidAmount`) || 0;
|
|
184
|
+
const dueAmount = this.getNumberValue(`/${this.getRootNodeName()}/cac:LegalMonetaryTotal/cbc:PayableAmount`);
|
|
185
|
+
// Calculate expected due amount
|
|
186
|
+
const expectedDueAmount = totalAmount - paidAmount;
|
|
187
|
+
// Compare with a small tolerance for rounding errors
|
|
188
|
+
if (Math.abs(dueAmount - expectedDueAmount) > 0.01) {
|
|
189
|
+
this.addError('BR-16', `Amount due for payment (${dueAmount}) must equal Invoice total amount with VAT (${totalAmount}) - Paid amount (${paidAmount})`, `/${this.getRootNodeName()}/cac:LegalMonetaryTotal`);
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
this.addError('UBL-AMOUNT', `Error validating amounts: ${error}`, '/');
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Validates mutually exclusive fields
|
|
201
|
+
* @returns True if validation passed
|
|
202
|
+
*/
|
|
203
|
+
validateMutuallyExclusiveFields() {
|
|
204
|
+
if (!this.xmlDoc)
|
|
205
|
+
return false;
|
|
206
|
+
try {
|
|
207
|
+
// Check for VAT point date and code (BR-CO-3)
|
|
208
|
+
const vatPointDate = this.exists(`/${this.getRootNodeName()}/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:TaxPointDate`);
|
|
209
|
+
const vatPointDateCode = this.exists(`/${this.getRootNodeName()}/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:TaxExemptionReasonCode`);
|
|
210
|
+
if (vatPointDate && vatPointDateCode) {
|
|
211
|
+
this.addError('BR-CO-3', 'Value added tax point date and Value added tax point date code are mutually exclusive', `/${this.getRootNodeName()}/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory`);
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
this.addError('UBL-MUTUAL', `Error validating mutually exclusive fields: ${error}`, '/');
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Validates seller VAT identifier requirements
|
|
223
|
+
* @returns True if validation passed
|
|
224
|
+
*/
|
|
225
|
+
validateSellerVatIdentifier() {
|
|
226
|
+
if (!this.xmlDoc)
|
|
227
|
+
return false;
|
|
228
|
+
try {
|
|
229
|
+
// Check if there are any standard rated line items
|
|
230
|
+
const standardRatedItems = this.exists(`/${this.getRootNodeName()}/cac:InvoiceLine/cac:Item/cac:ClassifiedTaxCategory/cbc:ID[text()="S"]`);
|
|
231
|
+
if (standardRatedItems) {
|
|
232
|
+
// Check for seller VAT identifier
|
|
233
|
+
const sellerVatId = this.exists(`/${this.getRootNodeName()}/cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID`);
|
|
234
|
+
const sellerTaxRepId = this.exists(`/${this.getRootNodeName()}/cac:TaxRepresentativeParty/cac:PartyTaxScheme/cbc:CompanyID`);
|
|
235
|
+
if (!sellerVatId && !sellerTaxRepId) {
|
|
236
|
+
this.addError('BR-S-1', 'An Invoice with standard rated items must contain the Seller VAT Identifier or Tax representative VAT identifier', `/${this.getRootNodeName()}/cac:AccountingSupplierParty/cac:Party`);
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
this.addError('UBL-VAT', `Error validating seller VAT identifier: ${error}`, '/');
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Validates XRechnung specific rules
|
|
249
|
+
* @returns True if validation passed
|
|
250
|
+
*/
|
|
251
|
+
validateXRechnungRules() {
|
|
252
|
+
if (!this.xmlDoc)
|
|
253
|
+
return false;
|
|
254
|
+
let valid = true;
|
|
255
|
+
try {
|
|
256
|
+
// BR-DE-1: Buyer reference must be present for German VAT compliance
|
|
257
|
+
if (!this.exists(`/${this.getRootNodeName()}/cbc:BuyerReference`)) {
|
|
258
|
+
this.addError('BR-DE-1', 'BuyerReference is mandatory for XRechnung', `/${this.getRootNodeName()}`);
|
|
259
|
+
valid = false;
|
|
260
|
+
}
|
|
261
|
+
// BR-DE-15: Contact information must be present
|
|
262
|
+
if (!this.exists(`/${this.getRootNodeName()}/cac:AccountingSupplierParty/cac:Party/cac:Contact`)) {
|
|
263
|
+
this.addError('BR-DE-15', 'Supplier contact information is mandatory for XRechnung', `/${this.getRootNodeName()}/cac:AccountingSupplierParty/cac:Party`);
|
|
264
|
+
valid = false;
|
|
265
|
+
}
|
|
266
|
+
// BR-DE-16: Electronic address identifier scheme (e.g. PEPPOL) must be present
|
|
267
|
+
if (!this.exists(`/${this.getRootNodeName()}/cac:AccountingSupplierParty/cac:Party/cbc:EndpointID`) ||
|
|
268
|
+
!this.exists(`/${this.getRootNodeName()}/cac:AccountingSupplierParty/cac:Party/cbc:EndpointID/@schemeID`)) {
|
|
269
|
+
this.addError('BR-DE-16', 'Supplier electronic address with scheme identifier is mandatory for XRechnung', `/${this.getRootNodeName()}/cac:AccountingSupplierParty/cac:Party`);
|
|
270
|
+
valid = false;
|
|
271
|
+
}
|
|
272
|
+
return valid;
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
this.addError('UBL-XRECHNUNG', `Error validating XRechnung rules: ${error}`, '/');
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Helper method to check if a node exists
|
|
281
|
+
* @param xpathExpression XPath to check
|
|
282
|
+
* @returns True if node exists
|
|
283
|
+
*/
|
|
284
|
+
exists(xpathExpression) {
|
|
285
|
+
if (!this.xmlDoc)
|
|
286
|
+
return false;
|
|
287
|
+
const nodes = xpath.select(xpathExpression, this.xmlDoc);
|
|
288
|
+
// Handle different return types from xpath.select()
|
|
289
|
+
if (Array.isArray(nodes)) {
|
|
290
|
+
return nodes.length > 0;
|
|
291
|
+
}
|
|
292
|
+
return nodes ? true : false;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Helper method to get a number value from XPath
|
|
296
|
+
* @param xpathExpression XPath to get number from
|
|
297
|
+
* @returns Number value or NaN if not found
|
|
298
|
+
*/
|
|
299
|
+
getNumberValue(xpathExpression) {
|
|
300
|
+
if (!this.xmlDoc)
|
|
301
|
+
return NaN;
|
|
302
|
+
const node = xpath.select1(`string(${xpathExpression})`, this.xmlDoc);
|
|
303
|
+
return node ? parseFloat(node.toString()) : NaN;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidWJsLnZhbGlkYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2Zvcm1hdHMvdWJsLnZhbGlkYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRW5ELE9BQU8sS0FBSyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQy9CLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFbkM7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLFlBQWEsU0FBUSxhQUFhO0lBQzdDLHlCQUF5QjthQUNWLGVBQVUsR0FBRyx3REFBd0QsQUFBM0QsQ0FBNEQ7YUFDdEUsV0FBTSxHQUFHLDBFQUEwRSxBQUE3RSxDQUE4RTthQUNwRixXQUFNLEdBQUcsc0VBQXNFLEFBQXpFLENBQTBFO0lBUS9GLFlBQVksR0FBVztRQUNyQixLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFQYiw4QkFBOEI7UUFDdEIsV0FBTSxHQUFvQixJQUFJLENBQUM7UUFFdkMsa0NBQWtDO1FBQzFCLG9CQUFlLEdBQVcsRUFBRSxDQUFDO1FBS25DLElBQUksQ0FBQztZQUNILHFCQUFxQjtZQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksU0FBUyxFQUFFLENBQUMsZUFBZSxDQUFDLEdBQUcsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO1lBRXRFLDJEQUEyRDtZQUMzRCxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztRQUMvQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxFQUFFLHdCQUF3QixLQUFLLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNuRSxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxRQUFRLENBQUMsUUFBeUIsZUFBZSxD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
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { InvoiceFormat } from '../../interfaces/common.js';
|
|
2
|
+
/**
|
|
3
|
+
* Utility class for detecting invoice formats
|
|
4
|
+
*/
|
|
5
|
+
export declare class FormatDetector {
|
|
6
|
+
/**
|
|
7
|
+
* Detects the format of an XML document
|
|
8
|
+
* @param xml XML content to analyze
|
|
9
|
+
* @returns Detected invoice format
|
|
10
|
+
*/
|
|
11
|
+
static detectFormat(xml: string): InvoiceFormat;
|
|
12
|
+
/**
|
|
13
|
+
* Performs a quick format check based on string content
|
|
14
|
+
* This is faster than full XML parsing for obvious cases
|
|
15
|
+
* @param xml XML string
|
|
16
|
+
* @returns Detected format or UNKNOWN if more analysis is needed
|
|
17
|
+
*/
|
|
18
|
+
private static quickFormatCheck;
|
|
19
|
+
/**
|
|
20
|
+
* Checks if the document is a UBL format
|
|
21
|
+
* @param root Root element
|
|
22
|
+
* @returns True if it's a UBL format
|
|
23
|
+
*/
|
|
24
|
+
private static isUBLFormat;
|
|
25
|
+
/**
|
|
26
|
+
* Checks if the document is an XRechnung format
|
|
27
|
+
* @param doc XML document
|
|
28
|
+
* @returns True if it's an XRechnung format
|
|
29
|
+
*/
|
|
30
|
+
private static isXRechnungFormat;
|
|
31
|
+
/**
|
|
32
|
+
* Checks if the document is a CII format (Factur-X/ZUGFeRD v2+)
|
|
33
|
+
* @param root Root element
|
|
34
|
+
* @returns True if it's a CII format
|
|
35
|
+
*/
|
|
36
|
+
private static isCIIFormat;
|
|
37
|
+
/**
|
|
38
|
+
* Checks if the document is a ZUGFeRD v1 format
|
|
39
|
+
* @param root Root element
|
|
40
|
+
* @returns True if it's a ZUGFeRD v1 format
|
|
41
|
+
*/
|
|
42
|
+
private static isZUGFeRDV1Format;
|
|
43
|
+
/**
|
|
44
|
+
* Checks if the document is a FatturaPA format
|
|
45
|
+
* @param root Root element
|
|
46
|
+
* @returns True if it's a FatturaPA format
|
|
47
|
+
*/
|
|
48
|
+
private static isFatturaPAFormat;
|
|
49
|
+
/**
|
|
50
|
+
* Detects the specific CII format (Factur-X vs ZUGFeRD)
|
|
51
|
+
* @param doc XML document
|
|
52
|
+
* @param xml Original XML string for fallback checks
|
|
53
|
+
* @returns Detected format
|
|
54
|
+
*/
|
|
55
|
+
private static detectCIIFormat;
|
|
56
|
+
/**
|
|
57
|
+
* Fallback method to detect CII format from string content
|
|
58
|
+
* @param xml XML string
|
|
59
|
+
* @returns Detected format
|
|
60
|
+
*/
|
|
61
|
+
private static detectCIIFormatFromString;
|
|
62
|
+
}
|