import { expect, tap } from '@git.zone/tstest/tapbundle';
import * as plugins from '../plugins.js';
import { EInvoice } from '../../../ts/index.js';
import { CorpusLoader } from '../corpus.loader.js';
import { PerformanceTracker } from '../performance.tracker.js';
tap.test('CONV-04: Field Mapping - should correctly map fields between formats', async (t) => {
// CONV-04: Verify accurate field mapping during format conversion
// This test ensures data is correctly transferred between different formats
const performanceTracker = new PerformanceTracker('CONV-04: Field Mapping');
const corpusLoader = new CorpusLoader();
t.test('Basic field mapping UBL to CII', async () => {
const startTime = performance.now();
// UBL invoice with comprehensive fields
const ublInvoice = `
2.1
urn:cen.eu:en16931:2017
urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
FIELD-MAP-001
2025-01-25
2025-02-25
380
Field mapping test invoice
2025-01-25
EUR
EUR
PO-2025-001
ORDER-123
PREV-INV-001
2025-01-01
5790000435975
DK12345678
Supplier Company A/S
Main Street
1
Copenhagen
1234
Capital Region
DK
DK12345678
VAT
Supplier Company A/S
DK12345678
John Doe
+45 12345678
john@supplier.dk
5790000435982
DK87654321
Customer Company B/V
Market Street
100
Aarhus
8000
DK
DK87654321
VAT
Jane Smith
jane@customer.dk
30
PAY-2025-001
DK5000400440116243
Supplier Bank Account
DANBDK22
Danske Bank
`;
const einvoice = new EInvoice();
await einvoice.loadFromString(ublInvoice);
// Check if key fields are preserved
const invoiceData = einvoice.getInvoiceData();
if (invoiceData) {
// Basic fields
expect(invoiceData.invoiceNumber).toBe('FIELD-MAP-001');
expect(invoiceData.issueDate).toContain('2025-01-25');
expect(invoiceData.dueDate).toContain('2025-02-25');
expect(invoiceData.currency).toBe('EUR');
// Supplier fields
if (invoiceData.supplier) {
expect(invoiceData.supplier.name).toContain('Supplier Company');
expect(invoiceData.supplier.vatNumber).toContain('DK12345678');
expect(invoiceData.supplier.address?.street).toContain('Main Street');
expect(invoiceData.supplier.address?.city).toBe('Copenhagen');
expect(invoiceData.supplier.address?.postalCode).toBe('1234');
expect(invoiceData.supplier.address?.country).toBe('DK');
}
// Customer fields
if (invoiceData.customer) {
expect(invoiceData.customer.name).toContain('Customer Company');
expect(invoiceData.customer.vatNumber).toContain('DK87654321');
expect(invoiceData.customer.address?.city).toBe('Aarhus');
}
console.log('Basic field mapping verified');
} else {
console.log('Field mapping through invoice data not available');
}
const elapsed = performance.now() - startTime;
performanceTracker.addMeasurement('basic-mapping', elapsed);
});
t.test('Complex nested field mapping', async () => {
const startTime = performance.now();
// CII invoice with nested structures
const ciiInvoice = `
urn:cen.eu:en16931:2017
NESTED-MAP-001
380
20250125
Complex nested structure test
AAI
Second note for testing
REG
1
Line item note
1234567890123
PROD-001
CUST-PROD-001
Complex Product
Product with multiple identifiers and attributes
Color
Blue
Size
Large
PO-LINE-001
120.00
false
10.00
12.00
Volume discount
108.00
10
VAT
S
19.00
1080.00
`;
const einvoice = new EInvoice();
await einvoice.loadFromString(ciiInvoice);
const xmlString = einvoice.getXmlString();
// Verify nested structures are preserved
expect(xmlString).toContain('NESTED-MAP-001');
expect(xmlString).toContain('Complex nested structure test');
expect(xmlString).toContain('PROD-001');
expect(xmlString).toContain('1234567890123');
expect(xmlString).toContain('Color');
expect(xmlString).toContain('Blue');
expect(xmlString).toContain('Volume discount');
console.log('Complex nested field mapping tested');
const elapsed = performance.now() - startTime;
performanceTracker.addMeasurement('nested-mapping', elapsed);
});
t.test('Field mapping with missing optional fields', async () => {
const startTime = performance.now();
// Minimal UBL invoice
const minimalUbl = `
MINIMAL-001
2025-01-25
380
EUR
Minimal Supplier
Minimal Customer
100.00
`;
const einvoice = new EInvoice();
await einvoice.loadFromString(minimalUbl);
const invoiceData = einvoice.getInvoiceData();
// Verify mandatory fields are mapped
expect(invoiceData?.invoiceNumber).toBe('MINIMAL-001');
expect(invoiceData?.issueDate).toContain('2025-01-25');
expect(invoiceData?.currency).toBe('EUR');
expect(invoiceData?.totalAmount).toBe(100.00);
// Optional fields should be undefined or have defaults
expect(invoiceData?.dueDate).toBeUndefined();
expect(invoiceData?.notes).toBeUndefined();
expect(invoiceData?.supplier?.vatNumber).toBeUndefined();
console.log('Minimal field mapping verified');
const elapsed = performance.now() - startTime;
performanceTracker.addMeasurement('minimal-mapping', elapsed);
});
t.test('Field type conversion mapping', async () => {
const startTime = performance.now();
// Invoice with various data types
const typeTestInvoice = `
TYPE-TEST-001
2025-01-25
14:30:00
380
EUR
5
2025-01-25
2025-01-01
2025-01-31
ORDER-123
SO-456
Type Test Supplier
Type Test Customer
false
0.05
50.00
1000.00
190.00
1000.00
190.00
S
19.00
VATEX-EU-O
`;
const einvoice = new EInvoice();
await einvoice.loadFromString(typeTestInvoice);
const xmlString = einvoice.getXmlString();
// Verify different data types are preserved
expect(xmlString).toContain('TYPE-TEST-001'); // String
expect(xmlString).toContain('2025-01-25'); // Date
expect(xmlString).toContain('14:30:00'); // Time
expect(xmlString).toContain('5'); // Integer
expect(xmlString).toContain('19.00'); // Decimal
expect(xmlString).toContain('false'); // Boolean
expect(xmlString).toContain('0.05'); // Float
console.log('Field type conversion mapping verified');
const elapsed = performance.now() - startTime;
performanceTracker.addMeasurement('type-conversion', elapsed);
});
t.test('Array field mapping', async () => {
const startTime = performance.now();
// Invoice with multiple repeated elements
const arrayInvoice = `
ARRAY-TEST-001
2025-01-25
380
First note
Second note
Third note with special chars: €£¥
EUR
DOC-001
Contract
DOC-002
Purchase Order
DOC-003
Delivery Note
1234567890123
DK12345678
123456789
Array Test Supplier
Array Test Customer
30
PAY-001
31
PAY-002
`;
const einvoice = new EInvoice();
await einvoice.loadFromString(arrayInvoice);
const xmlString = einvoice.getXmlString();
// Verify arrays are preserved
expect(xmlString).toContain('First note');
expect(xmlString).toContain('Second note');
expect(xmlString).toContain('Third note with special chars: €£¥');
expect(xmlString).toContain('DOC-001');
expect(xmlString).toContain('DOC-002');
expect(xmlString).toContain('DOC-003');
expect(xmlString).toContain('1234567890123');
expect(xmlString).toContain('DK12345678');
expect(xmlString).toContain('123456789');
console.log('Array field mapping verified');
const elapsed = performance.now() - startTime;
performanceTracker.addMeasurement('array-mapping', elapsed);
});
t.test('Cross-reference field mapping', async () => {
const startTime = performance.now();
// Invoice with cross-references between sections
const crossRefInvoice = `
XREF-TEST-001
2025-01-25
380
EUR
PROJ-2025-001
Cross Reference Supplier
Cross Reference Customer
2025-01-20
5790000435999
Delivery Street
Copenhagen
1
Delivered to GLN: 5790000435999
10
1000.00
ORDER-LINE-001
Product for PROJ-2025-001
100.00
`;
const einvoice = new EInvoice();
await einvoice.loadFromString(crossRefInvoice);
const xmlString = einvoice.getXmlString();
// Verify cross-references are maintained
expect(xmlString).toContain('PROJ-2025-001');
expect(xmlString).toContain('5790000435999');
expect(xmlString).toContain('Delivered to GLN: 5790000435999');
expect(xmlString).toContain('Product for PROJ-2025-001');
expect(xmlString).toContain('ORDER-LINE-001');
console.log('Cross-reference field mapping verified');
const elapsed = performance.now() - startTime;
performanceTracker.addMeasurement('cross-reference', elapsed);
});
t.test('Corpus field mapping validation', async () => {
const startTime = performance.now();
let processedCount = 0;
let mappingIssues = 0;
const criticalFields = ['ID', 'IssueDate', 'DocumentCurrencyCode', 'AccountingSupplierParty', 'AccountingCustomerParty'];
const files = await corpusLoader.getAllFiles();
const xmlFiles = files.filter(f => f.endsWith('.xml') && !f.includes('.pdf'));
// Test field mapping on corpus files
const sampleSize = Math.min(30, xmlFiles.length);
const sample = xmlFiles.slice(0, sampleSize);
for (const file of sample) {
try {
const content = await corpusLoader.readFile(file);
const einvoice = new EInvoice();
if (typeof content === 'string') {
await einvoice.loadFromString(content);
} else {
await einvoice.loadFromBuffer(content);
}
const xmlString = einvoice.getXmlString();
const invoiceData = einvoice.getInvoiceData();
// Check critical field mapping
let hasIssue = false;
if (invoiceData) {
if (!invoiceData.invoiceNumber && xmlString.includes('')) {
console.log(`${file}: Invoice number not mapped`);
hasIssue = true;
}
if (!invoiceData.issueDate && xmlString.includes('')) {
console.log(`${file}: Issue date not mapped`);
hasIssue = true;
}
if (!invoiceData.currency && xmlString.includes('')) {
console.log(`${file}: Currency not mapped`);
hasIssue = true;
}
}
if (hasIssue) mappingIssues++;
processedCount++;
} catch (error) {
console.log(`Field mapping error in ${file}:`, error.message);
}
}
console.log(`Corpus field mapping validation (${processedCount} files):`);
console.log(`- Files with potential mapping issues: ${mappingIssues}`);
const elapsed = performance.now() - startTime;
performanceTracker.addMeasurement('corpus-validation', elapsed);
});
// Print performance summary
performanceTracker.printSummary();
// Performance assertions
const avgTime = performanceTracker.getAverageTime();
expect(avgTime).toBeLessThan(300); // Field mapping should be reasonably fast
});
tap.start();