import { tap, expect } from '@git.zone/tstest/tapbundle'; import { MainValidator, createValidator } from '../ts/formats/validation/integrated.validator.js'; import { EInvoice } from '../ts/einvoice.js'; import * as fs from 'fs'; import * as path from 'path'; tap.test('Integrated Validator - Basic validation', async () => { const validator = new MainValidator(); const invoice = new EInvoice(); invoice.invoiceNumber = 'TEST-001'; invoice.issueDate = new Date('2025-01-11'); invoice.from = { type: 'company', name: 'Test Seller', address: { streetName: 'Test Street', city: 'Berlin', postalCode: '10115', countryCode: 'DE' } }; invoice.to = { name: 'Test Buyer', address: { streetName: 'Buyer Street', city: 'Munich', postalCode: '80331', countryCode: 'DE' } }; const report = await validator.validate(invoice); console.log('Basic validation report:'); console.log(` Valid: ${report.valid}`); console.log(` Errors: ${report.errorCount}`); console.log(` Warnings: ${report.warningCount}`); console.log(` Coverage: ${report.coverage.toFixed(1)}%`); expect(report).toBeDefined(); expect(report.errorCount).toBeGreaterThan(0); // Should have errors (missing required fields) }); tap.test('Integrated Validator - XRechnung detection', async () => { const validator = new MainValidator(); const invoice = new EInvoice(); invoice.metadata = { profileId: 'urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0', buyerReference: '991-12345678901-23' // Leitweg-ID }; invoice.invoiceNumber = 'XR-2025-001'; invoice.issueDate = new Date('2025-01-11'); const report = await validator.validate(invoice); console.log('XRechnung validation report:'); console.log(` Profile: ${report.profile}`); console.log(` XRechnung errors found: ${ report.results.filter(r => r.source === 'XRECHNUNG').length }`); expect(report.profile).toInclude('XRECHNUNG'); // Check for XRechnung-specific validation const xrErrors = report.results.filter(r => r.source === 'XRECHNUNG'); expect(xrErrors.length).toBeGreaterThan(0); }); tap.test('Integrated Validator - Complete valid invoice', async () => { const validator = await createValidator({ enableSchematron: false }); const invoice = new EInvoice(); invoice.accountingDocId = 'INV-2025-001'; invoice.accountingDocType = '380'; invoice.invoiceNumber = 'INV-2025-001'; invoice.issueDate = new Date('2025-01-11'); invoice.currencyCode = 'EUR'; invoice.from = { type: 'company', name: 'Example GmbH', address: { streetName: 'Hauptstraße 1', city: 'Berlin', postalCode: '10115', countryCode: 'DE' }, registrationDetails: { vatId: 'DE123456789' } }; invoice.to = { name: 'Customer AG', address: { streetName: 'Kundenweg 42', city: 'Munich', postalCode: '80331', countryCode: 'DE' } }; invoice.items = [{ title: 'Consulting Services', description: 'Professional consulting', quantity: 10, unitPrice: 100, netAmount: 1000, vatRate: 19, vatAmount: 190, grossAmount: 1190 }]; invoice.metadata = { customizationId: 'urn:cen.eu:en16931:2017', profileId: 'urn:cen.eu:en16931:2017', taxDetails: [{ taxPercent: 19, netAmount: 1000, taxAmount: 190 }], totals: { lineExtensionAmount: 1000, taxExclusiveAmount: 1000, taxInclusiveAmount: 1190, payableAmount: 1190 } }; const report = await validator.validate(invoice); console.log('\nComplete invoice validation:'); console.log(validator.formatReport(report)); // Should have fewer errors with more complete data expect(report.errorCount).toBeLessThan(10); }); tap.test('Integrated Validator - With XML content', async () => { const validator = await createValidator(); // Load a sample XML file if available const xmlPath = path.join( process.cwd(), 'corpus/xml-rechnung/3.1/ubl/01-01a-INVOICE_ubl.xml' ); if (fs.existsSync(xmlPath)) { const xmlContent = fs.readFileSync(xmlPath, 'utf-8'); const invoice = await EInvoice.fromXML(xmlContent); const report = await validator.validateAuto(invoice, xmlContent); console.log('\nXML validation with Schematron:'); console.log(` Format detected: ${report.format}`); console.log(` Schematron enabled: ${report.schematronEnabled}`); console.log(` Validation sources: ${ [...new Set(report.results.map(r => r.source))].join(', ') }`); expect(report.format).toBeDefined(); } else { console.log('Sample XML not found, skipping XML validation test'); } }); tap.test('Integrated Validator - Capabilities check', async () => { const validator = new MainValidator(); const capabilities = validator.getCapabilities(); console.log('\nValidator capabilities:'); console.log(` Schematron: ${capabilities.schematron ? '✅' : '❌'}`); console.log(` XRechnung: ${capabilities.xrechnung ? '✅' : '❌'}`); console.log(` PEPPOL: ${capabilities.peppol ? '✅' : '❌'}`); console.log(` Calculations: ${capabilities.calculations ? '✅' : '❌'}`); console.log(` Code Lists: ${capabilities.codeLists ? '✅' : '❌'}`); expect(capabilities.xrechnung).toBeTrue(); expect(capabilities.calculations).toBeTrue(); expect(capabilities.codeLists).toBeTrue(); }); tap.test('Integrated Validator - Deduplication', async () => { const validator = new MainValidator(); // Create invoice that will trigger duplicate errors const invoice = new EInvoice(); invoice.invoiceNumber = 'TEST-DUP'; const report = await validator.validate(invoice); // Check that duplicates are removed const ruleIds = report.results.map(r => r.ruleId); const uniqueRuleIds = [...new Set(ruleIds)]; console.log(`\nDeduplication test:`); console.log(` Total results: ${report.results.length}`); console.log(` Unique rule IDs: ${uniqueRuleIds.length}`); // Each rule+field combination should appear only once const combinations = new Set(); let duplicates = 0; for (const result of report.results) { const key = `${result.ruleId}|${result.field || ''}`; if (combinations.has(key)) { duplicates++; } combinations.add(key); } console.log(` Duplicate combinations: ${duplicates}`); expect(duplicates).toEqual(0); }); export default tap.start();