@fin.cx/einvoice 5.0.3 → 5.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/einvoice.d.ts +4 -8
- package/dist_ts/einvoice.js +46 -7
- package/dist_ts/formats/converters/xml-to-einvoice.converter.d.ts +21 -0
- package/dist_ts/formats/converters/xml-to-einvoice.converter.js +127 -0
- package/dist_ts/formats/semantic/bt-bg.model.d.ts +445 -0
- package/dist_ts/formats/semantic/bt-bg.model.js +12 -0
- package/dist_ts/formats/semantic/semantic.adapter.d.ts +87 -0
- package/dist_ts/formats/semantic/semantic.adapter.js +538 -0
- package/dist_ts/formats/semantic/semantic.validator.d.ts +48 -0
- package/dist_ts/formats/semantic/semantic.validator.js +596 -0
- package/dist_ts/formats/utils/currency.calculator.decimal.d.ts +98 -0
- package/dist_ts/formats/utils/currency.calculator.decimal.js +212 -0
- package/dist_ts/formats/utils/currency.utils.d.ts +99 -0
- package/dist_ts/formats/utils/currency.utils.js +250 -0
- package/dist_ts/formats/utils/decimal.d.ts +151 -0
- package/dist_ts/formats/utils/decimal.js +435 -0
- package/dist_ts/formats/validation/codelist.validator.d.ts +49 -0
- package/dist_ts/formats/validation/codelist.validator.js +188 -0
- package/dist_ts/formats/validation/conformance.harness.d.ts +99 -0
- package/dist_ts/formats/validation/conformance.harness.js +471 -0
- package/dist_ts/formats/validation/en16931.business-rules.validator.d.ts +58 -0
- package/dist_ts/formats/validation/en16931.business-rules.validator.js +459 -0
- package/dist_ts/formats/validation/facturx.validator.d.ts +75 -0
- package/dist_ts/formats/validation/facturx.validator.js +522 -0
- package/dist_ts/formats/validation/integrated.validator.d.ts +82 -0
- package/dist_ts/formats/validation/integrated.validator.js +311 -0
- package/dist_ts/formats/validation/peppol.validator.d.ts +77 -0
- package/dist_ts/formats/validation/peppol.validator.js +529 -0
- package/dist_ts/formats/validation/schematron.downloader.d.ts +71 -0
- package/dist_ts/formats/validation/schematron.downloader.js +254 -0
- package/dist_ts/formats/validation/schematron.integration.d.ts +60 -0
- package/dist_ts/formats/validation/schematron.integration.js +230 -0
- package/dist_ts/formats/validation/schematron.validator.d.ts +79 -0
- package/dist_ts/formats/validation/schematron.validator.js +288 -0
- package/dist_ts/formats/validation/schematron.worker.d.ts +50 -0
- package/dist_ts/formats/validation/schematron.worker.js +185 -0
- package/dist_ts/formats/validation/validation.types.d.ts +163 -0
- package/dist_ts/formats/validation/validation.types.js +181 -0
- package/dist_ts/formats/validation/vat-categories.validator.d.ts +87 -0
- package/dist_ts/formats/validation/vat-categories.validator.js +497 -0
- package/dist_ts/formats/validation/xrechnung.validator.d.ts +92 -0
- package/dist_ts/formats/validation/xrechnung.validator.js +417 -0
- package/dist_ts/interfaces/common.d.ts +1 -0
- package/dist_ts/interfaces/en16931-metadata.d.ts +83 -0
- package/dist_ts/interfaces/en16931-metadata.js +6 -0
- package/dist_ts/plugins.d.ts +3 -1
- package/dist_ts/plugins.js +7 -2
- package/dist_ts_install/download-schematron.d.ts +6 -0
- package/dist_ts_install/download-schematron.js +62 -0
- package/dist_ts_install/download-test-samples.d.ts +19 -0
- package/dist_ts_install/download-test-samples.js +169 -0
- package/dist_ts_install/download-xrechnung-rules.d.ts +7 -0
- package/dist_ts_install/download-xrechnung-rules.js +146 -0
- package/dist_ts_install/index.d.ts +8 -0
- package/dist_ts_install/index.js +246 -0
- package/npmextra.json +1 -1
- package/package.json +12 -6
- package/readme.md +255 -810
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/einvoice.ts +63 -14
- package/ts/formats/converters/xml-to-einvoice.converter.ts +142 -0
- package/ts/formats/semantic/bt-bg.model.ts +524 -0
- package/ts/formats/semantic/semantic.adapter.ts +600 -0
- package/ts/formats/semantic/semantic.validator.ts +654 -0
- package/ts/formats/utils/currency.calculator.decimal.ts +323 -0
- package/ts/formats/utils/currency.utils.ts +299 -0
- package/ts/formats/utils/decimal.ts +509 -0
- package/ts/formats/validation/codelist.validator.ts +317 -0
- package/ts/formats/validation/conformance.harness.ts +591 -0
- package/ts/formats/validation/en16931.business-rules.validator.ts +694 -0
- package/ts/formats/validation/facturx.validator.ts +579 -0
- package/ts/formats/validation/integrated.validator.ts +405 -0
- package/ts/formats/validation/peppol.validator.ts +589 -0
- package/ts/formats/validation/schematron.downloader.ts +304 -0
- package/ts/formats/validation/schematron.integration.ts +285 -0
- package/ts/formats/validation/schematron.validator.ts +348 -0
- package/ts/formats/validation/schematron.worker.ts +221 -0
- package/ts/formats/validation/validation.types.ts +274 -0
- package/ts/formats/validation/vat-categories.validator.ts +845 -0
- package/ts/formats/validation/xrechnung.validator.ts +494 -0
- package/ts/interfaces/common.ts +1 -0
- package/ts/interfaces/en16931-metadata.ts +104 -0
- package/ts/plugins.ts +8 -0
- package/ts/tspublish.json +3 -0
- package/dist_ts/classes.decoder.d.ts +0 -40
- package/dist_ts/classes.decoder.js +0 -320
- package/dist_ts/classes.encoder.d.ts +0 -51
- package/dist_ts/classes.encoder.js +0 -293
- package/dist_ts/classes.xinvoice.d.ts +0 -136
- package/dist_ts/classes.xinvoice.js +0 -352
- package/dist_ts/formats/base.decoder.d.ts +0 -19
- package/dist_ts/formats/base.decoder.js +0 -130
- package/dist_ts/formats/base.validator.d.ts +0 -44
- package/dist_ts/formats/base.validator.js +0 -39
- package/dist_ts/formats/decoder.factory.d.ts +0 -15
- package/dist_ts/formats/decoder.factory.js +0 -46
- package/dist_ts/formats/factorx.decoder.d.ts +0 -18
- package/dist_ts/formats/factorx.decoder.js +0 -178
- package/dist_ts/formats/factorx.encoder.d.ts +0 -51
- package/dist_ts/formats/factorx.encoder.js +0 -293
- package/dist_ts/formats/facturx.decoder.d.ts +0 -18
- package/dist_ts/formats/facturx.decoder.js +0 -210
- package/dist_ts/formats/facturx.encoder.d.ts +0 -51
- package/dist_ts/formats/facturx.encoder.js +0 -293
- package/dist_ts/formats/facturx.validator.d.ts +0 -67
- package/dist_ts/formats/facturx.validator.js +0 -266
- package/dist_ts/formats/pdf/robust-pdf.extractor.d.ts +0 -40
- package/dist_ts/formats/pdf/robust-pdf.extractor.js +0 -324
- package/dist_ts/formats/ubl.validator.d.ts +0 -82
- package/dist_ts/formats/ubl.validator.js +0 -306
- package/dist_ts/formats/validator.factory.d.ts +0 -18
- package/dist_ts/formats/validator.factory.js +0 -78
- package/dist_ts/formats/xinvoice.decoder.d.ts +0 -28
- package/dist_ts/formats/xinvoice.decoder.js +0 -332
- package/dist_ts/formats/xinvoice.encoder.d.ts +0 -19
- package/dist_ts/formats/xinvoice.encoder.js +0 -282
package/readme.md
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
# @fin.cx/einvoice
|
|
1
|
+
# @fin.cx/einvoice 🚀
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**The Ultimate TypeScript E-Invoicing Library for Europe** - Now with **100% EN16931 Compliance** ✅
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://www.cen.eu/work/areas/ict/ebusiness/pages/einvoicing.aspx)
|
|
7
|
+
[](https://github.com/fin-cx/einvoice)
|
|
8
|
+
[](./license)
|
|
6
9
|
|
|
7
|
-
- **
|
|
8
|
-
- **PDF handling**: Extract XML from PDF/A-3 invoices and embed XML into PDFs with robust error handling
|
|
9
|
-
- **Validation**: Validate invoices against format-specific rules with detailed error reporting
|
|
10
|
-
- **Conversion**: Convert between different invoice formats while preserving data integrity
|
|
11
|
-
- **TypeScript**: Fully typed API with TypeScript definitions following @tsclass/tsclass standards
|
|
12
|
-
- **Modular architecture**: Extensible design with specialized components
|
|
13
|
-
- **Robust error handling**: Detailed error information and graceful fallbacks
|
|
14
|
-
- **High performance**: Fast validation (~2.2ms) and efficient memory usage (~136KB per validation)
|
|
10
|
+
Transform the chaos of European e-invoicing into pure TypeScript elegance. **@fin.cx/einvoice** is your battle-tested solution for creating, validating, and converting electronic invoices across all major European standards - with blazing fast performance and enterprise-grade reliability.
|
|
15
11
|
|
|
16
|
-
##
|
|
12
|
+
## 🎯 Why @fin.cx/einvoice?
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
- **🏆 100% EN16931 Compliant**: Full implementation of all 162 Business Terms and 32 Business Groups
|
|
15
|
+
- **⚡ Blazing Fast**: Validate invoices in ~2.2ms, convert formats in ~0.6ms
|
|
16
|
+
- **🔐 Enterprise Security**: XXE prevention, resource limits, path traversal protection
|
|
17
|
+
- **🌍 Multi-Standard Support**: ZUGFeRD, Factur-X, XRechnung, PEPPOL BIS 3.0, UBL, and more
|
|
18
|
+
- **💎 Decimal Precision**: Arbitrary precision arithmetic for perfect financial calculations
|
|
19
|
+
- **🔄 Lossless Conversion**: 100% data preservation in round-trip conversions
|
|
20
|
+
- **📦 PDF Magic**: Extract and embed XML in PDF/A-3 documents seamlessly
|
|
21
|
+
- **🛠️ TypeScript First**: Fully typed with IntelliSense support throughout
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
## 🚀 Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
21
26
|
# Using pnpm (recommended)
|
|
22
27
|
pnpm add @fin.cx/einvoice
|
|
23
28
|
|
|
@@ -28,959 +33,399 @@ npm install @fin.cx/einvoice
|
|
|
28
33
|
yarn add @fin.cx/einvoice
|
|
29
34
|
```
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
The `@fin.cx/einvoice` module streamlines the management of electronic invoices, handling the creation, manipulation, and embedding of structured invoice data in PDF files. Below are examples of common use cases.
|
|
34
|
-
|
|
35
|
-
### Quick Start
|
|
36
|
+
### One-Minute Example
|
|
36
37
|
|
|
37
38
|
```typescript
|
|
38
39
|
import { EInvoice } from '@fin.cx/einvoice';
|
|
39
40
|
|
|
40
|
-
// Load from
|
|
41
|
-
const invoice = await EInvoice.fromFile('invoice.xml');
|
|
41
|
+
// Load from any source
|
|
42
|
+
const invoice = await EInvoice.fromFile('invoice.xml'); // From file
|
|
43
|
+
const invoice2 = await EInvoice.fromXml(xmlString); // From XML string
|
|
44
|
+
const invoice3 = await EInvoice.fromPdf(pdfBuffer); // From PDF with embedded XML
|
|
42
45
|
|
|
43
|
-
//
|
|
44
|
-
const
|
|
46
|
+
// Validate with comprehensive EN16931 rules
|
|
47
|
+
const validation = await invoice.validate();
|
|
48
|
+
console.log(`Valid: ${validation.valid}`);
|
|
45
49
|
|
|
46
|
-
//
|
|
47
|
-
const
|
|
50
|
+
// Convert between any formats - losslessly!
|
|
51
|
+
const xrechnung = await invoice.exportXml('xrechnung'); // For German B2G
|
|
52
|
+
const peppol = await invoice.exportXml('ubl'); // For PEPPOL network
|
|
53
|
+
const facturx = await invoice.exportXml('facturx'); // For France/Germany
|
|
54
|
+
const zugferd = await invoice.exportXml('zugferd'); // For German standard
|
|
48
55
|
|
|
49
|
-
//
|
|
50
|
-
const
|
|
51
|
-
const facturxXml = await invoice.exportXml('facturx');
|
|
52
|
-
const ublXml = await invoice.exportXml('ubl');
|
|
56
|
+
// Embed into PDF for hybrid invoices
|
|
57
|
+
const pdfWithXml = await invoice.exportPdf('facturx');
|
|
53
58
|
```
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
## 🏗️ Complete Invoice Creation
|
|
56
61
|
|
|
57
62
|
```typescript
|
|
58
63
|
import { EInvoice } from '@fin.cx/einvoice';
|
|
59
|
-
import { promises as fs } from 'fs';
|
|
60
64
|
|
|
61
|
-
// Create a
|
|
65
|
+
// Create a fully compliant invoice from scratch
|
|
62
66
|
const invoice = new EInvoice();
|
|
63
|
-
|
|
67
|
+
|
|
68
|
+
// Essential metadata
|
|
69
|
+
invoice.accountingDocId = 'INV-2025-001';
|
|
70
|
+
invoice.issueDate = new Date('2025-01-15');
|
|
71
|
+
invoice.accountingDocType = 'invoice';
|
|
72
|
+
invoice.currency = 'EUR';
|
|
73
|
+
invoice.dueInDays = 30;
|
|
74
|
+
|
|
75
|
+
// Seller information
|
|
64
76
|
invoice.from = {
|
|
65
|
-
name: 'Supplier Company',
|
|
66
77
|
type: 'company',
|
|
78
|
+
name: 'Tech Solutions GmbH',
|
|
67
79
|
address: {
|
|
68
|
-
streetName: '
|
|
69
|
-
houseNumber: '
|
|
80
|
+
streetName: 'Innovation Street',
|
|
81
|
+
houseNumber: '42',
|
|
70
82
|
city: 'Berlin',
|
|
71
83
|
postalCode: '10115',
|
|
72
|
-
country: '
|
|
73
|
-
countryCode: 'DE'
|
|
84
|
+
country: 'DE'
|
|
74
85
|
},
|
|
75
86
|
registrationDetails: {
|
|
76
87
|
vatId: 'DE123456789',
|
|
77
|
-
registrationId: 'HRB 123456'
|
|
78
|
-
|
|
88
|
+
registrationId: 'HRB 123456',
|
|
89
|
+
registrationName: 'Tech Solutions GmbH'
|
|
90
|
+
},
|
|
91
|
+
status: 'active'
|
|
79
92
|
};
|
|
93
|
+
|
|
94
|
+
// Buyer information
|
|
80
95
|
invoice.to = {
|
|
81
|
-
name: 'Customer Company',
|
|
82
96
|
type: 'company',
|
|
97
|
+
name: 'Customer Corp SAS',
|
|
83
98
|
address: {
|
|
84
|
-
streetName: '
|
|
85
|
-
houseNumber: '
|
|
99
|
+
streetName: 'Rue de la Paix',
|
|
100
|
+
houseNumber: '10',
|
|
86
101
|
city: 'Paris',
|
|
87
102
|
postalCode: '75001',
|
|
88
|
-
country: '
|
|
89
|
-
countryCode: 'FR'
|
|
103
|
+
country: 'FR'
|
|
90
104
|
},
|
|
91
105
|
registrationDetails: {
|
|
92
|
-
vatId: '
|
|
93
|
-
registrationId: 'RCS
|
|
106
|
+
vatId: 'FR987654321',
|
|
107
|
+
registrationId: 'RCS Paris 987654321'
|
|
94
108
|
}
|
|
95
109
|
};
|
|
96
110
|
|
|
97
|
-
//
|
|
98
|
-
invoice.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
111
|
+
// Payment details - SEPA ready
|
|
112
|
+
invoice.paymentAccount = {
|
|
113
|
+
iban: 'DE89370400440532013000',
|
|
114
|
+
bic: 'COBADEFFXXX',
|
|
115
|
+
accountName: 'Tech Solutions GmbH',
|
|
116
|
+
institutionName: 'Commerzbank'
|
|
104
117
|
};
|
|
105
118
|
|
|
106
|
-
//
|
|
119
|
+
// Line items with automatic calculations
|
|
107
120
|
invoice.items = [
|
|
108
121
|
{
|
|
109
122
|
position: 1,
|
|
110
|
-
name: '
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
name: 'Cloud Infrastructure Services',
|
|
124
|
+
description: 'Monthly cloud hosting and support',
|
|
125
|
+
articleNumber: 'CLOUD-PRO-001',
|
|
126
|
+
unitQuantity: 1,
|
|
127
|
+
unitNetPrice: 2500.00,
|
|
114
128
|
vatPercentage: 19,
|
|
115
|
-
unitType: '
|
|
129
|
+
unitType: 'MON' // Month
|
|
116
130
|
},
|
|
117
131
|
{
|
|
118
132
|
position: 2,
|
|
119
|
-
name: '
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
133
|
+
name: 'Professional Consulting',
|
|
134
|
+
description: 'Architecture review and optimization',
|
|
135
|
+
articleNumber: 'CONSULT-001',
|
|
136
|
+
unitQuantity: 16,
|
|
137
|
+
unitNetPrice: 150.00,
|
|
123
138
|
vatPercentage: 19,
|
|
124
|
-
unitType: '
|
|
139
|
+
unitType: 'HUR' // Hour
|
|
125
140
|
}
|
|
126
141
|
];
|
|
127
142
|
|
|
128
|
-
// Export to
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
// Load from XML
|
|
132
|
-
const loadedInvoice = await EInvoice.fromXml(xml);
|
|
133
|
-
|
|
134
|
-
// Load from PDF
|
|
135
|
-
const pdfBuffer = await fs.readFile('invoice.pdf');
|
|
136
|
-
const invoiceFromPdf = await EInvoice.fromPdf(pdfBuffer);
|
|
137
|
-
|
|
138
|
-
// Export to PDF with embedded XML
|
|
143
|
+
// Export to any format you need
|
|
144
|
+
const zugferdXml = await invoice.exportXml('zugferd');
|
|
139
145
|
const pdfWithXml = await invoice.exportPdf('facturx');
|
|
140
|
-
await fs.writeFile('invoice-with-xml.pdf', pdfWithXml.buffer);
|
|
141
146
|
```
|
|
142
147
|
|
|
143
|
-
|
|
148
|
+
## 🎨 Supported Standards & Formats
|
|
144
149
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
// Load an XRechnung invoice
|
|
155
|
-
const xrechnungXml = await fs.readFile('xrechnung-invoice.xml', 'utf8');
|
|
156
|
-
const xrechnungInvoice = await EInvoice.fromXml(xrechnungXml);
|
|
157
|
-
|
|
158
|
-
// Export as different formats
|
|
159
|
-
const facturxXml = await zugferdInvoice.exportXml('facturx');
|
|
160
|
-
const ublXml = await facturxInvoice.exportXml('ubl');
|
|
161
|
-
const xrechnungXml = await zugferdInvoice.exportXml('xrechnung');
|
|
162
|
-
```
|
|
150
|
+
| Standard | Version | Status | Use Case |
|
|
151
|
+
|----------|---------|--------|----------|
|
|
152
|
+
| **EN16931** | 2017 | ✅ 100% Complete | Core European standard |
|
|
153
|
+
| **ZUGFeRD** | 1.0, 2.0, 2.1 | ✅ Full Support | German B2B/B2C |
|
|
154
|
+
| **Factur-X** | 1.0 (all profiles) | ✅ Full Support | France/Germany |
|
|
155
|
+
| **XRechnung** | 2.0, 3.0 | ✅ Full Support | German public sector |
|
|
156
|
+
| **PEPPOL BIS 3.0** | 3.0 | ✅ Full Support | Cross-border B2G |
|
|
157
|
+
| **UBL** | 2.1 | ✅ Full Support | International |
|
|
158
|
+
| **CII** | D16B | ✅ Full Support | Cross Industry |
|
|
163
159
|
|
|
164
|
-
###
|
|
160
|
+
### 📋 Factur-X Profile Support
|
|
165
161
|
|
|
166
162
|
```typescript
|
|
167
|
-
//
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
// Embed XML into PDF
|
|
175
|
-
invoice.pdf = {
|
|
176
|
-
name: 'invoice.pdf',
|
|
177
|
-
id: 'invoice-1234',
|
|
178
|
-
metadata: { textExtraction: '' },
|
|
179
|
-
buffer: await fs.readFile('document.pdf')
|
|
163
|
+
// Automatic profile detection and validation
|
|
164
|
+
const profiles = {
|
|
165
|
+
MINIMUM: 'Essential fields only (BT-1, BT-2, BT-3)',
|
|
166
|
+
BASIC: 'Core invoice with line items',
|
|
167
|
+
BASIC_WL: 'Basic without lines (summary invoices)',
|
|
168
|
+
EN16931: 'Full EN16931 compliance',
|
|
169
|
+
EXTENDED: 'Additional structured data'
|
|
180
170
|
};
|
|
181
|
-
|
|
182
|
-
const pdfWithInvoice = await invoice.exportPdf('facturx');
|
|
183
|
-
await fs.writeFile('invoice-with-xml.pdf', pdfWithInvoice.buffer);
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Validating Invoices
|
|
187
|
-
|
|
188
|
-
```typescript
|
|
189
|
-
// Validate an invoice
|
|
190
|
-
const validationResult = await invoice.validate();
|
|
191
|
-
if (validationResult.valid) {
|
|
192
|
-
console.log('Invoice is valid');
|
|
193
|
-
} else {
|
|
194
|
-
console.log('Validation errors:', validationResult.errors);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Validate at different levels
|
|
198
|
-
const syntaxValidation = await invoice.validate(ValidationLevel.SYNTAX);
|
|
199
|
-
const semanticValidation = await invoice.validate(ValidationLevel.SEMANTIC);
|
|
200
|
-
const businessValidation = await invoice.validate(ValidationLevel.BUSINESS);
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
### Error Handling
|
|
204
|
-
|
|
205
|
-
```typescript
|
|
206
|
-
try {
|
|
207
|
-
const invoice = await EInvoice.fromFile('invoice.xml');
|
|
208
|
-
const result = await invoice.validate();
|
|
209
|
-
|
|
210
|
-
if (!result.valid) {
|
|
211
|
-
for (const error of result.errors) {
|
|
212
|
-
console.log(`Error at ${error.path}: ${error.message}`);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
} catch (error) {
|
|
216
|
-
if (error instanceof ParseError) {
|
|
217
|
-
console.error('Failed to parse XML:', error.message);
|
|
218
|
-
} else if (error instanceof ValidationError) {
|
|
219
|
-
console.error('Validation failed:', error.message);
|
|
220
|
-
} else {
|
|
221
|
-
console.error('Unexpected error:', error);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
### Converting Between Formats
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
// Load a ZUGFeRD invoice and convert to various formats
|
|
230
|
-
const zugferdInvoice = await EInvoice.fromFile('zugferd.xml');
|
|
231
|
-
|
|
232
|
-
// Convert to XRechnung (German standard)
|
|
233
|
-
const xrechnungXml = await zugferdInvoice.exportXml('xrechnung');
|
|
234
|
-
|
|
235
|
-
// Convert to UBL format
|
|
236
|
-
const ublXml = await zugferdInvoice.exportXml('ubl');
|
|
237
|
-
|
|
238
|
-
// Convert to Factur-X
|
|
239
|
-
const facturxXml = await zugferdInvoice.exportXml('facturx');
|
|
240
|
-
|
|
241
|
-
// Convert to generic CII format
|
|
242
|
-
const ciiXml = await zugferdInvoice.exportXml('cii');
|
|
243
|
-
|
|
244
|
-
// All conversions preserve:
|
|
245
|
-
// - Invoice ID and dates
|
|
246
|
-
// - Party information
|
|
247
|
-
// - Line items with descriptions
|
|
248
|
-
// - Tax calculations
|
|
249
|
-
// - Payment terms
|
|
250
|
-
// - Notes and references
|
|
251
171
|
```
|
|
252
172
|
|
|
253
|
-
##
|
|
254
|
-
|
|
255
|
-
EInvoice implements a sophisticated **plugin-based, factory-driven architecture** that excels at handling multiple European e-invoicing standards while maintaining clean separation of concerns.
|
|
256
|
-
|
|
257
|
-
### Design Philosophy
|
|
258
|
-
|
|
259
|
-
The library follows these architectural principles:
|
|
260
|
-
- **Single Responsibility**: Each component has one clear purpose
|
|
261
|
-
- **Open/Closed**: Easy to extend with new formats without modifying existing code
|
|
262
|
-
- **Dependency Inversion**: Core logic depends on abstractions, not implementations
|
|
263
|
-
- **Interface Segregation**: Small, focused interfaces for maximum flexibility
|
|
173
|
+
## 🔥 Power Features
|
|
264
174
|
|
|
265
|
-
###
|
|
175
|
+
### 🧮 Decimal Precision for Financial Accuracy
|
|
266
176
|
|
|
267
|
-
|
|
268
|
-
- **EInvoice**: High-level API facade implementing the TInvoice interface from @tsclass/tsclass
|
|
269
|
-
- **FormatDetector**: Multi-strategy format detection using namespace analysis and content patterns
|
|
270
|
-
- **Error Classes**: Specialized errors (ParseError, ValidationError, ConversionError) with context
|
|
177
|
+
No more floating-point errors! Built-in arbitrary precision arithmetic:
|
|
271
178
|
|
|
272
|
-
#### Factory Pattern Implementation
|
|
273
179
|
```typescript
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
BaseDecoder (abstract)
|
|
283
|
-
├── CIIDecoder (abstract)
|
|
284
|
-
│ ├── FacturXDecoder
|
|
285
|
-
│ ├── ZUGFeRDDecoder
|
|
286
|
-
│ └── ZUGFeRDV1Decoder
|
|
287
|
-
└── UBLDecoder
|
|
288
|
-
└── XRechnungDecoder
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
#### Encoder Hierarchy
|
|
292
|
-
```
|
|
293
|
-
BaseEncoder (abstract)
|
|
294
|
-
├── CIIEncoder (abstract)
|
|
295
|
-
│ ├── FacturXEncoder
|
|
296
|
-
│ └── ZUGFeRDEncoder
|
|
297
|
-
└── UBLEncoder
|
|
298
|
-
└── XRechnungEncoder
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### PDF Processing Architecture
|
|
302
|
-
|
|
303
|
-
- **PDFExtractor**: Implements chain of responsibility pattern with three extraction strategies:
|
|
304
|
-
- **StandardExtractor**: PDF/A-3 embedded files via /EmbeddedFiles
|
|
305
|
-
- **AssociatedExtractor**: Associated files via /AF entry
|
|
306
|
-
- **TextExtractor**: Pattern matching in PDF text stream
|
|
307
|
-
- **PDFEmbedder**: Creates PDF/A-3 compliant documents with embedded XML
|
|
308
|
-
|
|
309
|
-
### Data Flow
|
|
310
|
-
|
|
311
|
-
```
|
|
312
|
-
XML/PDF Input → Format Detection → Decoder → TInvoice Model → Encoder → XML/PDF Output
|
|
313
|
-
↓
|
|
314
|
-
Validation
|
|
180
|
+
// Perfect financial calculations every time
|
|
181
|
+
const calculator = new DecimalCurrencyCalculator('EUR');
|
|
182
|
+
const result = calculator.calculateLineNet(
|
|
183
|
+
'3.14159', // Quantity
|
|
184
|
+
'999.99', // Unit price
|
|
185
|
+
'0' // Discount (optional)
|
|
186
|
+
);
|
|
187
|
+
// Result: 3141.56 (correctly rounded for EUR)
|
|
315
188
|
```
|
|
316
189
|
|
|
317
|
-
###
|
|
318
|
-
|
|
319
|
-
1. **Factory Pattern**: Dynamic creation of format-specific handlers
|
|
320
|
-
2. **Strategy Pattern**: Different algorithms for each invoice format
|
|
321
|
-
3. **Template Method**: Base classes define processing skeleton
|
|
322
|
-
4. **Chain of Responsibility**: PDF extractors with fallback strategies
|
|
323
|
-
5. **Facade Pattern**: EInvoice class simplifies complex subsystems
|
|
324
|
-
|
|
325
|
-
This modular architecture ensures maximum extensibility, maintainability, and compatibility across all supported invoice formats.
|
|
326
|
-
|
|
327
|
-
## Supported Invoice Formats
|
|
328
|
-
|
|
329
|
-
| Format | Version | Read | Write | Validate | Notes |
|
|
330
|
-
|--------|---------|------|-------|----------|-------|
|
|
331
|
-
| ZUGFeRD | 1.0 | ✅ | ✅ | ✅ | Legacy format, full support |
|
|
332
|
-
| ZUGFeRD | 2.0/2.1 | ✅ | ✅ | ✅ | Current German standard |
|
|
333
|
-
| Factur-X | 1.0 | ✅ | ✅ | ✅ | French/German standard |
|
|
334
|
-
| XRechnung | 2.0+ | ✅ | ✅ | ✅ | German public sector |
|
|
335
|
-
| UBL | 2.1 | ✅ | ✅ | ✅ | International standard |
|
|
336
|
-
| CII | 16931 | ✅ | ✅ | ✅ | Cross Industry Invoice |
|
|
337
|
-
| FatturaPA | 1.2 | ✅ | ✅ | ✅ | Italian standard |
|
|
338
|
-
|
|
339
|
-
## Performance Metrics
|
|
340
|
-
|
|
341
|
-
The library is optimized for both speed and memory efficiency:
|
|
342
|
-
|
|
343
|
-
| Operation | Average Time | Memory Usage |
|
|
344
|
-
|-----------|--------------|--------------|
|
|
345
|
-
| Format detection | ~0.1ms | Minimal |
|
|
346
|
-
| XML parsing | ~0.5ms | ~100KB |
|
|
347
|
-
| Validation | ~2.2ms | ~136KB |
|
|
348
|
-
| Format conversion | ~0.6ms | ~150KB |
|
|
349
|
-
| PDF extraction | ~5ms | ~1MB |
|
|
350
|
-
| PDF embedding | ~10ms | ~2MB |
|
|
351
|
-
|
|
352
|
-
### Benchmarks
|
|
190
|
+
### 🔍 Multi-Level Validation
|
|
353
191
|
|
|
354
192
|
```typescript
|
|
355
|
-
//
|
|
356
|
-
|
|
193
|
+
// Three-layer validation with detailed diagnostics
|
|
194
|
+
const syntaxResult = await invoice.validate(ValidationLevel.SYNTAX);
|
|
195
|
+
const semanticResult = await invoice.validate(ValidationLevel.SEMANTIC);
|
|
196
|
+
const businessResult = await invoice.validate(ValidationLevel.BUSINESS);
|
|
357
197
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
198
|
+
// Get specific rule violations
|
|
199
|
+
businessResult.errors.forEach(error => {
|
|
200
|
+
console.log(`Rule ${error.ruleId}: ${error.message}`);
|
|
201
|
+
console.log(`Business Term: ${error.btReference}`);
|
|
202
|
+
console.log(`Field: ${error.field}`);
|
|
361
203
|
});
|
|
362
|
-
|
|
363
|
-
console.log(`Validation took ${metric.duration}ms`);
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
## Implementation Details
|
|
367
|
-
|
|
368
|
-
### Advanced Date Handling
|
|
369
|
-
|
|
370
|
-
The library implements sophisticated date parsing for different formats:
|
|
371
|
-
|
|
372
|
-
```typescript
|
|
373
|
-
// CII formats use special date format codes
|
|
374
|
-
// Format 102: YYYYMMDD (e.g., "20240315")
|
|
375
|
-
// Format 610: YYYYMM (e.g., "202403")
|
|
376
|
-
// Automatic detection and parsing based on format attribute
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
### Character Encoding and Special Characters
|
|
380
|
-
|
|
381
|
-
Full Unicode support with automatic XML escaping:
|
|
382
|
-
|
|
383
|
-
```typescript
|
|
384
|
-
// Supports all Unicode including emojis and special characters
|
|
385
|
-
invoice.notes = ['Invoice for services 🚀', '中文发票', 'Facture française'];
|
|
386
|
-
|
|
387
|
-
// Automatic XML entity escaping
|
|
388
|
-
invoice.description = 'Products & Services <special> "quoted"';
|
|
389
|
-
// Becomes: Products & Services <special> "quoted"
|
|
390
204
|
```
|
|
391
205
|
|
|
392
|
-
###
|
|
393
|
-
|
|
394
|
-
The library guarantees 100% data preservation through metadata:
|
|
206
|
+
### 🔄 Format Detection & Conversion
|
|
395
207
|
|
|
396
208
|
```typescript
|
|
397
|
-
//
|
|
398
|
-
const
|
|
399
|
-
console.log(
|
|
400
|
-
|
|
401
|
-
// Convert to UBL and back - no data loss
|
|
402
|
-
const ublXml = await zugferdInvoice.exportXml('ubl');
|
|
403
|
-
const backToZugferd = await EInvoice.fromXml(ublXml);
|
|
404
|
-
const zugferdXml2 = await backToZugferd.exportXml('zugferd');
|
|
405
|
-
// zugferdXml2 contains all original data
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
### Tax Calculation Engine
|
|
409
|
-
|
|
410
|
-
Efficient tax grouping and calculation:
|
|
411
|
-
|
|
412
|
-
```typescript
|
|
413
|
-
// Automatic tax breakdown by rate
|
|
414
|
-
const taxBreakdown = invoice.calculateTaxBreakdown();
|
|
415
|
-
// Returns: Map<number, { base: number, tax: number }>
|
|
416
|
-
// Example: { 19 => { base: 1000, tax: 190 }, 7 => { base: 500, tax: 35 } }
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
### Advanced Validation
|
|
420
|
-
|
|
421
|
-
Three-layer validation with detailed business rules:
|
|
422
|
-
|
|
423
|
-
```typescript
|
|
424
|
-
// Validation levels cascade
|
|
425
|
-
const syntaxResult = await invoice.validate(ValidationLevel.SYNTAX); // XML structure
|
|
426
|
-
const semanticResult = await invoice.validate(ValidationLevel.SEMANTIC); // Field content
|
|
427
|
-
const businessResult = await invoice.validate(ValidationLevel.BUSINESS); // EN16931 rules
|
|
428
|
-
|
|
429
|
-
// Business rules include:
|
|
430
|
-
// - BR-CO-10: Sum of line amounts = invoice total
|
|
431
|
-
// - BR-CO-13: Sum of allowances calculation
|
|
432
|
-
// - BR-CO-15: Invoice total with VAT calculation
|
|
433
|
-
// All with 0.01 tolerance for floating-point
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### Error Recovery Mechanisms
|
|
437
|
-
|
|
438
|
-
Sophisticated error handling with recovery:
|
|
439
|
-
|
|
440
|
-
```typescript
|
|
441
|
-
try {
|
|
442
|
-
const invoice = await EInvoice.fromXml(malformedXml);
|
|
443
|
-
} catch (error) {
|
|
444
|
-
if (error instanceof ParseError) {
|
|
445
|
-
// Automatic recovery attempts:
|
|
446
|
-
// 1. BOM removal
|
|
447
|
-
// 2. Entity fixing
|
|
448
|
-
// 3. Namespace correction
|
|
449
|
-
// 4. Encoding detection
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
### Performance Optimizations
|
|
455
|
-
|
|
456
|
-
- **Quick format detection**: String checks before DOM parsing
|
|
457
|
-
- **Lazy loading**: Format handlers loaded on demand
|
|
458
|
-
- **Efficient calculations**: Single-pass tax grouping
|
|
459
|
-
- **Memory efficiency**: ~136KB per validation
|
|
460
|
-
|
|
461
|
-
## Advanced Usage
|
|
462
|
-
|
|
463
|
-
### Custom Encoders and Decoders
|
|
464
|
-
|
|
465
|
-
```typescript
|
|
466
|
-
// Using specific encoders
|
|
467
|
-
import { ZUGFeRDEncoder, FacturXEncoder, UBLEncoder } from '@fin.cx/einvoice';
|
|
468
|
-
|
|
469
|
-
// Create ZUGFeRD XML
|
|
470
|
-
const zugferdEncoder = new ZUGFeRDEncoder();
|
|
471
|
-
const zugferdXml = await zugferdEncoder.encode(invoiceData);
|
|
472
|
-
|
|
473
|
-
// Create Factur-X XML
|
|
474
|
-
const facturxEncoder = new FacturXEncoder();
|
|
475
|
-
const facturxXml = await facturxEncoder.encode(invoiceData);
|
|
476
|
-
|
|
477
|
-
// Create UBL XML
|
|
478
|
-
const ublEncoder = new UBLEncoder();
|
|
479
|
-
const ublXml = await ublEncoder.encode(invoiceData);
|
|
480
|
-
|
|
481
|
-
// Using specific decoders
|
|
482
|
-
import { ZUGFeRDDecoder, FacturXDecoder } from '@fin.cx/einvoice';
|
|
483
|
-
|
|
484
|
-
// Decode ZUGFeRD XML
|
|
485
|
-
const zugferdDecoder = new ZUGFeRDDecoder(zugferdXml);
|
|
486
|
-
const zugferdData = await zugferdDecoder.decode();
|
|
209
|
+
// Automatic format detection
|
|
210
|
+
const format = FormatDetector.detectFormat(xmlString);
|
|
211
|
+
console.log(`Detected: ${format}`); // 'zugferd', 'facturx', 'xrechnung', etc.
|
|
487
212
|
|
|
488
|
-
//
|
|
489
|
-
const
|
|
490
|
-
const
|
|
213
|
+
// Intelligent conversion preserves all data
|
|
214
|
+
const zugferd = await EInvoice.fromFile('zugferd.xml');
|
|
215
|
+
const xrechnung = await zugferd.exportXml('xrechnung');
|
|
216
|
+
const backToZugferd = await EInvoice.fromXml(xrechnung);
|
|
217
|
+
// All data preserved through round-trip!
|
|
491
218
|
```
|
|
492
219
|
|
|
493
|
-
###
|
|
220
|
+
### 📄 PDF Operations
|
|
494
221
|
|
|
495
222
|
```typescript
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
// Extract XML from PDF
|
|
223
|
+
// Extract XML from PDF invoices
|
|
499
224
|
const extractor = new PDFExtractor();
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
console.log('Detected format:', extractResult.format);
|
|
505
|
-
console.log('Extraction method used:', extractResult.extractorUsed);
|
|
506
|
-
} else {
|
|
507
|
-
console.error('Extraction failed:', extractResult.error?.message);
|
|
225
|
+
const result = await extractor.extractXml(pdfBuffer);
|
|
226
|
+
if (result.success) {
|
|
227
|
+
console.log(`Found ${result.format} invoice`);
|
|
228
|
+
const invoice = await EInvoice.fromXml(result.xml);
|
|
508
229
|
}
|
|
509
230
|
|
|
510
|
-
// Embed XML into PDF
|
|
231
|
+
// Embed XML into PDF for hybrid invoices
|
|
511
232
|
const embedder = new PDFEmbedder();
|
|
512
|
-
const
|
|
513
|
-
|
|
233
|
+
const pdfWithXml = await embedder.createPdfWithXml(
|
|
234
|
+
existingPdf,
|
|
514
235
|
xmlContent,
|
|
515
236
|
'factur-x.xml',
|
|
516
|
-
'Factur-X
|
|
517
|
-
'invoice.pdf',
|
|
518
|
-
'invoice-123456'
|
|
237
|
+
'Factur-X Invoice'
|
|
519
238
|
);
|
|
520
|
-
|
|
521
|
-
if (embedResult.success && embedResult.pdf) {
|
|
522
|
-
await fs.writeFile('output.pdf', embedResult.pdf.buffer);
|
|
523
|
-
} else {
|
|
524
|
-
console.error('Embedding failed:', embedResult.error?.message);
|
|
525
|
-
}
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
### Format Detection
|
|
529
|
-
|
|
530
|
-
```typescript
|
|
531
|
-
import { FormatDetector, InvoiceFormat } from '@fin.cx/einvoice';
|
|
532
|
-
|
|
533
|
-
// Detect format from XML
|
|
534
|
-
const format = FormatDetector.detectFormat(xmlString);
|
|
535
|
-
|
|
536
|
-
// Check format
|
|
537
|
-
if (format === InvoiceFormat.ZUGFERD) {
|
|
538
|
-
console.log('This is a ZUGFeRD invoice');
|
|
539
|
-
} else if (format === InvoiceFormat.FACTURX) {
|
|
540
|
-
console.log('This is a Factur-X invoice');
|
|
541
|
-
} else if (format === InvoiceFormat.XRECHNUNG) {
|
|
542
|
-
console.log('This is an XRechnung invoice');
|
|
543
|
-
} else if (format === InvoiceFormat.UBL) {
|
|
544
|
-
console.log('This is a UBL invoice');
|
|
545
|
-
}
|
|
546
239
|
```
|
|
547
240
|
|
|
548
|
-
## Country-Specific
|
|
549
|
-
|
|
550
|
-
The library supports country-specific requirements and extensions:
|
|
241
|
+
## 🌍 Country-Specific Requirements
|
|
551
242
|
|
|
552
|
-
### German XRechnung
|
|
243
|
+
### 🇩🇪 German XRechnung
|
|
553
244
|
|
|
554
245
|
```typescript
|
|
555
|
-
const invoice = new EInvoice();
|
|
556
246
|
invoice.metadata = {
|
|
557
|
-
|
|
247
|
+
customizationId: 'urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0',
|
|
558
248
|
extensions: {
|
|
559
|
-
|
|
560
|
-
'
|
|
561
|
-
|
|
249
|
+
leitwegId: '991-12345-67', // Required routing ID
|
|
250
|
+
buyerReference: 'DE-BUYER-REF', // Mandatory
|
|
251
|
+
sellerContact: {
|
|
252
|
+
name: 'Max Mustermann',
|
|
253
|
+
phone: '+49 30 12345678',
|
|
254
|
+
email: 'invoice@company.de'
|
|
255
|
+
}
|
|
562
256
|
}
|
|
563
257
|
};
|
|
564
|
-
|
|
565
|
-
// XRechnung requires specific payment terms
|
|
566
|
-
invoice.paymentTerms = {
|
|
567
|
-
method: 'SEPA',
|
|
568
|
-
iban: 'DE89370400440532013000',
|
|
569
|
-
bic: 'DEUTDEFF',
|
|
570
|
-
reference: 'RF18539007547034'
|
|
571
|
-
};
|
|
572
258
|
```
|
|
573
259
|
|
|
574
|
-
###
|
|
260
|
+
### 🇪🇺 PEPPOL BIS 3.0
|
|
575
261
|
|
|
576
262
|
```typescript
|
|
577
|
-
const invoice = new EInvoice();
|
|
578
263
|
invoice.metadata = {
|
|
579
|
-
|
|
264
|
+
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
|
|
580
265
|
extensions: {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
CodiceFiscale: 'RSSMRA80A01H501U'
|
|
266
|
+
endpointId: '0088:1234567890128', // GLN with checksum
|
|
267
|
+
documentTypeId: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017',
|
|
268
|
+
processId: 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0'
|
|
585
269
|
}
|
|
586
270
|
};
|
|
587
271
|
```
|
|
588
272
|
|
|
589
|
-
### French
|
|
273
|
+
### 🇫🇷 French Chorus Pro
|
|
590
274
|
|
|
591
275
|
```typescript
|
|
592
|
-
const invoice = new EInvoice();
|
|
593
276
|
invoice.metadata = {
|
|
594
|
-
format: InvoiceFormat.FACTURX,
|
|
595
277
|
extensions: {
|
|
596
278
|
siret: '12345678901234',
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
engagementNumber: 'ENG123456'
|
|
601
|
-
}
|
|
279
|
+
serviceCode: 'SERVICE-2025',
|
|
280
|
+
engagementNumber: 'ENG-123456',
|
|
281
|
+
marketReference: 'MARKET-REF-001'
|
|
602
282
|
}
|
|
603
283
|
};
|
|
604
284
|
```
|
|
605
285
|
|
|
606
|
-
##
|
|
286
|
+
## ⚡ Performance Metrics
|
|
607
287
|
|
|
608
|
-
|
|
609
|
-
- **Plugin-based design** with factory pattern for easy extensibility
|
|
610
|
-
- **SOLID principles** throughout the codebase
|
|
611
|
-
- **Comprehensive test coverage** with 500+ test cases
|
|
612
|
-
- **Battle-tested** with real-world invoice corpus
|
|
613
|
-
|
|
614
|
-
### 🔒 Enterprise Security
|
|
615
|
-
- **XXE prevention** with disabled external entities
|
|
616
|
-
- **Resource limits** to prevent DoS attacks
|
|
617
|
-
- **Path traversal protection** for PDF operations
|
|
618
|
-
- **SSRF mitigation** in XML processing
|
|
619
|
-
|
|
620
|
-
### ⚡ High Performance
|
|
621
|
-
- **Sub-millisecond conversions** (~0.6ms average)
|
|
622
|
-
- **Efficient memory usage** (~136KB per validation)
|
|
623
|
-
- **Concurrent processing** support
|
|
624
|
-
- **Streaming capabilities** for large files
|
|
625
|
-
|
|
626
|
-
### 🌍 Standards Compliance
|
|
627
|
-
- **EN16931** business rules implementation
|
|
628
|
-
- **Country-specific extensions** (XRechnung, FatturaPA, Factur-X)
|
|
629
|
-
- **100% data preservation** in round-trip conversions
|
|
630
|
-
- **Multi-format validation** with detailed error reporting
|
|
631
|
-
|
|
632
|
-
### 🛠️ Developer Experience
|
|
633
|
-
- **Fully typed** with TypeScript
|
|
634
|
-
- **Intuitive API** with static factory methods
|
|
635
|
-
- **Detailed error messages** with recovery suggestions
|
|
636
|
-
- **Extensive documentation** and examples
|
|
637
|
-
|
|
638
|
-
## Recent Improvements
|
|
639
|
-
|
|
640
|
-
### Version 2.0.0 (2025)
|
|
641
|
-
|
|
642
|
-
- **TypeScript Type System**: Full alignment with @tsclass/tsclass interfaces
|
|
643
|
-
- **Date Parsing**: Enhanced CII date parsing for various formats (YYYYMMDD, YYYYMM)
|
|
644
|
-
- **API Enhancements**: Added static factory methods (fromXml, fromFile, fromPdf)
|
|
645
|
-
- **Format Support**: Added generic CII export format
|
|
646
|
-
- **Performance**: Optimized validation to ~2.2ms average
|
|
647
|
-
- **Memory Efficiency**: Reduced memory usage to ~136KB per validation
|
|
648
|
-
- **XRechnung Encoder**: Complete implementation with German-specific requirements
|
|
649
|
-
- **Error Recovery**: Improved error handling with detailed messages
|
|
650
|
-
- **Security Hardening**: XXE prevention, resource limits, path traversal protection
|
|
651
|
-
- **Production Features**: Concurrent processing, memory management, integration patterns
|
|
652
|
-
|
|
653
|
-
## Development
|
|
654
|
-
|
|
655
|
-
### Building the Project
|
|
288
|
+
Lightning-fast operations with minimal memory footprint:
|
|
656
289
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
290
|
+
| Operation | Speed | Memory |
|
|
291
|
+
|-----------|-------|--------|
|
|
292
|
+
| **Format Detection** | ~0.1ms | Minimal |
|
|
293
|
+
| **XML Parsing** | ~0.5ms | ~100KB |
|
|
294
|
+
| **Full Validation** | ~2.2ms | ~136KB |
|
|
295
|
+
| **Format Conversion** | ~0.6ms | ~150KB |
|
|
296
|
+
| **PDF Extraction** | ~5ms | ~1MB |
|
|
297
|
+
| **PDF Embedding** | ~10ms | ~2MB |
|
|
660
298
|
|
|
661
|
-
|
|
662
|
-
pnpm run build
|
|
663
|
-
```
|
|
299
|
+
## 🏗️ Architecture
|
|
664
300
|
|
|
665
|
-
###
|
|
666
|
-
|
|
667
|
-
```bash
|
|
668
|
-
# Run all tests
|
|
669
|
-
pnpm test
|
|
301
|
+
### Plugin-Based Design
|
|
670
302
|
|
|
671
|
-
|
|
672
|
-
|
|
303
|
+
```typescript
|
|
304
|
+
// Factory pattern for extensibility
|
|
305
|
+
DecoderFactory.getDecoder(format) → BaseDecoder
|
|
306
|
+
EncoderFactory.getEncoder(format) → BaseEncoder
|
|
307
|
+
ValidatorFactory.getValidator(format) → BaseValidator
|
|
308
|
+
```
|
|
673
309
|
|
|
674
|
-
|
|
675
|
-
tstest test/suite/einvoice_validation/test.val-12.validation-performance.ts --verbose
|
|
310
|
+
### Data Flow
|
|
676
311
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
312
|
+
```
|
|
313
|
+
Input (XML/PDF) → Format Detection → Decoder → EInvoice Model
|
|
314
|
+
↓
|
|
315
|
+
Validation
|
|
316
|
+
↓
|
|
317
|
+
Encoder → Output (XML/PDF)
|
|
681
318
|
```
|
|
682
319
|
|
|
683
|
-
|
|
684
|
-
- **Format Detection**: Automatic detection of all supported formats
|
|
685
|
-
- **Conversion**: Round-trip conversion between all format pairs
|
|
686
|
-
- **Validation**: Multi-level validation (syntax, semantic, business rules)
|
|
687
|
-
- **Performance**: Validation in ~2.2ms, memory usage ~136KB
|
|
688
|
-
- **PDF Operations**: Extraction and embedding with multiple strategies
|
|
689
|
-
- **Error Handling**: Recovery from malformed data
|
|
690
|
-
- **Special Characters**: Unicode and escape sequence handling
|
|
691
|
-
- **Country Extensions**: XRechnung, FatturaPA, Factur-X specifics
|
|
320
|
+
## 🔒 Security Features
|
|
692
321
|
|
|
693
|
-
|
|
322
|
+
- **XXE Prevention**: External entities disabled by default
|
|
323
|
+
- **Resource Limits**: Max 100MB XML, max 100 nesting levels
|
|
324
|
+
- **Path Traversal Protection**: Sanitized filenames in PDFs
|
|
325
|
+
- **SSRF Mitigation**: Entity blocking in XML processing
|
|
326
|
+
- **Input Validation**: Comprehensive input sanitization
|
|
694
327
|
|
|
695
|
-
|
|
328
|
+
## 🧪 Testing
|
|
696
329
|
|
|
697
|
-
|
|
330
|
+
```bash
|
|
331
|
+
# Run all tests
|
|
332
|
+
pnpm test
|
|
698
333
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
// ✓ Maximum XML size: 100MB (configurable)
|
|
707
|
-
// ✓ Maximum nesting depth: 100 levels
|
|
708
|
-
// ✓ Memory protection via streaming for large files
|
|
709
|
-
|
|
710
|
-
// Path Traversal Prevention
|
|
711
|
-
// ✓ Filename sanitization for PDF attachments
|
|
712
|
-
// ✓ No file system access from XML content
|
|
334
|
+
# Run specific test suites
|
|
335
|
+
pnpm test test/test.peppol-validator.ts
|
|
336
|
+
pnpm test test/test.facturx-validator.ts
|
|
337
|
+
pnpm test test/test.semantic-model.ts
|
|
338
|
+
|
|
339
|
+
# Run with verbose output
|
|
340
|
+
pnpm test -- --verbose
|
|
713
341
|
```
|
|
714
342
|
|
|
715
|
-
|
|
343
|
+
## 📚 Advanced Examples
|
|
716
344
|
|
|
717
|
-
|
|
345
|
+
### Batch Processing with Concurrency Control
|
|
718
346
|
|
|
719
347
|
```typescript
|
|
720
|
-
|
|
721
|
-
const invoices = ['invoice1.xml', 'invoice2.xml', 'invoice3.xml'];
|
|
722
|
-
const results = await Promise.all(
|
|
723
|
-
invoices.map(file => EInvoice.fromFile(file))
|
|
724
|
-
);
|
|
348
|
+
import pLimit from 'p-limit';
|
|
725
349
|
|
|
726
|
-
// Concurrent validation with controlled concurrency
|
|
727
|
-
const pLimit = (await import('p-limit')).default;
|
|
728
350
|
const limit = pLimit(5); // Max 5 concurrent operations
|
|
351
|
+
const files = ['invoice1.xml', 'invoice2.xml', /* ... */];
|
|
729
352
|
|
|
730
|
-
const
|
|
731
|
-
|
|
732
|
-
limit(() =>
|
|
353
|
+
const results = await Promise.all(
|
|
354
|
+
files.map(file =>
|
|
355
|
+
limit(async () => {
|
|
356
|
+
const invoice = await EInvoice.fromFile(file);
|
|
357
|
+
const validation = await invoice.validate();
|
|
358
|
+
return { file, valid: validation.valid };
|
|
359
|
+
})
|
|
733
360
|
)
|
|
734
361
|
);
|
|
735
362
|
```
|
|
736
363
|
|
|
737
|
-
###
|
|
738
|
-
|
|
739
|
-
Best practices for handling large volumes:
|
|
740
|
-
|
|
741
|
-
```typescript
|
|
742
|
-
// Process large batches with memory control
|
|
743
|
-
async function processBatch(files: string[]) {
|
|
744
|
-
const batchSize = 100;
|
|
745
|
-
const results = [];
|
|
746
|
-
|
|
747
|
-
for (let i = 0; i < files.length; i += batchSize) {
|
|
748
|
-
const batch = files.slice(i, i + batchSize);
|
|
749
|
-
const batchResults = await Promise.all(
|
|
750
|
-
batch.map(f => processInvoice(f))
|
|
751
|
-
);
|
|
752
|
-
results.push(...batchResults);
|
|
753
|
-
|
|
754
|
-
// Allow garbage collection between batches
|
|
755
|
-
if (global.gc) global.gc();
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
return results;
|
|
759
|
-
}
|
|
760
|
-
```
|
|
761
|
-
|
|
762
|
-
### Edge Case Handling
|
|
763
|
-
|
|
764
|
-
The library handles numerous edge cases:
|
|
364
|
+
### REST API Integration
|
|
765
365
|
|
|
766
366
|
```typescript
|
|
767
|
-
|
|
768
|
-
try {
|
|
769
|
-
await EInvoice.fromXml(''); // Throws ParseError
|
|
770
|
-
} catch (e) {
|
|
771
|
-
// Handle empty input
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// Huge files (500+ line items)
|
|
775
|
-
const largeInvoice = new EInvoice();
|
|
776
|
-
largeInvoice.items = Array(1000).fill(null).map((_, i) => ({
|
|
777
|
-
position: i + 1,
|
|
778
|
-
name: `Item ${i + 1}`,
|
|
779
|
-
unitQuantity: 1,
|
|
780
|
-
unitNetPrice: 10,
|
|
781
|
-
vatPercentage: 19
|
|
782
|
-
}));
|
|
783
|
-
// Handles efficiently with ~136KB memory per validation
|
|
784
|
-
|
|
785
|
-
// Mixed character encodings
|
|
786
|
-
invoice.notes = ['UTF-8: €', 'Emoji: 🚀', 'Chinese: 中文'];
|
|
787
|
-
// All properly encoded in output XML
|
|
788
|
-
|
|
789
|
-
// Timezone handling
|
|
790
|
-
invoice.issueDate = new Date('2024-01-01T00:00:00+02:00');
|
|
791
|
-
// Preserves timezone information
|
|
792
|
-
```
|
|
793
|
-
|
|
794
|
-
### Production Configuration
|
|
795
|
-
|
|
796
|
-
Recommended settings for production:
|
|
797
|
-
|
|
798
|
-
```typescript
|
|
799
|
-
// Error handling strategy
|
|
800
|
-
const productionConfig = {
|
|
801
|
-
// Validation
|
|
802
|
-
validationLevel: ValidationLevel.BUSINESS,
|
|
803
|
-
strictMode: true,
|
|
804
|
-
|
|
805
|
-
// Performance
|
|
806
|
-
maxConcurrency: os.cpus().length,
|
|
807
|
-
cacheEnabled: true,
|
|
808
|
-
|
|
809
|
-
// Security
|
|
810
|
-
maxXmlSize: 100 * 1024 * 1024, // 100MB
|
|
811
|
-
maxNestingDepth: 100,
|
|
812
|
-
externalEntities: false,
|
|
813
|
-
|
|
814
|
-
// Logging
|
|
815
|
-
logLevel: 'error', // 'debug' | 'info' | 'warn' | 'error'
|
|
816
|
-
logFormat: 'json'
|
|
817
|
-
};
|
|
818
|
-
```
|
|
819
|
-
|
|
820
|
-
### Integration Patterns
|
|
821
|
-
|
|
822
|
-
Common integration scenarios:
|
|
823
|
-
|
|
824
|
-
```typescript
|
|
825
|
-
// REST API Integration
|
|
826
|
-
app.post('/invoice/convert', async (req, res) => {
|
|
367
|
+
app.post('/api/invoice/convert', async (req, res) => {
|
|
827
368
|
try {
|
|
828
369
|
const { xml, targetFormat } = req.body;
|
|
829
370
|
const invoice = await EInvoice.fromXml(xml);
|
|
371
|
+
|
|
372
|
+
// Validate before conversion
|
|
373
|
+
const validation = await invoice.validate();
|
|
374
|
+
if (!validation.valid) {
|
|
375
|
+
return res.status(400).json({
|
|
376
|
+
error: 'Invalid invoice',
|
|
377
|
+
violations: validation.errors
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
830
381
|
const converted = await invoice.exportXml(targetFormat);
|
|
831
382
|
res.json({ success: true, xml: converted });
|
|
832
383
|
} catch (error) {
|
|
833
|
-
res.status(
|
|
834
|
-
success: false,
|
|
835
|
-
error: error.message,
|
|
836
|
-
type: error.constructor.name
|
|
837
|
-
});
|
|
384
|
+
res.status(500).json({ error: error.message });
|
|
838
385
|
}
|
|
839
386
|
});
|
|
840
|
-
|
|
841
|
-
// Message Queue Processing
|
|
842
|
-
async function processInvoiceMessage(message: any) {
|
|
843
|
-
const { invoiceId, pdfBuffer } = message;
|
|
844
|
-
|
|
845
|
-
try {
|
|
846
|
-
const invoice = await EInvoice.fromPdf(Buffer.from(pdfBuffer, 'base64'));
|
|
847
|
-
const validation = await invoice.validate();
|
|
848
|
-
|
|
849
|
-
await saveToDatabase(invoiceId, invoice, validation);
|
|
850
|
-
await acknowledgeMessage(message);
|
|
851
|
-
} catch (error) {
|
|
852
|
-
await handleError(message, error);
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
// Batch Processing Pipeline
|
|
857
|
-
const pipeline = [
|
|
858
|
-
extractFromPdf,
|
|
859
|
-
validateInvoice,
|
|
860
|
-
convertToXRechnung,
|
|
861
|
-
sendToERP
|
|
862
|
-
];
|
|
863
|
-
|
|
864
|
-
for (const step of pipeline) {
|
|
865
|
-
await step(invoice);
|
|
866
|
-
}
|
|
867
387
|
```
|
|
868
388
|
|
|
869
|
-
##
|
|
389
|
+
## 🎯 What Makes Us Different
|
|
870
390
|
|
|
871
|
-
###
|
|
391
|
+
### 🏆 100% EN16931 Compliance
|
|
392
|
+
- All 162 Business Terms implemented
|
|
393
|
+
- All 32 Business Groups structured
|
|
394
|
+
- Complete semantic model with BT/BG validation
|
|
395
|
+
- Official Schematron rules integrated
|
|
872
396
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
} catch (error) {
|
|
879
|
-
console.error('Failed to parse:', error.message);
|
|
880
|
-
// Try format-specific decoder
|
|
881
|
-
const decoder = new ZUGFeRDDecoder(xmlString);
|
|
882
|
-
const invoice = await decoder.decode();
|
|
883
|
-
}
|
|
884
|
-
```
|
|
885
|
-
|
|
886
|
-
**PDF Extraction Failures**
|
|
887
|
-
```typescript
|
|
888
|
-
// PDF might not contain XML
|
|
889
|
-
const result = await PDFExtractor.extractXml(pdfBuffer);
|
|
890
|
-
if (!result.success) {
|
|
891
|
-
console.log('No XML found in PDF');
|
|
892
|
-
// Create invoice from scratch or OCR
|
|
893
|
-
}
|
|
894
|
-
```
|
|
895
|
-
|
|
896
|
-
**Validation Errors**
|
|
897
|
-
```typescript
|
|
898
|
-
// Check validation level
|
|
899
|
-
const result = await invoice.validate();
|
|
900
|
-
if (!result.valid) {
|
|
901
|
-
// Check if it's a warning vs error
|
|
902
|
-
const errors = result.errors.filter(e => e.severity === 'error');
|
|
903
|
-
const warnings = result.errors.filter(e => e.severity === 'warning');
|
|
904
|
-
}
|
|
905
|
-
```
|
|
906
|
-
|
|
907
|
-
## API Reference
|
|
908
|
-
|
|
909
|
-
### EInvoice Class
|
|
910
|
-
|
|
911
|
-
```typescript
|
|
912
|
-
class EInvoice {
|
|
913
|
-
// Static factory methods
|
|
914
|
-
static fromXml(xmlString: string): Promise<EInvoice>
|
|
915
|
-
static fromFile(filePath: string): Promise<EInvoice>
|
|
916
|
-
static fromPdf(pdfBuffer: Buffer): Promise<EInvoice>
|
|
917
|
-
|
|
918
|
-
// Instance methods
|
|
919
|
-
validate(level?: ValidationLevel): Promise<ValidationResult>
|
|
920
|
-
exportXml(format: ExportFormat): Promise<string>
|
|
921
|
-
exportPdf(format: ExportFormat): Promise<{ buffer: Buffer }>
|
|
922
|
-
getFormat(): InvoiceFormat
|
|
923
|
-
|
|
924
|
-
// Properties (following TInvoice interface)
|
|
925
|
-
id: string
|
|
926
|
-
date: Date
|
|
927
|
-
from: TParty
|
|
928
|
-
to: TParty
|
|
929
|
-
items: TAccountingDocItem[]
|
|
930
|
-
paymentOptions: TPaymentOptions
|
|
931
|
-
metadata?: any
|
|
932
|
-
}
|
|
933
|
-
```
|
|
934
|
-
|
|
935
|
-
### Supported Export Formats
|
|
936
|
-
|
|
937
|
-
```typescript
|
|
938
|
-
type ExportFormat = 'facturx' | 'zugferd' | 'xrechnung' | 'ubl' | 'cii'
|
|
939
|
-
```
|
|
940
|
-
|
|
941
|
-
### Validation Levels
|
|
942
|
-
|
|
943
|
-
```typescript
|
|
944
|
-
enum ValidationLevel {
|
|
945
|
-
SYNTAX = 'syntax', // XML structure validation
|
|
946
|
-
SEMANTIC = 'semantic', // Field content validation
|
|
947
|
-
BUSINESS = 'business' // Business rule validation
|
|
948
|
-
}
|
|
949
|
-
```
|
|
950
|
-
|
|
951
|
-
## Key Features
|
|
952
|
-
|
|
953
|
-
1. **PDF Integration**
|
|
954
|
-
- Embed XML invoices in PDF documents with detailed error reporting
|
|
955
|
-
- Extract XML from existing PDF invoices using multiple fallback strategies
|
|
956
|
-
- Handle different XML attachment methods and encodings
|
|
397
|
+
### 💎 Production Excellence
|
|
398
|
+
- **500+ test cases** ensuring reliability
|
|
399
|
+
- **Battle-tested** with real-world invoice corpus
|
|
400
|
+
- **Memory efficient** - handles 1000+ line items
|
|
401
|
+
- **Thread-safe** for concurrent processing
|
|
957
402
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
403
|
+
### 🚀 Developer Experience
|
|
404
|
+
- **IntelliSense everywhere** - fully typed API
|
|
405
|
+
- **Detailed error messages** with recovery hints
|
|
406
|
+
- **Static factory methods** for intuitive usage
|
|
407
|
+
- **Comprehensive documentation** with real examples
|
|
963
408
|
|
|
964
|
-
|
|
965
|
-
- Automatic detection of invoice XML format
|
|
966
|
-
- Support for different XML namespaces
|
|
967
|
-
- Graceful handling of malformed XML
|
|
409
|
+
## 📦 Installation Requirements
|
|
968
410
|
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
411
|
+
- Node.js 18+ or modern browser
|
|
412
|
+
- TypeScript 5.0+ (for TypeScript projects)
|
|
413
|
+
- ~15MB installed size
|
|
414
|
+
- Zero native dependencies
|
|
973
415
|
|
|
974
|
-
|
|
975
|
-
- Robust error recovery mechanisms
|
|
976
|
-
- Detailed error information
|
|
977
|
-
- Type-safe error reporting
|
|
416
|
+
## 🤝 Standards Compliance
|
|
978
417
|
|
|
979
|
-
|
|
418
|
+
This library implements:
|
|
419
|
+
- **EN 16931-1:2017** - Core invoice model
|
|
420
|
+
- **CEN/TS 16931-3** - Syntax bindings
|
|
421
|
+
- **ISO 4217** - Currency codes
|
|
422
|
+
- **ISO 3166** - Country codes
|
|
423
|
+
- **UN/ECE Rec 20** - Units of measure
|
|
424
|
+
- **ISO 6523** - Organization identifiers
|
|
980
425
|
|
|
981
426
|
## License and Legal Information
|
|
982
427
|
|
|
983
|
-
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
428
|
+
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
984
429
|
|
|
985
430
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
986
431
|
|