@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,304 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import * as path from 'path';
3
+ import { promises as fs } from 'fs';
4
+
5
+ /**
6
+ * Schematron rule sources
7
+ */
8
+ export interface SchematronSource {
9
+ name: string;
10
+ version: string;
11
+ url: string;
12
+ description: string;
13
+ format: 'UBL' | 'CII' | 'BOTH';
14
+ }
15
+
16
+ /**
17
+ * Official Schematron sources for e-invoicing standards
18
+ */
19
+ export const SCHEMATRON_SOURCES: Record<string, SchematronSource[]> = {
20
+ EN16931: [
21
+ {
22
+ name: 'EN16931-UBL',
23
+ version: '1.3.14',
24
+ url: 'https://github.com/ConnectingEurope/eInvoicing-EN16931/raw/master/ubl/schematron/EN16931-UBL-validation.sch',
25
+ description: 'Official EN16931 validation rules for UBL format',
26
+ format: 'UBL'
27
+ },
28
+ {
29
+ name: 'EN16931-CII',
30
+ version: '1.3.14',
31
+ url: 'https://github.com/ConnectingEurope/eInvoicing-EN16931/raw/master/cii/schematron/EN16931-CII-validation.sch',
32
+ description: 'Official EN16931 validation rules for CII format',
33
+ format: 'CII'
34
+ },
35
+ {
36
+ name: 'EN16931-EDIFACT',
37
+ version: '1.3.14',
38
+ url: 'https://github.com/ConnectingEurope/eInvoicing-EN16931/raw/master/edifact/schematron/EN16931-EDIFACT-validation.sch',
39
+ description: 'Official EN16931 validation rules for EDIFACT format',
40
+ format: 'CII'
41
+ }
42
+ ],
43
+ XRECHNUNG: [
44
+ {
45
+ name: 'XRechnung-UBL',
46
+ version: '3.0.2',
47
+ url: 'https://github.com/itplr-kosit/xrechnung-schematron/raw/master/src/validation/schematron/ubl/XRechnung-UBL-validation.sch',
48
+ description: 'XRechnung CIUS validation for UBL',
49
+ format: 'UBL'
50
+ },
51
+ {
52
+ name: 'XRechnung-CII',
53
+ version: '3.0.2',
54
+ url: 'https://github.com/itplr-kosit/xrechnung-schematron/raw/master/src/validation/schematron/cii/XRechnung-CII-validation.sch',
55
+ description: 'XRechnung CIUS validation for CII',
56
+ format: 'CII'
57
+ }
58
+ ],
59
+ PEPPOL: [
60
+ {
61
+ name: 'PEPPOL-EN16931-UBL',
62
+ version: '3.0.17',
63
+ url: 'https://github.com/OpenPEPPOL/peppol-bis-invoice-3/raw/master/rules/sch/PEPPOL-EN16931-UBL.sch',
64
+ description: 'PEPPOL BIS Billing 3.0 validation rules for UBL',
65
+ format: 'UBL'
66
+ },
67
+ {
68
+ name: 'PEPPOL-EN16931-CII',
69
+ version: '3.0.17',
70
+ url: 'https://github.com/OpenPEPPOL/peppol-bis-invoice-3/raw/master/rules/sch/PEPPOL-EN16931-CII.sch',
71
+ description: 'PEPPOL BIS Billing 3.0 validation rules for CII',
72
+ format: 'CII'
73
+ }
74
+ ]
75
+ };
76
+
77
+ /**
78
+ * Schematron downloader and cache manager
79
+ */
80
+ export class SchematronDownloader {
81
+ private cacheDir: string;
82
+ private smartfile: any;
83
+
84
+ constructor(cacheDir: string = 'assets_downloaded/schematron') {
85
+ this.cacheDir = cacheDir;
86
+ }
87
+
88
+ /**
89
+ * Initialize the downloader
90
+ */
91
+ public async initialize(): Promise<void> {
92
+ // Ensure cache directory exists
93
+ this.smartfile = await import('@push.rocks/smartfile');
94
+ await fs.mkdir(this.cacheDir, { recursive: true });
95
+ }
96
+
97
+ /**
98
+ * Download a Schematron file
99
+ */
100
+ public async download(source: SchematronSource): Promise<string> {
101
+ const fileName = `${source.name}-v${source.version}.sch`;
102
+ const filePath = path.join(this.cacheDir, fileName);
103
+
104
+ // Check if already cached
105
+ if (await this.isCached(filePath)) {
106
+ console.log(`Using cached Schematron: ${fileName}`);
107
+ return filePath;
108
+ }
109
+
110
+ console.log(`Downloading Schematron: ${source.name} v${source.version}`);
111
+
112
+ try {
113
+ // Download the file
114
+ const response = await fetch(source.url);
115
+ if (!response.ok) {
116
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
117
+ }
118
+
119
+ const content = await response.text();
120
+
121
+ // Validate it's actually Schematron
122
+ if (!content.includes('schematron') && !content.includes('sch:schema')) {
123
+ throw new Error('Downloaded file does not appear to be Schematron');
124
+ }
125
+
126
+ // Save to cache
127
+ await fs.writeFile(filePath, content, 'utf-8');
128
+
129
+ // Also save metadata
130
+ const metaPath = filePath.replace('.sch', '.meta.json');
131
+ await fs.writeFile(metaPath, JSON.stringify({
132
+ source: source.name,
133
+ version: source.version,
134
+ url: source.url,
135
+ format: source.format,
136
+ downloadDate: new Date().toISOString()
137
+ }, null, 2), 'utf-8');
138
+
139
+ console.log(`Successfully downloaded: ${fileName}`);
140
+ return filePath;
141
+ } catch (error) {
142
+ throw new Error(`Failed to download ${source.name}: ${error.message}`);
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Download all Schematron files for a standard
148
+ */
149
+ public async downloadStandard(
150
+ standard: 'EN16931' | 'XRECHNUNG' | 'PEPPOL'
151
+ ): Promise<string[]> {
152
+ const sources = SCHEMATRON_SOURCES[standard];
153
+ if (!sources) {
154
+ throw new Error(`Unknown standard: ${standard}`);
155
+ }
156
+
157
+ const paths: string[] = [];
158
+ for (const source of sources) {
159
+ try {
160
+ const path = await this.download(source);
161
+ paths.push(path);
162
+ } catch (error) {
163
+ console.warn(`Failed to download ${source.name}: ${error.message}`);
164
+ }
165
+ }
166
+
167
+ return paths;
168
+ }
169
+
170
+ /**
171
+ * Check if a file is cached
172
+ */
173
+ private async isCached(filePath: string): Promise<boolean> {
174
+ try {
175
+ await fs.access(filePath);
176
+
177
+ // Check if file is not empty
178
+ const stats = await fs.stat(filePath);
179
+ return stats.size > 0;
180
+ } catch {
181
+ return false;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Get cached Schematron files
187
+ */
188
+ public async getCachedFiles(): Promise<Array<{
189
+ path: string;
190
+ metadata: any;
191
+ }>> {
192
+ const files: Array<{ path: string; metadata: any }> = [];
193
+
194
+ try {
195
+ const entries = await fs.readdir(this.cacheDir);
196
+
197
+ for (const entry of entries) {
198
+ if (entry.endsWith('.sch')) {
199
+ const filePath = path.join(this.cacheDir, entry);
200
+ const metaPath = filePath.replace('.sch', '.meta.json');
201
+
202
+ try {
203
+ const metadata = JSON.parse(await fs.readFile(metaPath, 'utf-8'));
204
+ files.push({ path: filePath, metadata });
205
+ } catch {
206
+ // No metadata file
207
+ files.push({ path: filePath, metadata: null });
208
+ }
209
+ }
210
+ }
211
+ } catch (error) {
212
+ console.warn(`Failed to list cached files: ${error.message}`);
213
+ }
214
+
215
+ return files;
216
+ }
217
+
218
+ /**
219
+ * Clear cache
220
+ */
221
+ public async clearCache(): Promise<void> {
222
+ try {
223
+ const entries = await fs.readdir(this.cacheDir);
224
+
225
+ for (const entry of entries) {
226
+ if (entry.endsWith('.sch') || entry.endsWith('.meta.json')) {
227
+ await fs.unlink(path.join(this.cacheDir, entry));
228
+ }
229
+ }
230
+
231
+ console.log('Schematron cache cleared');
232
+ } catch (error) {
233
+ console.warn(`Failed to clear cache: ${error.message}`);
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Get the appropriate Schematron for a format
239
+ */
240
+ public async getSchematronForFormat(
241
+ standard: 'EN16931' | 'XRECHNUNG' | 'PEPPOL',
242
+ format: 'UBL' | 'CII'
243
+ ): Promise<string | null> {
244
+ const sources = SCHEMATRON_SOURCES[standard];
245
+ if (!sources) return null;
246
+
247
+ const source = sources.find(s => s.format === format || s.format === 'BOTH');
248
+ if (!source) return null;
249
+
250
+ return await this.download(source);
251
+ }
252
+
253
+ /**
254
+ * Update all cached Schematron files
255
+ */
256
+ public async updateAll(): Promise<void> {
257
+ console.log('Updating all Schematron files...');
258
+
259
+ for (const standard of ['EN16931', 'XRECHNUNG', 'PEPPOL'] as const) {
260
+ await this.downloadStandard(standard);
261
+ }
262
+
263
+ console.log('All Schematron files updated');
264
+ }
265
+ }
266
+
267
+ /**
268
+ * ISO Schematron skeleton URLs
269
+ * These are needed to compile Schematron to XSLT
270
+ */
271
+ export const ISO_SCHEMATRON_SKELETONS = {
272
+ 'iso_dsdl_include.xsl': 'https://github.com/Schematron/schematron/raw/master/trunk/schematron/code/iso_dsdl_include.xsl',
273
+ 'iso_abstract_expand.xsl': 'https://github.com/Schematron/schematron/raw/master/trunk/schematron/code/iso_abstract_expand.xsl',
274
+ 'iso_svrl_for_xslt2.xsl': 'https://github.com/Schematron/schematron/raw/master/trunk/schematron/code/iso_svrl_for_xslt2.xsl',
275
+ 'iso_schematron_skeleton_for_saxon.xsl': 'https://github.com/Schematron/schematron/raw/master/trunk/schematron/code/iso_schematron_skeleton_for_saxon.xsl'
276
+ };
277
+
278
+ /**
279
+ * Download ISO Schematron skeleton files
280
+ */
281
+ export async function downloadISOSkeletons(targetDir: string = 'assets_downloaded/schematron/iso'): Promise<void> {
282
+ await fs.mkdir(targetDir, { recursive: true });
283
+
284
+ console.log('Downloading ISO Schematron skeleton files...');
285
+
286
+ for (const [name, url] of Object.entries(ISO_SCHEMATRON_SKELETONS)) {
287
+ try {
288
+ const response = await fetch(url);
289
+ if (!response.ok) {
290
+ throw new Error(`HTTP ${response.status}`);
291
+ }
292
+
293
+ const content = await response.text();
294
+ const filePath = path.join(targetDir, name);
295
+ await fs.writeFile(filePath, content, 'utf-8');
296
+
297
+ console.log(`Downloaded: ${name}`);
298
+ } catch (error) {
299
+ console.warn(`Failed to download ${name}: ${error.message}`);
300
+ }
301
+ }
302
+
303
+ console.log('ISO Schematron skeleton download complete');
304
+ }
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Integration of official Schematron validation with the EInvoice module
3
+ */
4
+
5
+ import { SchematronValidator, HybridValidator } from './schematron.validator.js';
6
+ import { EN16931BusinessRulesValidator } from './en16931.business-rules.validator.js';
7
+ import { CodeListValidator } from './codelist.validator.js';
8
+ import type { ValidationResult, ValidationOptions, ValidationReport } from './validation.types.js';
9
+ import type { EInvoice } from '../../einvoice.js';
10
+ import * as path from 'path';
11
+ import { promises as fs } from 'fs';
12
+
13
+ /**
14
+ * Integrated validator combining TypeScript and Schematron validation
15
+ */
16
+ export class IntegratedValidator {
17
+ private hybridValidator: HybridValidator;
18
+ private schematronValidator: SchematronValidator;
19
+ private businessRulesValidator: EN16931BusinessRulesValidator;
20
+ private codeListValidator: CodeListValidator;
21
+ private schematronLoaded: boolean = false;
22
+
23
+ constructor() {
24
+ this.schematronValidator = new SchematronValidator();
25
+ this.hybridValidator = new HybridValidator(this.schematronValidator);
26
+ this.businessRulesValidator = new EN16931BusinessRulesValidator();
27
+ this.codeListValidator = new CodeListValidator();
28
+
29
+ // Add TypeScript validators to hybrid pipeline
30
+ this.setupTypeScriptValidators();
31
+ }
32
+
33
+ /**
34
+ * Setup TypeScript validators in the hybrid pipeline
35
+ */
36
+ private setupTypeScriptValidators(): void {
37
+ // Wrap business rules validator
38
+ this.hybridValidator.addTSValidator({
39
+ validate: (xml: string) => {
40
+ // Note: This would need the invoice object, not XML
41
+ // In practice, we'd parse the XML to EInvoice first
42
+ return [];
43
+ }
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Load Schematron for a specific format and standard
49
+ */
50
+ public async loadSchematron(
51
+ standard: 'EN16931' | 'PEPPOL' | 'XRECHNUNG',
52
+ format: 'UBL' | 'CII'
53
+ ): Promise<void> {
54
+ const schematronPath = await this.getSchematronPath(standard, format);
55
+
56
+ if (!schematronPath) {
57
+ throw new Error(`No Schematron available for ${standard} ${format}`);
58
+ }
59
+
60
+ // Check if file exists
61
+ try {
62
+ await fs.access(schematronPath);
63
+ } catch {
64
+ throw new Error(`Schematron file not found: ${schematronPath}. Run 'npm run download-schematron' first.`);
65
+ }
66
+
67
+ await this.schematronValidator.loadSchematron(schematronPath, true);
68
+ this.schematronLoaded = true;
69
+ }
70
+
71
+ /**
72
+ * Get the path to the appropriate Schematron file
73
+ */
74
+ private async getSchematronPath(
75
+ standard: 'EN16931' | 'PEPPOL' | 'XRECHNUNG',
76
+ format: 'UBL' | 'CII'
77
+ ): Promise<string | null> {
78
+ const basePath = 'assets_downloaded/schematron';
79
+
80
+ // Map standard and format to file pattern
81
+ const patterns: Record<string, Record<string, string>> = {
82
+ EN16931: {
83
+ UBL: 'EN16931-UBL-*.sch',
84
+ CII: 'EN16931-CII-*.sch'
85
+ },
86
+ PEPPOL: {
87
+ UBL: 'PEPPOL-EN16931-UBL-*.sch',
88
+ CII: 'PEPPOL-EN16931-CII-*.sch'
89
+ },
90
+ XRECHNUNG: {
91
+ UBL: 'XRechnung-UBL-*.sch',
92
+ CII: 'XRechnung-CII-*.sch'
93
+ }
94
+ };
95
+
96
+ const pattern = patterns[standard]?.[format];
97
+ if (!pattern) return null;
98
+
99
+ // Find matching files
100
+ try {
101
+ const files = await fs.readdir(basePath);
102
+ const regex = new RegExp(pattern.replace('*', '.*'));
103
+ const matches = files.filter(f => regex.test(f));
104
+
105
+ if (matches.length > 0) {
106
+ // Return the most recent version (lexicographically last)
107
+ matches.sort();
108
+ return path.join(basePath, matches[matches.length - 1]);
109
+ }
110
+ } catch {
111
+ // Directory doesn't exist
112
+ }
113
+
114
+ return null;
115
+ }
116
+
117
+ /**
118
+ * Validate an invoice using all available validators
119
+ */
120
+ public async validate(
121
+ invoice: EInvoice,
122
+ xmlContent?: string,
123
+ options: ValidationOptions = {}
124
+ ): Promise<ValidationReport> {
125
+ const startTime = Date.now();
126
+ const results: ValidationResult[] = [];
127
+
128
+ // Determine format hint
129
+ const formatHint = options.formatHint || this.detectFormat(xmlContent);
130
+
131
+ // Run TypeScript validators
132
+ if (options.checkCodeLists !== false) {
133
+ results.push(...this.codeListValidator.validate(invoice));
134
+ }
135
+
136
+ results.push(...this.businessRulesValidator.validate(invoice, options));
137
+
138
+ // Run Schematron validation if XML is provided and Schematron is loaded
139
+ if (xmlContent && this.schematronLoaded) {
140
+ try {
141
+ const schematronResults = await this.schematronValidator.validate(xmlContent, {
142
+ includeWarnings: !options.strictMode,
143
+ parameters: {
144
+ profile: options.profile
145
+ }
146
+ });
147
+ results.push(...schematronResults);
148
+ } catch (error) {
149
+ console.warn(`Schematron validation failed: ${error.message}`);
150
+ }
151
+ }
152
+
153
+ // Calculate statistics
154
+ const errorCount = results.filter(r => r.severity === 'error').length;
155
+ const warningCount = results.filter(r => r.severity === 'warning').length;
156
+ const infoCount = results.filter(r => r.severity === 'info').length;
157
+
158
+ // Estimate rule coverage
159
+ const totalRules = this.estimateTotalRules(options.profile);
160
+ const rulesChecked = new Set(results.map(r => r.ruleId)).size;
161
+
162
+ return {
163
+ valid: errorCount === 0,
164
+ profile: options.profile || 'EN16931',
165
+ timestamp: new Date().toISOString(),
166
+ validatorVersion: '1.0.0',
167
+ rulesetVersion: '1.3.14',
168
+ results,
169
+ errorCount,
170
+ warningCount,
171
+ infoCount,
172
+ rulesChecked,
173
+ rulesTotal: totalRules,
174
+ coverage: (rulesChecked / totalRules) * 100,
175
+ validationTime: Date.now() - startTime,
176
+ documentId: invoice.accountingDocId,
177
+ documentType: invoice.accountingDocType,
178
+ format: formatHint
179
+ };
180
+ }
181
+
182
+ /**
183
+ * Detect format from XML content
184
+ */
185
+ private detectFormat(xmlContent?: string): 'UBL' | 'CII' | undefined {
186
+ if (!xmlContent) return undefined;
187
+
188
+ if (xmlContent.includes('urn:oasis:names:specification:ubl:schema:xsd:Invoice-2')) {
189
+ return 'UBL';
190
+ } else if (xmlContent.includes('urn:un:unece:uncefact:data:standard:CrossIndustryInvoice')) {
191
+ return 'CII';
192
+ }
193
+
194
+ return undefined;
195
+ }
196
+
197
+ /**
198
+ * Estimate total number of rules for a profile
199
+ */
200
+ private estimateTotalRules(profile?: string): number {
201
+ const ruleCounts: Record<string, number> = {
202
+ EN16931: 150,
203
+ PEPPOL_BIS_3_0: 250,
204
+ XRECHNUNG_3_0: 280,
205
+ FACTURX_BASIC: 100,
206
+ FACTURX_EN16931: 150
207
+ };
208
+
209
+ return ruleCounts[profile || 'EN16931'] || 150;
210
+ }
211
+
212
+ /**
213
+ * Validate with automatic format detection
214
+ */
215
+ public async validateAuto(
216
+ invoice: EInvoice,
217
+ xmlContent?: string
218
+ ): Promise<ValidationReport> {
219
+ // Auto-detect format
220
+ const format = this.detectFormat(xmlContent);
221
+
222
+ // Try to load appropriate Schematron
223
+ if (format && !this.schematronLoaded) {
224
+ try {
225
+ await this.loadSchematron('EN16931', format);
226
+ } catch (error) {
227
+ console.warn(`Could not load Schematron: ${error.message}`);
228
+ }
229
+ }
230
+
231
+ return this.validate(invoice, xmlContent, {
232
+ formatHint: format,
233
+ checkCalculations: true,
234
+ checkVAT: true,
235
+ checkCodeLists: true
236
+ });
237
+ }
238
+
239
+ /**
240
+ * Check if Schematron validation is available
241
+ */
242
+ public hasSchematron(): boolean {
243
+ return this.schematronLoaded;
244
+ }
245
+
246
+ /**
247
+ * Get available Schematron files
248
+ */
249
+ public async getAvailableSchematron(): Promise<Array<{
250
+ standard: string;
251
+ format: string;
252
+ path: string;
253
+ }>> {
254
+ const available: Array<{ standard: string; format: string; path: string }> = [];
255
+
256
+ for (const standard of ['EN16931', 'PEPPOL', 'XRECHNUNG'] as const) {
257
+ for (const format of ['UBL', 'CII'] as const) {
258
+ const schematronPath = await this.getSchematronPath(standard, format);
259
+ if (schematronPath) {
260
+ available.push({ standard, format, path: schematronPath });
261
+ }
262
+ }
263
+ }
264
+
265
+ return available;
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Create a pre-configured validator for a specific standard
271
+ */
272
+ export async function createStandardValidator(
273
+ standard: 'EN16931' | 'PEPPOL' | 'XRECHNUNG',
274
+ format: 'UBL' | 'CII'
275
+ ): Promise<IntegratedValidator> {
276
+ const validator = new IntegratedValidator();
277
+
278
+ try {
279
+ await validator.loadSchematron(standard, format);
280
+ } catch (error) {
281
+ console.warn(`Schematron not available for ${standard} ${format}: ${error.message}`);
282
+ }
283
+
284
+ return validator;
285
+ }