@fin.cx/einvoice 5.0.3 ā 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.
- 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/package.json +9 -3
- 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,471 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conformance Test Harness for EN16931 Validation
|
|
3
|
+
* Tests validators against official samples and generates coverage reports
|
|
4
|
+
*/
|
|
5
|
+
import * as plugins from '../../plugins.js';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { IntegratedValidator } from './schematron.integration.js';
|
|
9
|
+
import { EN16931BusinessRulesValidator } from './en16931.business-rules.validator.js';
|
|
10
|
+
import { CodeListValidator } from './codelist.validator.js';
|
|
11
|
+
import { VATCategoriesValidator } from './vat-categories.validator.js';
|
|
12
|
+
import { XMLToEInvoiceConverter } from '../converters/xml-to-einvoice.converter.js';
|
|
13
|
+
/**
|
|
14
|
+
* Conformance Test Harness
|
|
15
|
+
*/
|
|
16
|
+
export class ConformanceTestHarness {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.testSamples = [];
|
|
19
|
+
this.results = [];
|
|
20
|
+
this.integratedValidator = new IntegratedValidator();
|
|
21
|
+
this.businessRulesValidator = new EN16931BusinessRulesValidator();
|
|
22
|
+
this.codeListValidator = new CodeListValidator();
|
|
23
|
+
this.vatCategoriesValidator = new VATCategoriesValidator();
|
|
24
|
+
this.xmlConverter = new XMLToEInvoiceConverter();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Load test samples from directory
|
|
28
|
+
*/
|
|
29
|
+
async loadTestSamples(baseDir = 'test-samples') {
|
|
30
|
+
this.testSamples = [];
|
|
31
|
+
// Load PEPPOL BIS 3.0 samples
|
|
32
|
+
const peppolDir = path.join(baseDir, 'peppol-bis3');
|
|
33
|
+
if (fs.existsSync(peppolDir)) {
|
|
34
|
+
const peppolFiles = fs.readdirSync(peppolDir);
|
|
35
|
+
for (const file of peppolFiles) {
|
|
36
|
+
if (file.endsWith('.xml')) {
|
|
37
|
+
this.testSamples.push({
|
|
38
|
+
id: `peppol-${path.basename(file, '.xml')}`,
|
|
39
|
+
name: file,
|
|
40
|
+
path: path.join(peppolDir, file),
|
|
41
|
+
format: 'UBL',
|
|
42
|
+
standard: 'PEPPOL-BIS-3.0',
|
|
43
|
+
expectedValid: true,
|
|
44
|
+
description: this.getDescriptionFromFilename(file),
|
|
45
|
+
focusRules: this.getFocusRulesFromFilename(file)
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Load CEN TC434 samples
|
|
51
|
+
const cenDir = path.join(baseDir, 'cen-tc434');
|
|
52
|
+
if (fs.existsSync(cenDir)) {
|
|
53
|
+
const cenFiles = fs.readdirSync(cenDir);
|
|
54
|
+
for (const file of cenFiles) {
|
|
55
|
+
if (file.endsWith('.xml')) {
|
|
56
|
+
const format = file.includes('ubl') ? 'UBL' : 'CII';
|
|
57
|
+
this.testSamples.push({
|
|
58
|
+
id: `cen-${path.basename(file, '.xml')}`,
|
|
59
|
+
name: file,
|
|
60
|
+
path: path.join(cenDir, file),
|
|
61
|
+
format,
|
|
62
|
+
standard: 'EN16931',
|
|
63
|
+
expectedValid: true,
|
|
64
|
+
description: `CEN TC434 ${format} example`
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
console.log(`Loaded ${this.testSamples.length} test samples`);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Run all validators against a single test sample
|
|
73
|
+
*/
|
|
74
|
+
async runTestSample(sample) {
|
|
75
|
+
const startTime = Date.now();
|
|
76
|
+
const result = {
|
|
77
|
+
sampleId: sample.id,
|
|
78
|
+
sampleName: sample.name,
|
|
79
|
+
passed: false,
|
|
80
|
+
errors: [],
|
|
81
|
+
warnings: [],
|
|
82
|
+
rulesTriggered: [],
|
|
83
|
+
executionTime: 0,
|
|
84
|
+
validatorResults: {
|
|
85
|
+
typescript: [],
|
|
86
|
+
schematron: [],
|
|
87
|
+
vatCategories: [],
|
|
88
|
+
codeLists: []
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
try {
|
|
92
|
+
// Read XML content
|
|
93
|
+
const xmlContent = fs.readFileSync(sample.path, 'utf-8');
|
|
94
|
+
// Convert XML to EInvoice
|
|
95
|
+
const invoice = await this.xmlConverter.convert(xmlContent, sample.format);
|
|
96
|
+
// Run TypeScript validators
|
|
97
|
+
const businessRules = this.businessRulesValidator.validate(invoice);
|
|
98
|
+
result.validatorResults.typescript = businessRules;
|
|
99
|
+
const codeLists = this.codeListValidator.validate(invoice);
|
|
100
|
+
result.validatorResults.codeLists = codeLists;
|
|
101
|
+
const vatCategories = this.vatCategoriesValidator.validate(invoice);
|
|
102
|
+
result.validatorResults.vatCategories = vatCategories;
|
|
103
|
+
// Try to run Schematron if available
|
|
104
|
+
try {
|
|
105
|
+
await this.integratedValidator.loadSchematron('EN16931', sample.format);
|
|
106
|
+
const report = await this.integratedValidator.validate(invoice, xmlContent);
|
|
107
|
+
result.validatorResults.schematron = report.results.filter(r => r.source === 'Schematron');
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.warn(`Schematron not available for ${sample.format}: ${error.message}`);
|
|
111
|
+
}
|
|
112
|
+
// Aggregate results
|
|
113
|
+
const allResults = [
|
|
114
|
+
...businessRules,
|
|
115
|
+
...codeLists,
|
|
116
|
+
...vatCategories,
|
|
117
|
+
...result.validatorResults.schematron
|
|
118
|
+
];
|
|
119
|
+
result.errors = allResults.filter(r => r.severity === 'error');
|
|
120
|
+
result.warnings = allResults.filter(r => r.severity === 'warning');
|
|
121
|
+
result.rulesTriggered = [...new Set(allResults.map(r => r.ruleId))];
|
|
122
|
+
result.passed = result.errors.length === 0 === sample.expectedValid;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.error(`Error testing ${sample.name}: ${error.message}`);
|
|
126
|
+
result.errors.push({
|
|
127
|
+
ruleId: 'TEST-ERROR',
|
|
128
|
+
source: 'TestHarness',
|
|
129
|
+
severity: 'error',
|
|
130
|
+
message: `Test execution failed: ${error.message}`
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
result.executionTime = Date.now() - startTime;
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Run conformance tests on all samples
|
|
138
|
+
*/
|
|
139
|
+
async runConformanceTests() {
|
|
140
|
+
console.log('\nš¬ Running conformance tests...\n');
|
|
141
|
+
this.results = [];
|
|
142
|
+
for (const sample of this.testSamples) {
|
|
143
|
+
process.stdout.write(`Testing ${sample.name}... `);
|
|
144
|
+
const result = await this.runTestSample(sample);
|
|
145
|
+
this.results.push(result);
|
|
146
|
+
if (result.passed) {
|
|
147
|
+
console.log('ā
PASSED');
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
console.log(`ā FAILED (${result.errors.length} errors)`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
console.log('\n' + '='.repeat(60));
|
|
154
|
+
this.printSummary();
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Generate BR coverage matrix
|
|
158
|
+
*/
|
|
159
|
+
generateCoverageMatrix() {
|
|
160
|
+
// Define all EN16931 business rules
|
|
161
|
+
const allRules = this.getAllEN16931Rules();
|
|
162
|
+
const ruleDetails = new Map();
|
|
163
|
+
// Initialize rule details
|
|
164
|
+
for (const rule of allRules) {
|
|
165
|
+
ruleDetails.set(rule, {
|
|
166
|
+
covered: false,
|
|
167
|
+
samplesCovering: [],
|
|
168
|
+
errorCount: 0,
|
|
169
|
+
warningCount: 0
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
// Process test results
|
|
173
|
+
for (const result of this.results) {
|
|
174
|
+
for (const ruleId of result.rulesTriggered) {
|
|
175
|
+
if (ruleDetails.has(ruleId)) {
|
|
176
|
+
const detail = ruleDetails.get(ruleId);
|
|
177
|
+
detail.covered = true;
|
|
178
|
+
detail.samplesCovering.push(result.sampleId);
|
|
179
|
+
detail.errorCount += result.errors.filter(e => e.ruleId === ruleId).length;
|
|
180
|
+
detail.warningCount += result.warnings.filter(w => w.ruleId === ruleId).length;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Calculate coverage by category
|
|
185
|
+
const categories = {
|
|
186
|
+
document: { total: 0, covered: 0 },
|
|
187
|
+
calculation: { total: 0, covered: 0 },
|
|
188
|
+
vat: { total: 0, covered: 0 },
|
|
189
|
+
lineLevel: { total: 0, covered: 0 },
|
|
190
|
+
codeLists: { total: 0, covered: 0 }
|
|
191
|
+
};
|
|
192
|
+
for (const [rule, detail] of ruleDetails) {
|
|
193
|
+
const category = this.getRuleCategory(rule);
|
|
194
|
+
if (category && categories[category]) {
|
|
195
|
+
categories[category].total++;
|
|
196
|
+
if (detail.covered) {
|
|
197
|
+
categories[category].covered++;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Find uncovered rules
|
|
202
|
+
const uncoveredRules = Array.from(ruleDetails.entries())
|
|
203
|
+
.filter(([_, detail]) => !detail.covered)
|
|
204
|
+
.map(([rule, _]) => rule);
|
|
205
|
+
const coveredCount = Array.from(ruleDetails.values())
|
|
206
|
+
.filter(d => d.covered).length;
|
|
207
|
+
return {
|
|
208
|
+
totalRules: allRules.length,
|
|
209
|
+
coveredRules: coveredCount,
|
|
210
|
+
coveragePercentage: (coveredCount / allRules.length) * 100,
|
|
211
|
+
ruleDetails,
|
|
212
|
+
uncoveredRules,
|
|
213
|
+
byCategory: categories
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Print test summary
|
|
218
|
+
*/
|
|
219
|
+
printSummary() {
|
|
220
|
+
const passed = this.results.filter(r => r.passed).length;
|
|
221
|
+
const failed = this.results.filter(r => !r.passed).length;
|
|
222
|
+
const totalErrors = this.results.reduce((sum, r) => sum + r.errors.length, 0);
|
|
223
|
+
const totalWarnings = this.results.reduce((sum, r) => sum + r.warnings.length, 0);
|
|
224
|
+
console.log('\nš Test Summary:');
|
|
225
|
+
console.log(` Total samples: ${this.testSamples.length}`);
|
|
226
|
+
console.log(` ā
Passed: ${passed}`);
|
|
227
|
+
console.log(` ā Failed: ${failed}`);
|
|
228
|
+
console.log(` š“ Total errors: ${totalErrors}`);
|
|
229
|
+
console.log(` š” Total warnings: ${totalWarnings}`);
|
|
230
|
+
// Show failed samples
|
|
231
|
+
if (failed > 0) {
|
|
232
|
+
console.log('\nā Failed samples:');
|
|
233
|
+
for (const result of this.results.filter(r => !r.passed)) {
|
|
234
|
+
console.log(` - ${result.sampleName} (${result.errors.length} errors)`);
|
|
235
|
+
for (const error of result.errors.slice(0, 3)) {
|
|
236
|
+
console.log(` ⢠${error.ruleId}: ${error.message}`);
|
|
237
|
+
}
|
|
238
|
+
if (result.errors.length > 3) {
|
|
239
|
+
console.log(` ... and ${result.errors.length - 3} more errors`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Generate HTML coverage report
|
|
246
|
+
*/
|
|
247
|
+
async generateHTMLReport(outputPath = 'coverage-report.html') {
|
|
248
|
+
const coverage = this.generateCoverageMatrix();
|
|
249
|
+
const html = `
|
|
250
|
+
<!DOCTYPE html>
|
|
251
|
+
<html>
|
|
252
|
+
<head>
|
|
253
|
+
<title>EN16931 Conformance Test Report</title>
|
|
254
|
+
<style>
|
|
255
|
+
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
256
|
+
h1 { color: #333; }
|
|
257
|
+
.summary { background: #f0f0f0; padding: 15px; border-radius: 5px; margin: 20px 0; }
|
|
258
|
+
.metric { display: inline-block; margin: 10px 20px 10px 0; }
|
|
259
|
+
.metric-value { font-size: 24px; font-weight: bold; color: #007bff; }
|
|
260
|
+
.coverage-bar { width: 100%; height: 30px; background: #e0e0e0; border-radius: 5px; overflow: hidden; }
|
|
261
|
+
.coverage-fill { height: 100%; background: linear-gradient(90deg, #28a745, #ffc107); }
|
|
262
|
+
table { width: 100%; border-collapse: collapse; margin: 20px 0; }
|
|
263
|
+
th, td { padding: 10px; text-align: left; border: 1px solid #ddd; }
|
|
264
|
+
th { background: #f8f9fa; font-weight: bold; }
|
|
265
|
+
.covered { background: #d4edda; }
|
|
266
|
+
.uncovered { background: #f8d7da; }
|
|
267
|
+
.category-section { margin: 30px 0; }
|
|
268
|
+
.rule-tag { display: inline-block; padding: 2px 8px; margin: 2px; background: #007bff; color: white; border-radius: 3px; font-size: 12px; }
|
|
269
|
+
</style>
|
|
270
|
+
</head>
|
|
271
|
+
<body>
|
|
272
|
+
<h1>EN16931 Conformance Test Report</h1>
|
|
273
|
+
<div class="summary">
|
|
274
|
+
<h2>Overall Coverage</h2>
|
|
275
|
+
<div class="metric">
|
|
276
|
+
<div class="metric-value">${coverage.coveragePercentage.toFixed(1)}%</div>
|
|
277
|
+
<div>Total Coverage</div>
|
|
278
|
+
</div>
|
|
279
|
+
<div class="metric">
|
|
280
|
+
<div class="metric-value">${coverage.coveredRules}</div>
|
|
281
|
+
<div>Rules Covered</div>
|
|
282
|
+
</div>
|
|
283
|
+
<div class="metric">
|
|
284
|
+
<div class="metric-value">${coverage.totalRules}</div>
|
|
285
|
+
<div>Total Rules</div>
|
|
286
|
+
</div>
|
|
287
|
+
<div class="coverage-bar">
|
|
288
|
+
<div class="coverage-fill" style="width: ${coverage.coveragePercentage}%"></div>
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
|
|
292
|
+
<div class="category-section">
|
|
293
|
+
<h2>Coverage by Category</h2>
|
|
294
|
+
<table>
|
|
295
|
+
<tr>
|
|
296
|
+
<th>Category</th>
|
|
297
|
+
<th>Covered</th>
|
|
298
|
+
<th>Total</th>
|
|
299
|
+
<th>Percentage</th>
|
|
300
|
+
</tr>
|
|
301
|
+
${Object.entries(coverage.byCategory).map(([cat, data]) => `
|
|
302
|
+
<tr>
|
|
303
|
+
<td>${cat.charAt(0).toUpperCase() + cat.slice(1)}</td>
|
|
304
|
+
<td>${data.covered}</td>
|
|
305
|
+
<td>${data.total}</td>
|
|
306
|
+
<td>${data.total > 0 ? ((data.covered / data.total) * 100).toFixed(1) : 0}%</td>
|
|
307
|
+
</tr>
|
|
308
|
+
`).join('')}
|
|
309
|
+
</table>
|
|
310
|
+
</div>
|
|
311
|
+
|
|
312
|
+
<div class="category-section">
|
|
313
|
+
<h2>Test Samples</h2>
|
|
314
|
+
<table>
|
|
315
|
+
<tr>
|
|
316
|
+
<th>Sample</th>
|
|
317
|
+
<th>Status</th>
|
|
318
|
+
<th>Errors</th>
|
|
319
|
+
<th>Warnings</th>
|
|
320
|
+
<th>Rules Triggered</th>
|
|
321
|
+
</tr>
|
|
322
|
+
${this.results.map(r => `
|
|
323
|
+
<tr class="${r.passed ? 'covered' : 'uncovered'}">
|
|
324
|
+
<td>${r.sampleName}</td>
|
|
325
|
+
<td>${r.passed ? 'ā
PASSED' : 'ā FAILED'}</td>
|
|
326
|
+
<td>${r.errors.length}</td>
|
|
327
|
+
<td>${r.warnings.length}</td>
|
|
328
|
+
<td>${r.rulesTriggered.length}</td>
|
|
329
|
+
</tr>
|
|
330
|
+
`).join('')}
|
|
331
|
+
</table>
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
<div class="category-section">
|
|
335
|
+
<h2>Uncovered Rules</h2>
|
|
336
|
+
${coverage.uncoveredRules.length === 0 ? '<p>All rules covered! š</p>' : `
|
|
337
|
+
<p>The following ${coverage.uncoveredRules.length} rules need test coverage:</p>
|
|
338
|
+
<div>
|
|
339
|
+
${coverage.uncoveredRules.map(rule => `<span class="rule-tag">${rule}</span>`).join('')}
|
|
340
|
+
</div>
|
|
341
|
+
`}
|
|
342
|
+
</div>
|
|
343
|
+
|
|
344
|
+
<div class="category-section">
|
|
345
|
+
<p>Generated: ${new Date().toISOString()}</p>
|
|
346
|
+
</div>
|
|
347
|
+
</body>
|
|
348
|
+
</html>
|
|
349
|
+
`;
|
|
350
|
+
fs.writeFileSync(outputPath, html);
|
|
351
|
+
console.log(`\nš HTML report generated: ${outputPath}`);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Get all EN16931 business rules
|
|
355
|
+
*/
|
|
356
|
+
getAllEN16931Rules() {
|
|
357
|
+
return [
|
|
358
|
+
// Document level rules
|
|
359
|
+
'BR-01', 'BR-02', 'BR-03', 'BR-04', 'BR-05', 'BR-06', 'BR-07', 'BR-08', 'BR-09', 'BR-10',
|
|
360
|
+
'BR-11', 'BR-12', 'BR-13', 'BR-14', 'BR-15', 'BR-16', 'BR-17', 'BR-18', 'BR-19', 'BR-20',
|
|
361
|
+
// Line level rules
|
|
362
|
+
'BR-21', 'BR-22', 'BR-23', 'BR-24', 'BR-25', 'BR-26', 'BR-27', 'BR-28', 'BR-29', 'BR-30',
|
|
363
|
+
// Allowances and charges
|
|
364
|
+
'BR-31', 'BR-32', 'BR-33', 'BR-34', 'BR-35', 'BR-36', 'BR-37', 'BR-38', 'BR-39', 'BR-40',
|
|
365
|
+
'BR-41', 'BR-42', 'BR-43', 'BR-44', 'BR-45', 'BR-46', 'BR-47', 'BR-48', 'BR-49', 'BR-50',
|
|
366
|
+
'BR-51', 'BR-52', 'BR-53', 'BR-54', 'BR-55', 'BR-56', 'BR-57', 'BR-58', 'BR-59', 'BR-60',
|
|
367
|
+
'BR-61', 'BR-62', 'BR-63', 'BR-64', 'BR-65',
|
|
368
|
+
// Calculation rules
|
|
369
|
+
'BR-CO-01', 'BR-CO-02', 'BR-CO-03', 'BR-CO-04', 'BR-CO-05', 'BR-CO-06', 'BR-CO-07', 'BR-CO-08',
|
|
370
|
+
'BR-CO-09', 'BR-CO-10', 'BR-CO-11', 'BR-CO-12', 'BR-CO-13', 'BR-CO-14', 'BR-CO-15', 'BR-CO-16',
|
|
371
|
+
'BR-CO-17', 'BR-CO-18', 'BR-CO-19', 'BR-CO-20',
|
|
372
|
+
// VAT rules - Standard rate
|
|
373
|
+
'BR-S-01', 'BR-S-02', 'BR-S-03', 'BR-S-04', 'BR-S-05', 'BR-S-06', 'BR-S-07', 'BR-S-08',
|
|
374
|
+
// VAT rules - Zero rated
|
|
375
|
+
'BR-Z-01', 'BR-Z-02', 'BR-Z-03', 'BR-Z-04', 'BR-Z-05', 'BR-Z-06', 'BR-Z-07', 'BR-Z-08',
|
|
376
|
+
// VAT rules - Exempt
|
|
377
|
+
'BR-E-01', 'BR-E-02', 'BR-E-03', 'BR-E-04', 'BR-E-05', 'BR-E-06', 'BR-E-07', 'BR-E-08',
|
|
378
|
+
// VAT rules - Reverse charge
|
|
379
|
+
'BR-AE-01', 'BR-AE-02', 'BR-AE-03', 'BR-AE-04', 'BR-AE-05', 'BR-AE-06', 'BR-AE-07', 'BR-AE-08',
|
|
380
|
+
// VAT rules - Intra-community
|
|
381
|
+
'BR-K-01', 'BR-K-02', 'BR-K-03', 'BR-K-04', 'BR-K-05', 'BR-K-06', 'BR-K-07', 'BR-K-08',
|
|
382
|
+
'BR-K-09', 'BR-K-10',
|
|
383
|
+
// VAT rules - Export
|
|
384
|
+
'BR-G-01', 'BR-G-02', 'BR-G-03', 'BR-G-04', 'BR-G-05', 'BR-G-06', 'BR-G-07', 'BR-G-08',
|
|
385
|
+
// VAT rules - Out of scope
|
|
386
|
+
'BR-O-01', 'BR-O-02', 'BR-O-03', 'BR-O-04', 'BR-O-05', 'BR-O-06', 'BR-O-07', 'BR-O-08',
|
|
387
|
+
// Code list rules
|
|
388
|
+
'BR-CL-01', 'BR-CL-02', 'BR-CL-03', 'BR-CL-04', 'BR-CL-05', 'BR-CL-06', 'BR-CL-07', 'BR-CL-08',
|
|
389
|
+
'BR-CL-09', 'BR-CL-10', 'BR-CL-11', 'BR-CL-12', 'BR-CL-13', 'BR-CL-14', 'BR-CL-15', 'BR-CL-16',
|
|
390
|
+
'BR-CL-17', 'BR-CL-18', 'BR-CL-19', 'BR-CL-20', 'BR-CL-21', 'BR-CL-22', 'BR-CL-23', 'BR-CL-24',
|
|
391
|
+
'BR-CL-25', 'BR-CL-26'
|
|
392
|
+
];
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Get category for a rule
|
|
396
|
+
*/
|
|
397
|
+
getRuleCategory(ruleId) {
|
|
398
|
+
if (ruleId.startsWith('BR-CO-'))
|
|
399
|
+
return 'calculation';
|
|
400
|
+
if (ruleId.match(/^BR-[SZAEKG0]-/))
|
|
401
|
+
return 'vat';
|
|
402
|
+
if (ruleId.startsWith('BR-CL-'))
|
|
403
|
+
return 'codeLists';
|
|
404
|
+
if (ruleId.match(/^BR-2[0-9]/) || ruleId.match(/^BR-3[0-9]/))
|
|
405
|
+
return 'lineLevel';
|
|
406
|
+
if (ruleId.match(/^BR-[0-9]/) || ruleId.match(/^BR-1[0-9]/))
|
|
407
|
+
return 'document';
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Get description from filename
|
|
412
|
+
*/
|
|
413
|
+
getDescriptionFromFilename(filename) {
|
|
414
|
+
const descriptions = {
|
|
415
|
+
'Allowance-example': 'Invoice with document level allowances',
|
|
416
|
+
'base-example': 'Basic EN16931 compliant invoice',
|
|
417
|
+
'base-negative-inv-correction': 'Negative invoice correction',
|
|
418
|
+
'vat-category-E': 'VAT Exempt invoice',
|
|
419
|
+
'vat-category-O': 'Out of scope services',
|
|
420
|
+
'vat-category-S': 'Standard rated VAT',
|
|
421
|
+
'vat-category-Z': 'Zero rated VAT',
|
|
422
|
+
'vat-category-AE': 'Reverse charge VAT',
|
|
423
|
+
'vat-category-K': 'Intra-community supply',
|
|
424
|
+
'vat-category-G': 'Export outside EU'
|
|
425
|
+
};
|
|
426
|
+
const key = filename.replace('.xml', '');
|
|
427
|
+
return descriptions[key] || filename;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Get focus rules from filename
|
|
431
|
+
*/
|
|
432
|
+
getFocusRulesFromFilename(filename) {
|
|
433
|
+
const focusMap = {
|
|
434
|
+
'vat-category-E': ['BR-E-01', 'BR-E-02', 'BR-E-03', 'BR-E-04', 'BR-E-05', 'BR-E-06'],
|
|
435
|
+
'vat-category-S': ['BR-S-01', 'BR-S-02', 'BR-S-03', 'BR-S-04', 'BR-S-05'],
|
|
436
|
+
'vat-category-Z': ['BR-Z-01', 'BR-Z-02', 'BR-Z-03', 'BR-Z-04', 'BR-Z-05'],
|
|
437
|
+
'vat-category-AE': ['BR-AE-01', 'BR-AE-02', 'BR-AE-03', 'BR-AE-04', 'BR-AE-05', 'BR-AE-06'],
|
|
438
|
+
'vat-category-K': ['BR-K-01', 'BR-K-02', 'BR-K-03', 'BR-K-04', 'BR-K-05', 'BR-K-06'],
|
|
439
|
+
'vat-category-G': ['BR-G-01', 'BR-G-02', 'BR-G-03', 'BR-G-04', 'BR-G-05', 'BR-G-06'],
|
|
440
|
+
'vat-category-O': ['BR-O-01', 'BR-O-02', 'BR-O-03', 'BR-O-04', 'BR-O-05', 'BR-O-06']
|
|
441
|
+
};
|
|
442
|
+
const key = filename.replace('.xml', '');
|
|
443
|
+
return focusMap[key] || [];
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Export convenience function to run conformance tests
|
|
448
|
+
*/
|
|
449
|
+
export async function runConformanceTests(samplesDir = 'test-samples', generateReport = true) {
|
|
450
|
+
const harness = new ConformanceTestHarness();
|
|
451
|
+
// Load samples
|
|
452
|
+
await harness.loadTestSamples(samplesDir);
|
|
453
|
+
// Run tests
|
|
454
|
+
await harness.runConformanceTests();
|
|
455
|
+
// Generate reports
|
|
456
|
+
if (generateReport) {
|
|
457
|
+
const coverage = harness.generateCoverageMatrix();
|
|
458
|
+
console.log('\nš Coverage Report:');
|
|
459
|
+
console.log(` Overall: ${coverage.coveragePercentage.toFixed(1)}%`);
|
|
460
|
+
console.log(` Rules covered: ${coverage.coveredRules}/${coverage.totalRules}`);
|
|
461
|
+
// Show category breakdown
|
|
462
|
+
console.log('\n By Category:');
|
|
463
|
+
for (const [category, data] of Object.entries(coverage.byCategory)) {
|
|
464
|
+
const pct = data.total > 0 ? ((data.covered / data.total) * 100).toFixed(1) : '0';
|
|
465
|
+
console.log(` - ${category}: ${data.covered}/${data.total} (${pct}%)`);
|
|
466
|
+
}
|
|
467
|
+
// Generate HTML report
|
|
468
|
+
await harness.generateHTMLReport();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZm9ybWFuY2UuaGFybmVzcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2Zvcm1hdHMvdmFsaWRhdGlvbi9jb25mb3JtYW5jZS5oYXJuZXNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVILE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDbEUsT0FBTyxFQUFFLDZCQUE2QixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDdEYsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDNUQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFHdkUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUEwRHBGOztHQUVHO0FBQ0gsTUFBTSxPQUFPLHNCQUFzQjtJQVNqQztRQUhRLGdCQUFXLEdBQWlCLEVBQUUsQ0FBQztRQUMvQixZQUFPLEdBQWlCLEVBQUUsQ0FBQztRQUdqQyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxtQkFBbUIsRUFBRSxDQUFDO1FBQ3JELElBQUksQ0FBQyxzQkFBc0IsR0FBRyxJQUFJLDZCQUE2QixFQUFFLENBQUM7UUFDbEUsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksaUJBQWlCLEVBQUUsQ0FBQztRQUNqRCxJQUFJLENBQUMsc0JBQXNCLEdBQUcsSUFBSSxzQkFBc0IsRUFBRSxDQUFDO1FBQzNELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxzQkFBc0IsRUFBRSxDQUFDO0lBQ25ELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxlQUFlLENBQUMsVUFBa0IsY0FBYztR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
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { EInvoice } from '../../einvoice.js';
|
|
2
|
+
import type { ValidationResult, ValidationOptions } from './validation.types.js';
|
|
3
|
+
/**
|
|
4
|
+
* EN16931 Business Rules Validator
|
|
5
|
+
* Implements the full set of EN16931 business rules for invoice validation
|
|
6
|
+
*/
|
|
7
|
+
export declare class EN16931BusinessRulesValidator {
|
|
8
|
+
private results;
|
|
9
|
+
private currencyCalculator?;
|
|
10
|
+
private decimalCalculator?;
|
|
11
|
+
/**
|
|
12
|
+
* Validate an invoice against EN16931 business rules
|
|
13
|
+
*/
|
|
14
|
+
validate(invoice: EInvoice, options?: ValidationOptions): ValidationResult[];
|
|
15
|
+
/**
|
|
16
|
+
* Validate document level rules (BR-01 to BR-65)
|
|
17
|
+
*/
|
|
18
|
+
private validateDocumentRules;
|
|
19
|
+
/**
|
|
20
|
+
* Validate calculation rules (BR-CO-*)
|
|
21
|
+
*/
|
|
22
|
+
private validateCalculationRules;
|
|
23
|
+
/**
|
|
24
|
+
* Validate VAT rules
|
|
25
|
+
*/
|
|
26
|
+
private validateVATRules;
|
|
27
|
+
/**
|
|
28
|
+
* Validate line level rules (BR-21 to BR-30)
|
|
29
|
+
*/
|
|
30
|
+
private validateLineRules;
|
|
31
|
+
/**
|
|
32
|
+
* Validate allowances and charges
|
|
33
|
+
*/
|
|
34
|
+
private validateAllowancesCharges;
|
|
35
|
+
private calculateLineTotal;
|
|
36
|
+
/**
|
|
37
|
+
* Calculate line total using decimal arithmetic for precision
|
|
38
|
+
*/
|
|
39
|
+
private calculateLineTotalDecimal;
|
|
40
|
+
/**
|
|
41
|
+
* Calculate document allowances using decimal arithmetic
|
|
42
|
+
*/
|
|
43
|
+
private calculateDocumentAllowancesDecimal;
|
|
44
|
+
/**
|
|
45
|
+
* Calculate document charges using decimal arithmetic
|
|
46
|
+
*/
|
|
47
|
+
private calculateDocumentChargesDecimal;
|
|
48
|
+
/**
|
|
49
|
+
* Calculate total VAT using decimal arithmetic
|
|
50
|
+
*/
|
|
51
|
+
private calculateTotalVATDecimal;
|
|
52
|
+
private calculateDocumentAllowances;
|
|
53
|
+
private calculateDocumentCharges;
|
|
54
|
+
private calculateTotalVAT;
|
|
55
|
+
private groupItemsByVAT;
|
|
56
|
+
private addError;
|
|
57
|
+
private addWarning;
|
|
58
|
+
}
|