fix(compliance): improve compliance

This commit is contained in:
2025-05-28 14:46:32 +00:00
parent 784a50bc7f
commit 16e2bd6b1a
16 changed files with 4718 additions and 3138 deletions

View File

@ -1,60 +1,170 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { EInvoice } from '../../../ts/index.js';
import { PerformanceTracker } from '../performance.tracker.js';
tap.test('ENC-10: Cross-Format Encoding - should handle encoding across different invoice formats', async () => {
// ENC-10: Verify handling of Cross-Format Encoding encoded documents
console.log('Testing cross-format encoding consistency...\n');
// Test 1: Direct Cross-Format Encoding encoding (expected to fail)
console.log('\nTest 1: Direct Cross-Format Encoding encoding');
const { result: directResult, metric: directMetric } = await PerformanceTracker.track(
'cross-direct',
async () => {
// XML parsers typically don't support Cross-Format Encoding directly
const xmlContent = `<?xml version="1.0" encoding="Cross-Format Encoding"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<UBLVersionID>2.1</UBLVersionID>
<ID>CROSS-TEST</ID>
<IssueDate>2025-01-25</IssueDate>
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
</Invoice>`;
let success = false;
let error = null;
try {
const newInvoice = new EInvoice();
await newInvoice.fromXmlString(xmlContent);
success = newInvoice.id === 'CROSS-TEST' ||
newInvoice.invoiceId === 'CROSS-TEST' ||
newInvoice.accountingDocId === 'CROSS-TEST';
} catch (e) {
error = e;
console.log(` Cross-Format Encoding not directly supported: ${e.message}`);
// Test 1: UBL to CII encoding consistency
const testUblToCiiEncoding = async () => {
const einvoice = new EInvoice();
einvoice.id = 'CROSS-FORMAT-TEST';
einvoice.issueDate = new Date(2025, 0, 25);
einvoice.subject = 'Cross-format test with special chars: éñüß';
einvoice.from = {
type: 'company',
name: 'Test Company éñüß',
description: 'Testing cross-format encoding: €£¥',
address: {
streetName: 'Straße with ümlaut',
houseNumber: '1',
postalCode: '12345',
city: 'München',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2020, month: 1, day: 1 },
registrationDetails: {
vatId: 'DE123456789',
registrationId: 'HRB 12345',
registrationName: 'Commercial Register'
}
};
einvoice.to = {
type: 'person',
name: 'José',
surname: 'Müller',
salutation: 'Mr' as const,
sex: 'male' as const,
title: 'Doctor' as const,
description: 'Customer with spëcial chars',
address: {
streetName: 'Côte d\'Azur',
houseNumber: '2',
postalCode: '54321',
city: 'São Paulo',
country: 'BR'
}
};
einvoice.items = [{
position: 1,
name: 'Product with éñü symbols',
articleNumber: 'CROSS-001',
unitType: 'EA',
unitQuantity: 1,
unitNetPrice: 100,
vatPercentage: 19
}];
try {
// Export as UBL
const ublXml = await einvoice.toXmlString('ubl');
return { success, error };
// Export as CII
const ciiXml = await einvoice.toXmlString('cii');
// Verify both formats preserve special characters
const ublHasSpecialChars = ublXml.includes('éñüß') && ublXml.includes('München') && ublXml.includes('José');
const ciiHasSpecialChars = ciiXml.includes('éñüß') && ciiXml.includes('München') && ciiXml.includes('José');
// Test round-trip for both formats
const ublInvoice = new EInvoice();
await ublInvoice.fromXmlString(ublXml);
const ciiInvoice = new EInvoice();
await ciiInvoice.fromXmlString(ciiXml);
const ublRoundTrip = ublInvoice.from?.name?.includes('éñüß') && ublInvoice.to?.name?.includes('José');
const ciiRoundTrip = ciiInvoice.from?.name?.includes('éñüß') && ciiInvoice.to?.name?.includes('José');
console.log(`Test 1 - UBL to CII encoding:`);
console.log(` UBL preserves special chars: ${ublHasSpecialChars ? 'Yes' : 'No'}`);
console.log(` CII preserves special chars: ${ciiHasSpecialChars ? 'Yes' : 'No'}`);
console.log(` UBL round-trip successful: ${ublRoundTrip ? 'Yes' : 'No'}`);
console.log(` CII round-trip successful: ${ciiRoundTrip ? 'Yes' : 'No'}`);
return { ublHasSpecialChars, ciiHasSpecialChars, ublRoundTrip, ciiRoundTrip };
} catch (error) {
console.log(`Test 1 - UBL to CII encoding:`);
console.log(` Cross-format encoding failed: ${error.message}`);
return { ublHasSpecialChars: false, ciiHasSpecialChars: false, ublRoundTrip: false, ciiRoundTrip: false };
}
);
};
console.log(` Cross-Format Encoding direct test completed in ${directMetric.duration}ms`);
// Test 2: Different encoding declarations consistency
const testEncodingDeclarations = async () => {
const ublWithUnicodeXml = `<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:ID>ENCODING-CONSISTENCY-TEST</cbc:ID>
<cbc:IssueDate>2025-01-25</cbc:IssueDate>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cac:AccountingSupplierParty>
<cac:Party>
<cac:PartyName>
<cbc:Name>Ünîcödë Company €éñ</cbc:Name>
</cac:PartyName>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="EA">1</cbc:InvoicedQuantity>
<cac:Item>
<cbc:Name>Product with spëcîãl chars</cbc:Name>
</cac:Item>
</cac:InvoiceLine>
</Invoice>`;
try {
// Parse UBL with Unicode content
const ublInvoice = new EInvoice();
await ublInvoice.fromXmlString(ublWithUnicodeXml);
// Convert to CII and back to UBL
const ciiXml = await ublInvoice.toXmlString('cii');
const ublFromCii = new EInvoice();
await ublFromCii.fromXmlString(ciiXml);
// Check if special characters survive format conversion
const originalHasUnicode = ublInvoice.from?.name?.includes('Ünîcödë') &&
ublInvoice.from?.name?.includes('€éñ');
const ciiPreservesUnicode = ciiXml.includes('Ünîcödë') && ciiXml.includes('€éñ');
const roundTripPreservesUnicode = ublFromCii.from?.name?.includes('Ünîcödë') &&
ublFromCii.from?.name?.includes('€éñ');
console.log(`\nTest 2 - Encoding declaration consistency:`);
console.log(` Original UBL has Unicode: ${originalHasUnicode ? 'Yes' : 'No'}`);
console.log(` CII conversion preserves Unicode: ${ciiPreservesUnicode ? 'Yes' : 'No'}`);
console.log(` Round-trip preserves Unicode: ${roundTripPreservesUnicode ? 'Yes' : 'No'}`);
return { originalHasUnicode, ciiPreservesUnicode, roundTripPreservesUnicode };
} catch (error) {
console.log(`\nTest 2 - Encoding declaration consistency:`);
console.log(` Encoding consistency test failed: ${error.message}`);
return { originalHasUnicode: false, ciiPreservesUnicode: false, roundTripPreservesUnicode: false };
}
};
// Test 2: UTF-8 fallback (should always work)
console.log('\nTest 2: UTF-8 fallback');
const { result: fallbackResult, metric: fallbackMetric } = await PerformanceTracker.track(
'cross-fallback',
async () => {
// Test 3: Mixed format documents
const testMixedFormatSupport = async () => {
try {
const einvoice = new EInvoice();
einvoice.id = 'CROSS-FALLBACK-TEST';
einvoice.id = 'MIXED-FORMAT-TEST';
einvoice.issueDate = new Date(2025, 0, 25);
einvoice.invoiceId = 'CROSS-FALLBACK-TEST';
einvoice.accountingDocId = 'CROSS-FALLBACK-TEST';
einvoice.subject = 'Cross-Format Encoding fallback test';
einvoice.subject = 'Mixed format test';
einvoice.from = {
type: 'company',
name: 'Test Company',
description: 'Testing Cross-Format Encoding encoding',
name: 'Mixed Format Tëst Co.',
description: 'Testing mixed formats with €áàâ',
address: {
streetName: 'Test Street',
houseNumber: '1',
@ -91,39 +201,138 @@ tap.test('ENC-10: Cross-Format Encoding - should handle encoding across differen
einvoice.items = [{
position: 1,
name: 'Test Product',
articleNumber: 'CROSS-001',
articleNumber: 'MIXED-001',
unitType: 'EA',
unitQuantity: 1,
unitNetPrice: 100,
vatPercentage: 19
}];
// Export as UTF-8 (our default)
const utf8Xml = await einvoice.toXmlString('ubl');
// Test multiple format exports and verify encoding consistency
const ublXml = await einvoice.toXmlString('ubl');
const ciiXml = await einvoice.toXmlString('cii');
// Verify UTF-8 works correctly
const newInvoice = new EInvoice();
await newInvoice.fromXmlString(utf8Xml);
// All formats should have proper UTF-8 encoding declaration
const ublHasUtf8 = ublXml.includes('encoding="UTF-8"') || !ublXml.includes('encoding=');
const ciiHasUtf8 = ciiXml.includes('encoding="UTF-8"') || !ciiXml.includes('encoding=');
const success = newInvoice.id === 'CROSS-FALLBACK-TEST' ||
newInvoice.invoiceId === 'CROSS-FALLBACK-TEST' ||
newInvoice.accountingDocId === 'CROSS-FALLBACK-TEST';
// Check if special characters are preserved across formats
const ublPreservesChars = ublXml.includes('Tëst') && ublXml.includes('€áàâ');
const ciiPreservesChars = ciiXml.includes('Tëst') && ciiXml.includes('€áàâ');
console.log(` UTF-8 fallback works: ${success}`);
console.log(`\nTest 3 - Mixed format support:`);
console.log(` UBL has UTF-8 encoding: ${ublHasUtf8 ? 'Yes' : 'No'}`);
console.log(` CII has UTF-8 encoding: ${ciiHasUtf8 ? 'Yes' : 'No'}`);
console.log(` UBL preserves special chars: ${ublPreservesChars ? 'Yes' : 'No'}`);
console.log(` CII preserves special chars: ${ciiPreservesChars ? 'Yes' : 'No'}`);
return { success };
return { ublHasUtf8, ciiHasUtf8, ublPreservesChars, ciiPreservesChars };
} catch (error) {
console.log(`\nTest 3 - Mixed format support:`);
console.log(` Mixed format test failed: ${error.message}`);
return { ublHasUtf8: false, ciiHasUtf8: false, ublPreservesChars: false, ciiPreservesChars: false };
}
);
};
console.log(` Cross-Format Encoding fallback test completed in ${fallbackMetric.duration}ms`);
// Test 4: Encoding header consistency
const testEncodingHeaders = async () => {
try {
const einvoice = new EInvoice();
einvoice.id = 'HEADER-TEST';
einvoice.issueDate = new Date(2025, 0, 25);
einvoice.subject = 'Encoding header test';
einvoice.from = {
type: 'company',
name: 'Header Test Company',
description: 'Testing encoding headers',
address: {
streetName: 'Test Street',
houseNumber: '1',
postalCode: '12345',
city: 'Test City',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2020, month: 1, day: 1 },
registrationDetails: {
vatId: 'DE123456789',
registrationId: 'HRB 12345',
registrationName: 'Commercial Register'
}
};
einvoice.to = {
type: 'person',
name: 'Test',
surname: 'Customer',
salutation: 'Mr' as const,
sex: 'male' as const,
title: 'Doctor' as const,
description: 'Test customer',
address: {
streetName: 'Customer Street',
houseNumber: '2',
postalCode: '54321',
city: 'Customer City',
country: 'DE'
}
};
einvoice.items = [{
position: 1,
name: 'Test Product',
articleNumber: 'HEADER-001',
unitType: 'EA',
unitQuantity: 1,
unitNetPrice: 100,
vatPercentage: 19
}];
// Generate both formats and check XML headers
const ublXml = await einvoice.toXmlString('ubl');
const ciiXml = await einvoice.toXmlString('cii');
// Check if both start with proper XML declaration
const ublHasXmlDecl = ublXml.startsWith('<?xml version="1.0"');
const ciiHasXmlDecl = ciiXml.startsWith('<?xml version="1.0"');
// Check if encoding is consistent
const ublConsistentEncoding = !ublXml.includes('encoding=') || ublXml.includes('encoding="UTF-8"');
const ciiConsistentEncoding = !ciiXml.includes('encoding=') || ciiXml.includes('encoding="UTF-8"');
console.log(`\nTest 4 - Encoding header consistency:`);
console.log(` UBL has XML declaration: ${ublHasXmlDecl ? 'Yes' : 'No'}`);
console.log(` CII has XML declaration: ${ciiHasXmlDecl ? 'Yes' : 'No'}`);
console.log(` UBL encoding consistent: ${ublConsistentEncoding ? 'Yes' : 'No'}`);
console.log(` CII encoding consistent: ${ciiConsistentEncoding ? 'Yes' : 'No'}`);
return { ublHasXmlDecl, ciiHasXmlDecl, ublConsistentEncoding, ciiConsistentEncoding };
} catch (error) {
console.log(`\nTest 4 - Encoding header consistency:`);
console.log(` Header consistency test failed: ${error.message}`);
return { ublHasXmlDecl: false, ciiHasXmlDecl: false, ublConsistentEncoding: false, ciiConsistentEncoding: false };
}
};
// Summary
console.log('\n=== Cross-Format Encoding Encoding Test Summary ===');
console.log(`Cross-Format Encoding Direct: ${directResult.success ? 'Supported' : 'Not supported (acceptable)'}`);
console.log(`UTF-8 Fallback: ${fallbackResult.success ? 'Working' : 'Failed'}`);
// Run all tests
const crossFormatResult = await testUblToCiiEncoding();
const encodingDeclResult = await testEncodingDeclarations();
const mixedFormatResult = await testMixedFormatSupport();
const headerResult = await testEncodingHeaders();
// The test passes if UTF-8 fallback works, since Cross-Format Encoding support is optional
expect(fallbackResult.success).toBeTrue();
console.log(`\n=== Cross-Format Encoding Test Summary ===`);
console.log(`UBL-CII encoding consistency: ${crossFormatResult.ublRoundTrip && crossFormatResult.ciiRoundTrip ? 'Working' : 'Issues'}`);
console.log(`Format conversion encoding: ${encodingDeclResult.roundTripPreservesUnicode ? 'Working' : 'Issues'}`);
console.log(`Mixed format support: ${mixedFormatResult.ublPreservesChars && mixedFormatResult.ciiPreservesChars ? 'Working' : 'Issues'}`);
console.log(`Encoding header consistency: ${headerResult.ublConsistentEncoding && headerResult.ciiConsistentEncoding ? 'Working' : 'Issues'}`);
console.log(`Cross-format round-trip: ${crossFormatResult.ublRoundTrip && crossFormatResult.ciiRoundTrip ? 'Working' : 'Issues'}`);
// Test passes if basic cross-format consistency works
expect(crossFormatResult.ublRoundTrip || crossFormatResult.ciiRoundTrip).toBeTrue();
expect(headerResult.ublHasXmlDecl && headerResult.ciiHasXmlDecl).toBeTrue();
});
// Run the test