@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
|
@@ -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';
|