- Added validation types for EN16931 compliance in `validation.types.ts`, including interfaces for `ValidationResult`, `ValidationOptions`, and `ValidationReport`. - Introduced `VATCategoriesValidator` in `vat-categories.validator.ts` to validate VAT categories according to EN16931 rules, including detailed checks for standard, zero-rated, exempt, reverse charge, intra-community, export, and out-of-scope services. - Enhanced `IEInvoiceMetadata` interface in `en16931-metadata.ts` to include additional fields required for full standards compliance, such as delivery information, payment information, allowances, and charges. - Implemented helper methods for VAT calculations and validation logic to ensure accurate compliance with EN16931 standards.
163 lines
5.6 KiB
TypeScript
163 lines
5.6 KiB
TypeScript
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
|
import { SchematronValidator, HybridValidator } from '../ts/formats/validation/schematron.validator.js';
|
|
import { SchematronDownloader } from '../ts/formats/validation/schematron.downloader.js';
|
|
import { SchematronWorkerPool } from '../ts/formats/validation/schematron.worker.js';
|
|
|
|
tap.test('Schematron Infrastructure - should initialize correctly', async () => {
|
|
const validator = new SchematronValidator();
|
|
expect(validator).toBeInstanceOf(SchematronValidator);
|
|
expect(validator.hasRules()).toBeFalse();
|
|
});
|
|
|
|
tap.test('Schematron Infrastructure - should load Schematron rules', async () => {
|
|
const validator = new SchematronValidator();
|
|
|
|
// Load a simple test Schematron
|
|
const testSchematron = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron">
|
|
<sch:ns prefix="ubl" uri="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"/>
|
|
|
|
<sch:pattern id="test-pattern">
|
|
<sch:rule context="//ubl:Invoice">
|
|
<sch:assert test="ubl:ID" id="TEST-01">
|
|
Invoice must have an ID
|
|
</sch:assert>
|
|
</sch:rule>
|
|
</sch:pattern>
|
|
</sch:schema>`;
|
|
|
|
await validator.loadSchematron(testSchematron, false);
|
|
expect(validator.hasRules()).toBeTrue();
|
|
});
|
|
|
|
tap.test('Schematron Infrastructure - should detect phases', async () => {
|
|
const validator = new SchematronValidator();
|
|
|
|
const schematronWithPhases = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron">
|
|
<sch:phase id="basic">
|
|
<sch:active pattern="basic-rules"/>
|
|
</sch:phase>
|
|
<sch:phase id="extended">
|
|
<sch:active pattern="basic-rules"/>
|
|
<sch:active pattern="extended-rules"/>
|
|
</sch:phase>
|
|
|
|
<sch:pattern id="basic-rules">
|
|
<sch:rule context="//Invoice">
|
|
<sch:assert test="ID">Invoice must have ID</sch:assert>
|
|
</sch:rule>
|
|
</sch:pattern>
|
|
</sch:schema>`;
|
|
|
|
await validator.loadSchematron(schematronWithPhases, false);
|
|
const phases = await validator.getPhases();
|
|
|
|
expect(phases).toContain('basic');
|
|
expect(phases).toContain('extended');
|
|
});
|
|
|
|
tap.test('Schematron Downloader - should initialize', async () => {
|
|
const downloader = new SchematronDownloader('.nogit/schematron-test');
|
|
await downloader.initialize();
|
|
|
|
// Check that sources are defined
|
|
expect(downloader).toBeInstanceOf(SchematronDownloader);
|
|
});
|
|
|
|
tap.test('Schematron Downloader - should list available sources', async () => {
|
|
const { SCHEMATRON_SOURCES } = await import('../ts/formats/validation/schematron.downloader.js');
|
|
|
|
// Check EN16931 sources
|
|
expect(SCHEMATRON_SOURCES.EN16931).toBeDefined();
|
|
expect(SCHEMATRON_SOURCES.EN16931.length).toBeGreaterThan(0);
|
|
|
|
const en16931Ubl = SCHEMATRON_SOURCES.EN16931.find(s => s.format === 'UBL');
|
|
expect(en16931Ubl).toBeDefined();
|
|
expect(en16931Ubl?.name).toEqual('EN16931-UBL');
|
|
|
|
// Check PEPPOL sources
|
|
expect(SCHEMATRON_SOURCES.PEPPOL).toBeDefined();
|
|
expect(SCHEMATRON_SOURCES.PEPPOL.length).toBeGreaterThan(0);
|
|
|
|
// Check XRechnung sources
|
|
expect(SCHEMATRON_SOURCES.XRECHNUNG).toBeDefined();
|
|
expect(SCHEMATRON_SOURCES.XRECHNUNG.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
tap.test('Hybrid Validator - should combine validators', async () => {
|
|
const schematronValidator = new SchematronValidator();
|
|
const hybrid = new HybridValidator(schematronValidator);
|
|
|
|
// Add a mock TypeScript validator
|
|
const mockTSValidator = {
|
|
validate: (xml: string) => [{
|
|
ruleId: 'TS-TEST-01',
|
|
severity: 'error' as const,
|
|
message: 'Test error from TS validator',
|
|
btReference: undefined,
|
|
bgReference: undefined
|
|
}]
|
|
};
|
|
|
|
hybrid.addTSValidator(mockTSValidator);
|
|
|
|
// Test validation (will only run TS validator since no Schematron loaded)
|
|
const results = await hybrid.validate('<Invoice/>');
|
|
expect(results.length).toEqual(1);
|
|
expect(results[0].ruleId).toEqual('TS-TEST-01');
|
|
});
|
|
|
|
tap.test('Schematron Worker Pool - should initialize', async () => {
|
|
const pool = new SchematronWorkerPool(2);
|
|
|
|
// Test pool stats
|
|
const stats = pool.getStats();
|
|
expect(stats.totalWorkers).toEqual(0); // Not initialized yet
|
|
expect(stats.queuedTasks).toEqual(0);
|
|
|
|
// Note: Full worker pool test would require actual worker thread setup
|
|
// which may not work in all test environments
|
|
});
|
|
|
|
tap.test('Schematron Validator - SVRL parsing', async () => {
|
|
const validator = new SchematronValidator();
|
|
|
|
// Test SVRL output parsing
|
|
const testSVRL = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<svrl:schematron-output xmlns:svrl="http://purl.oclc.org/dsdl/svrl">
|
|
<svrl:active-pattern document="test.xml"/>
|
|
|
|
<svrl:failed-assert test="count(ID) = 1"
|
|
location="/Invoice"
|
|
id="BR-01"
|
|
flag="fatal">
|
|
<svrl:text>[BR-01] Invoice must have exactly one ID</svrl:text>
|
|
</svrl:failed-assert>
|
|
|
|
<svrl:successful-report test="Currency = 'EUR'"
|
|
location="/Invoice"
|
|
id="INFO-01"
|
|
flag="information">
|
|
<svrl:text>Currency is EUR</svrl:text>
|
|
</svrl:successful-report>
|
|
</svrl:schematron-output>`;
|
|
|
|
// This would test the SVRL parsing logic
|
|
// The actual implementation would parse this and return ValidationResult[]
|
|
expect(testSVRL).toContain('failed-assert');
|
|
expect(testSVRL).toContain('BR-01');
|
|
});
|
|
|
|
tap.test('Schematron Integration - should handle missing files gracefully', async () => {
|
|
const validator = new SchematronValidator();
|
|
|
|
try {
|
|
await validator.loadSchematron('non-existent-file.sch', true);
|
|
expect(true).toBeFalse(); // Should not reach here
|
|
} catch (error) {
|
|
expect(error).toBeDefined();
|
|
}
|
|
});
|
|
|
|
tap.start(); |