@fin.cx/einvoice 5.0.2 → 5.1.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.
Files changed (116) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/einvoice.d.ts +4 -8
  3. package/dist_ts/einvoice.js +46 -7
  4. package/dist_ts/formats/converters/xml-to-einvoice.converter.d.ts +21 -0
  5. package/dist_ts/formats/converters/xml-to-einvoice.converter.js +127 -0
  6. package/dist_ts/formats/semantic/bt-bg.model.d.ts +445 -0
  7. package/dist_ts/formats/semantic/bt-bg.model.js +12 -0
  8. package/dist_ts/formats/semantic/semantic.adapter.d.ts +87 -0
  9. package/dist_ts/formats/semantic/semantic.adapter.js +538 -0
  10. package/dist_ts/formats/semantic/semantic.validator.d.ts +48 -0
  11. package/dist_ts/formats/semantic/semantic.validator.js +596 -0
  12. package/dist_ts/formats/utils/currency.calculator.decimal.d.ts +98 -0
  13. package/dist_ts/formats/utils/currency.calculator.decimal.js +212 -0
  14. package/dist_ts/formats/utils/currency.utils.d.ts +99 -0
  15. package/dist_ts/formats/utils/currency.utils.js +250 -0
  16. package/dist_ts/formats/utils/decimal.d.ts +151 -0
  17. package/dist_ts/formats/utils/decimal.js +435 -0
  18. package/dist_ts/formats/validation/codelist.validator.d.ts +49 -0
  19. package/dist_ts/formats/validation/codelist.validator.js +188 -0
  20. package/dist_ts/formats/validation/conformance.harness.d.ts +99 -0
  21. package/dist_ts/formats/validation/conformance.harness.js +471 -0
  22. package/dist_ts/formats/validation/en16931.business-rules.validator.d.ts +58 -0
  23. package/dist_ts/formats/validation/en16931.business-rules.validator.js +459 -0
  24. package/dist_ts/formats/validation/facturx.validator.d.ts +75 -0
  25. package/dist_ts/formats/validation/facturx.validator.js +522 -0
  26. package/dist_ts/formats/validation/integrated.validator.d.ts +82 -0
  27. package/dist_ts/formats/validation/integrated.validator.js +311 -0
  28. package/dist_ts/formats/validation/peppol.validator.d.ts +77 -0
  29. package/dist_ts/formats/validation/peppol.validator.js +529 -0
  30. package/dist_ts/formats/validation/schematron.downloader.d.ts +71 -0
  31. package/dist_ts/formats/validation/schematron.downloader.js +254 -0
  32. package/dist_ts/formats/validation/schematron.integration.d.ts +60 -0
  33. package/dist_ts/formats/validation/schematron.integration.js +230 -0
  34. package/dist_ts/formats/validation/schematron.validator.d.ts +79 -0
  35. package/dist_ts/formats/validation/schematron.validator.js +288 -0
  36. package/dist_ts/formats/validation/schematron.worker.d.ts +50 -0
  37. package/dist_ts/formats/validation/schematron.worker.js +185 -0
  38. package/dist_ts/formats/validation/validation.types.d.ts +163 -0
  39. package/dist_ts/formats/validation/validation.types.js +181 -0
  40. package/dist_ts/formats/validation/vat-categories.validator.d.ts +87 -0
  41. package/dist_ts/formats/validation/vat-categories.validator.js +497 -0
  42. package/dist_ts/formats/validation/xrechnung.validator.d.ts +92 -0
  43. package/dist_ts/formats/validation/xrechnung.validator.js +417 -0
  44. package/dist_ts/interfaces/common.d.ts +1 -0
  45. package/dist_ts/interfaces/en16931-metadata.d.ts +83 -0
  46. package/dist_ts/interfaces/en16931-metadata.js +6 -0
  47. package/dist_ts/plugins.d.ts +3 -1
  48. package/dist_ts/plugins.js +7 -2
  49. package/dist_ts_install/download-schematron.d.ts +6 -0
  50. package/dist_ts_install/download-schematron.js +62 -0
  51. package/dist_ts_install/download-test-samples.d.ts +19 -0
  52. package/dist_ts_install/download-test-samples.js +169 -0
  53. package/dist_ts_install/download-xrechnung-rules.d.ts +7 -0
  54. package/dist_ts_install/download-xrechnung-rules.js +146 -0
  55. package/dist_ts_install/index.d.ts +8 -0
  56. package/dist_ts_install/index.js +246 -0
  57. package/package.json +13 -8
  58. package/readme.md +255 -810
  59. package/ts/00_commitinfo_data.ts +1 -1
  60. package/ts/einvoice.ts +63 -14
  61. package/ts/formats/converters/xml-to-einvoice.converter.ts +142 -0
  62. package/ts/formats/semantic/bt-bg.model.ts +524 -0
  63. package/ts/formats/semantic/semantic.adapter.ts +600 -0
  64. package/ts/formats/semantic/semantic.validator.ts +654 -0
  65. package/ts/formats/utils/currency.calculator.decimal.ts +323 -0
  66. package/ts/formats/utils/currency.utils.ts +299 -0
  67. package/ts/formats/utils/decimal.ts +509 -0
  68. package/ts/formats/validation/codelist.validator.ts +317 -0
  69. package/ts/formats/validation/conformance.harness.ts +591 -0
  70. package/ts/formats/validation/en16931.business-rules.validator.ts +694 -0
  71. package/ts/formats/validation/facturx.validator.ts +579 -0
  72. package/ts/formats/validation/integrated.validator.ts +405 -0
  73. package/ts/formats/validation/peppol.validator.ts +589 -0
  74. package/ts/formats/validation/schematron.downloader.ts +304 -0
  75. package/ts/formats/validation/schematron.integration.ts +285 -0
  76. package/ts/formats/validation/schematron.validator.ts +348 -0
  77. package/ts/formats/validation/schematron.worker.ts +221 -0
  78. package/ts/formats/validation/validation.types.ts +274 -0
  79. package/ts/formats/validation/vat-categories.validator.ts +845 -0
  80. package/ts/formats/validation/xrechnung.validator.ts +494 -0
  81. package/ts/interfaces/common.ts +1 -0
  82. package/ts/interfaces/en16931-metadata.ts +104 -0
  83. package/ts/plugins.ts +8 -0
  84. package/ts/tspublish.json +3 -0
  85. package/dist_ts/classes.decoder.d.ts +0 -40
  86. package/dist_ts/classes.decoder.js +0 -320
  87. package/dist_ts/classes.encoder.d.ts +0 -51
  88. package/dist_ts/classes.encoder.js +0 -293
  89. package/dist_ts/classes.xinvoice.d.ts +0 -136
  90. package/dist_ts/classes.xinvoice.js +0 -352
  91. package/dist_ts/formats/base.decoder.d.ts +0 -19
  92. package/dist_ts/formats/base.decoder.js +0 -130
  93. package/dist_ts/formats/base.validator.d.ts +0 -44
  94. package/dist_ts/formats/base.validator.js +0 -39
  95. package/dist_ts/formats/decoder.factory.d.ts +0 -15
  96. package/dist_ts/formats/decoder.factory.js +0 -46
  97. package/dist_ts/formats/factorx.decoder.d.ts +0 -18
  98. package/dist_ts/formats/factorx.decoder.js +0 -178
  99. package/dist_ts/formats/factorx.encoder.d.ts +0 -51
  100. package/dist_ts/formats/factorx.encoder.js +0 -293
  101. package/dist_ts/formats/facturx.decoder.d.ts +0 -18
  102. package/dist_ts/formats/facturx.decoder.js +0 -210
  103. package/dist_ts/formats/facturx.encoder.d.ts +0 -51
  104. package/dist_ts/formats/facturx.encoder.js +0 -293
  105. package/dist_ts/formats/facturx.validator.d.ts +0 -67
  106. package/dist_ts/formats/facturx.validator.js +0 -266
  107. package/dist_ts/formats/pdf/robust-pdf.extractor.d.ts +0 -40
  108. package/dist_ts/formats/pdf/robust-pdf.extractor.js +0 -324
  109. package/dist_ts/formats/ubl.validator.d.ts +0 -82
  110. package/dist_ts/formats/ubl.validator.js +0 -306
  111. package/dist_ts/formats/validator.factory.d.ts +0 -18
  112. package/dist_ts/formats/validator.factory.js +0 -78
  113. package/dist_ts/formats/xinvoice.decoder.d.ts +0 -28
  114. package/dist_ts/formats/xinvoice.decoder.js +0 -332
  115. package/dist_ts/formats/xinvoice.encoder.d.ts +0 -19
  116. package/dist_ts/formats/xinvoice.encoder.js +0 -282
@@ -0,0 +1,405 @@
1
+ /**
2
+ * Main integrated validator combining all validation capabilities
3
+ * Orchestrates TypeScript validators, Schematron, and profile-specific rules
4
+ */
5
+
6
+ import { IntegratedValidator } from './schematron.integration.js';
7
+ import { XRechnungValidator } from './xrechnung.validator.js';
8
+ import { PeppolValidator } from './peppol.validator.js';
9
+ import { FacturXValidator } from './facturx.validator.js';
10
+ import { EN16931BusinessRulesValidator } from './en16931.business-rules.validator.js';
11
+ import { CodeListValidator } from './codelist.validator.js';
12
+ import type { ValidationResult, ValidationOptions, ValidationReport } from './validation.types.js';
13
+ import type { EInvoice } from '../../einvoice.js';
14
+
15
+ /**
16
+ * Main validator that combines all validation capabilities
17
+ */
18
+ export class MainValidator {
19
+ private integratedValidator: IntegratedValidator;
20
+ private xrechnungValidator: XRechnungValidator;
21
+ private peppolValidator: PeppolValidator;
22
+ private facturxValidator: FacturXValidator;
23
+ private businessRulesValidator: EN16931BusinessRulesValidator;
24
+ private codeListValidator: CodeListValidator;
25
+ private schematronEnabled: boolean = false;
26
+
27
+ constructor() {
28
+ this.integratedValidator = new IntegratedValidator();
29
+ this.xrechnungValidator = XRechnungValidator.create();
30
+ this.peppolValidator = PeppolValidator.create();
31
+ this.facturxValidator = FacturXValidator.create();
32
+ this.businessRulesValidator = new EN16931BusinessRulesValidator();
33
+ this.codeListValidator = new CodeListValidator();
34
+ }
35
+
36
+ /**
37
+ * Initialize Schematron validation for better coverage
38
+ */
39
+ public async initializeSchematron(
40
+ profile?: 'EN16931' | 'PEPPOL' | 'XRECHNUNG'
41
+ ): Promise<void> {
42
+ try {
43
+ // Check available Schematron files
44
+ const available = await this.integratedValidator.getAvailableSchematron();
45
+
46
+ if (available.length === 0) {
47
+ console.warn('No Schematron files available. Run: npm run download-schematron');
48
+ return;
49
+ }
50
+
51
+ // Load appropriate Schematron based on profile
52
+ const standard = profile || 'EN16931';
53
+ const format = 'UBL'; // Default to UBL, can be made configurable
54
+
55
+ await this.integratedValidator.loadSchematron(
56
+ standard === 'XRECHNUNG' ? 'EN16931' : standard, // XRechnung uses EN16931 as base
57
+ format
58
+ );
59
+
60
+ this.schematronEnabled = true;
61
+ console.log(`Schematron validation enabled for ${standard} ${format}`);
62
+ } catch (error) {
63
+ console.warn(`Failed to initialize Schematron: ${error.message}`);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Validate an invoice with all available validators
69
+ */
70
+ public async validate(
71
+ invoice: EInvoice,
72
+ xmlContent?: string,
73
+ options: ValidationOptions = {}
74
+ ): Promise<ValidationReport> {
75
+ const startTime = Date.now();
76
+ const results: ValidationResult[] = [];
77
+
78
+ // Detect profile from invoice
79
+ const profile = this.detectProfile(invoice);
80
+ const mergedOptions: ValidationOptions = {
81
+ ...options,
82
+ profile: profile as ValidationOptions['profile']
83
+ };
84
+
85
+ // Run base validators
86
+ if (options.checkCodeLists !== false) {
87
+ results.push(...this.codeListValidator.validate(invoice));
88
+ }
89
+
90
+ results.push(...this.businessRulesValidator.validate(invoice, mergedOptions));
91
+
92
+ // Run XRechnung-specific validation if applicable
93
+ if (this.isXRechnungInvoice(invoice)) {
94
+ const xrResults = this.xrechnungValidator.validateXRechnung(invoice);
95
+ results.push(...xrResults);
96
+ }
97
+
98
+ // Run PEPPOL-specific validation if applicable
99
+ if (this.isPeppolInvoice(invoice)) {
100
+ const peppolResults = this.peppolValidator.validatePeppol(invoice);
101
+ results.push(...peppolResults);
102
+ }
103
+
104
+ // Run Factur-X specific validation if applicable
105
+ if (this.isFacturXInvoice(invoice)) {
106
+ const facturxResults = this.facturxValidator.validateFacturX(invoice);
107
+ results.push(...facturxResults);
108
+ }
109
+
110
+ // Run Schematron validation if available and XML is provided
111
+ if (this.schematronEnabled && xmlContent) {
112
+ try {
113
+ const schematronReport = await this.integratedValidator.validate(
114
+ invoice,
115
+ xmlContent,
116
+ mergedOptions
117
+ );
118
+ // Extract only Schematron-specific results to avoid duplication
119
+ const schematronResults = schematronReport.results.filter(
120
+ r => r.source === 'SCHEMATRON'
121
+ );
122
+ results.push(...schematronResults);
123
+ } catch (error) {
124
+ console.warn(`Schematron validation error: ${error.message}`);
125
+ }
126
+ }
127
+
128
+ // Remove duplicates (same rule + same field)
129
+ const uniqueResults = this.deduplicateResults(results);
130
+
131
+ // Calculate statistics
132
+ const errorCount = uniqueResults.filter(r => r.severity === 'error').length;
133
+ const warningCount = uniqueResults.filter(r => r.severity === 'warning').length;
134
+ const infoCount = uniqueResults.filter(r => r.severity === 'info').length;
135
+
136
+ // Estimate coverage
137
+ const totalRules = this.estimateTotalRules(profile);
138
+ const rulesChecked = new Set(uniqueResults.map(r => r.ruleId)).size;
139
+ const coverage = totalRules > 0 ? (rulesChecked / totalRules) * 100 : 0;
140
+
141
+ return {
142
+ valid: errorCount === 0,
143
+ profile: profile || 'EN16931',
144
+ timestamp: new Date().toISOString(),
145
+ validatorVersion: '2.0.0',
146
+ rulesetVersion: '1.3.14',
147
+ results: uniqueResults,
148
+ errorCount,
149
+ warningCount,
150
+ infoCount,
151
+ rulesChecked,
152
+ rulesTotal: totalRules,
153
+ coverage,
154
+ validationTime: Date.now() - startTime,
155
+ documentId: invoice.accountingDocId,
156
+ documentType: invoice.accountingDocType,
157
+ format: this.detectFormat(xmlContent)
158
+ } as ValidationReport & { schematronEnabled: boolean };
159
+ }
160
+
161
+ /**
162
+ * Detect profile from invoice metadata
163
+ */
164
+ private detectProfile(invoice: EInvoice): string {
165
+ const profileId = invoice.metadata?.profileId || '';
166
+ const customizationId = invoice.metadata?.customizationId || '';
167
+
168
+ if (profileId.includes('xrechnung') || customizationId.includes('xrechnung')) {
169
+ return 'XRECHNUNG_3.0';
170
+ }
171
+
172
+ if (profileId.includes('peppol') || customizationId.includes('peppol') ||
173
+ profileId.includes('urn:fdc:peppol.eu')) {
174
+ return 'PEPPOL_BIS_3.0';
175
+ }
176
+
177
+ if (profileId.includes('facturx') || customizationId.includes('facturx') ||
178
+ profileId.includes('zugferd')) {
179
+ // Try to detect specific Factur-X profile
180
+ const facturxProfile = this.facturxValidator.detectProfile(invoice);
181
+ if (facturxProfile) {
182
+ return `FACTURX_${facturxProfile}`;
183
+ }
184
+ return 'FACTURX_EN16931';
185
+ }
186
+
187
+ return 'EN16931';
188
+ }
189
+
190
+ /**
191
+ * Check if invoice is XRechnung
192
+ */
193
+ private isXRechnungInvoice(invoice: EInvoice): boolean {
194
+ const profileId = invoice.metadata?.profileId || '';
195
+ const customizationId = invoice.metadata?.customizationId || '';
196
+
197
+ const xrechnungProfiles = [
198
+ 'urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung',
199
+ 'urn:cen.eu:en16931:2017#conformant#urn:xeinkauf.de:kosit:xrechnung',
200
+ 'xrechnung'
201
+ ];
202
+
203
+ return xrechnungProfiles.some(profile =>
204
+ profileId.toLowerCase().includes(profile.toLowerCase()) ||
205
+ customizationId.toLowerCase().includes(profile.toLowerCase())
206
+ );
207
+ }
208
+
209
+ /**
210
+ * Check if invoice is PEPPOL
211
+ */
212
+ private isPeppolInvoice(invoice: EInvoice): boolean {
213
+ const profileId = invoice.metadata?.profileId || '';
214
+ const customizationId = invoice.metadata?.customizationId || '';
215
+
216
+ const peppolProfiles = [
217
+ 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
218
+ 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
219
+ 'peppol-bis-3',
220
+ 'peppol'
221
+ ];
222
+
223
+ return peppolProfiles.some(profile =>
224
+ profileId.toLowerCase().includes(profile.toLowerCase()) ||
225
+ customizationId.toLowerCase().includes(profile.toLowerCase())
226
+ );
227
+ }
228
+
229
+ /**
230
+ * Check if invoice is Factur-X
231
+ */
232
+ private isFacturXInvoice(invoice: EInvoice): boolean {
233
+ const profileId = invoice.metadata?.profileId || '';
234
+ const customizationId = invoice.metadata?.customizationId || '';
235
+ const format = invoice.metadata?.format;
236
+
237
+ return format?.includes('facturx') ||
238
+ profileId.toLowerCase().includes('facturx') ||
239
+ customizationId.toLowerCase().includes('facturx') ||
240
+ profileId.toLowerCase().includes('zugferd') ||
241
+ customizationId.toLowerCase().includes('zugferd');
242
+ }
243
+
244
+ /**
245
+ * Detect format from XML content
246
+ */
247
+ private detectFormat(xmlContent?: string): 'UBL' | 'CII' | undefined {
248
+ if (!xmlContent) return undefined;
249
+
250
+ if (xmlContent.includes('urn:oasis:names:specification:ubl:schema:xsd:Invoice-2')) {
251
+ return 'UBL';
252
+ } else if (xmlContent.includes('urn:un:unece:uncefact:data:standard:CrossIndustryInvoice')) {
253
+ return 'CII';
254
+ }
255
+
256
+ return undefined;
257
+ }
258
+
259
+ /**
260
+ * Remove duplicate validation results
261
+ */
262
+ private deduplicateResults(results: ValidationResult[]): ValidationResult[] {
263
+ const seen = new Set<string>();
264
+ const unique: ValidationResult[] = [];
265
+
266
+ for (const result of results) {
267
+ const key = `${result.ruleId}|${result.field || ''}|${result.message}`;
268
+ if (!seen.has(key)) {
269
+ seen.add(key);
270
+ unique.push(result);
271
+ }
272
+ }
273
+
274
+ return unique;
275
+ }
276
+
277
+ /**
278
+ * Estimate total rules for coverage calculation
279
+ */
280
+ private estimateTotalRules(profile?: string): number {
281
+ const ruleCounts: Record<string, number> = {
282
+ EN16931: 150,
283
+ 'PEPPOL_BIS_3.0': 250,
284
+ 'XRECHNUNG_3.0': 280,
285
+ FACTURX_BASIC: 100,
286
+ FACTURX_EN16931: 150
287
+ };
288
+
289
+ return ruleCounts[profile || 'EN16931'] || 150;
290
+ }
291
+
292
+ /**
293
+ * Validate with automatic format and profile detection
294
+ */
295
+ public async validateAuto(
296
+ invoice: EInvoice,
297
+ xmlContent?: string
298
+ ): Promise<ValidationReport> {
299
+ // Auto-detect profile
300
+ const profile = this.detectProfile(invoice);
301
+
302
+ // Initialize Schematron if not already done
303
+ if (!this.schematronEnabled && xmlContent) {
304
+ await this.initializeSchematron(
305
+ profile.startsWith('XRECHNUNG') ? 'XRECHNUNG' :
306
+ profile.startsWith('PEPPOL') ? 'PEPPOL' : 'EN16931'
307
+ );
308
+ }
309
+
310
+ return this.validate(invoice, xmlContent, {
311
+ checkCalculations: true,
312
+ checkVAT: true,
313
+ checkCodeLists: true,
314
+ strictMode: profile.includes('XRECHNUNG') // Strict for XRechnung
315
+ });
316
+ }
317
+
318
+ /**
319
+ * Get validation capabilities
320
+ */
321
+ public getCapabilities(): {
322
+ schematron: boolean;
323
+ xrechnung: boolean;
324
+ peppol: boolean;
325
+ facturx: boolean;
326
+ calculations: boolean;
327
+ codeLists: boolean;
328
+ } {
329
+ return {
330
+ schematron: this.schematronEnabled,
331
+ xrechnung: true,
332
+ peppol: true,
333
+ facturx: true,
334
+ calculations: true,
335
+ codeLists: true
336
+ };
337
+ }
338
+
339
+ /**
340
+ * Format validation report as text
341
+ */
342
+ public formatReport(report: ValidationReport): string {
343
+ const lines: string[] = [];
344
+
345
+ lines.push('=== Validation Report ===');
346
+ lines.push(`Profile: ${report.profile}`);
347
+ lines.push(`Valid: ${report.valid ? '✅' : '❌'}`);
348
+ lines.push(`Timestamp: ${report.timestamp}`);
349
+ lines.push('');
350
+
351
+ if (report.errorCount > 0) {
352
+ lines.push(`Errors: ${report.errorCount}`);
353
+ report.results
354
+ .filter(r => r.severity === 'error')
355
+ .forEach(r => {
356
+ lines.push(` ❌ [${r.ruleId}] ${r.message}`);
357
+ if (r.field) lines.push(` Field: ${r.field}`);
358
+ });
359
+ lines.push('');
360
+ }
361
+
362
+ if (report.warningCount > 0) {
363
+ lines.push(`Warnings: ${report.warningCount}`);
364
+ report.results
365
+ .filter(r => r.severity === 'warning')
366
+ .forEach(r => {
367
+ lines.push(` ⚠️ [${r.ruleId}] ${r.message}`);
368
+ if (r.field) lines.push(` Field: ${r.field}`);
369
+ });
370
+ lines.push('');
371
+ }
372
+
373
+ lines.push('Statistics:');
374
+ lines.push(` Rules checked: ${report.rulesChecked}/${report.rulesTotal}`);
375
+ lines.push(` Coverage: ${report.coverage.toFixed(1)}%`);
376
+ lines.push(` Validation time: ${report.validationTime}ms`);
377
+
378
+ if ((report as any).schematronEnabled) {
379
+ lines.push(' Schematron: ✅ Enabled');
380
+ }
381
+
382
+ return lines.join('\n');
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Create a pre-configured validator instance
388
+ */
389
+ export async function createValidator(
390
+ options: {
391
+ profile?: 'EN16931' | 'PEPPOL' | 'XRECHNUNG';
392
+ enableSchematron?: boolean;
393
+ } = {}
394
+ ): Promise<MainValidator> {
395
+ const validator = new MainValidator();
396
+
397
+ if (options.enableSchematron !== false) {
398
+ await validator.initializeSchematron(options.profile);
399
+ }
400
+
401
+ return validator;
402
+ }
403
+
404
+ // Export for convenience
405
+ export type { ValidationReport, ValidationResult, ValidationOptions } from './validation.types.js';