import { tap, expect } from '@git.zone/tstest/tapbundle'; import { EInvoice } from '../../../ts/index.js'; import { InvoiceFormat, ValidationLevel } from '../../../ts/interfaces/common.js'; import { CorpusLoader, PerformanceTracker } from '../../helpers/test-utils.js'; import * as path from 'path'; /** * Test ID: CORP-05 * Test Description: FatturaPA Corpus Processing * Priority: Medium * * This test validates processing of Italian FatturaPA format files, * including structure validation and conversion capabilities. */ tap.test('CORP-05: FatturaPA Corpus Processing - should process Italian FatturaPA files', async (t) => { // Load FatturaPA test files const fatturapaFiles = await CorpusLoader.loadCategory('FATTURAPA'); console.log(`Testing ${fatturapaFiles.length} FatturaPA files`); const results = { total: fatturapaFiles.length, successful: 0, failed: 0, parseErrors: 0, validationErrors: 0, documentTypes: new Map(), transmissionFormats: new Map(), processingTimes: [] as number[] }; const failures: Array<{ file: string; error: string; type: 'parse' | 'validation' | 'format'; }> = []; // Italian-specific validation patterns const italianValidations = { vatNumber: /^IT\d{11}$/, fiscalCode: /^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/, invoiceNumber: /^\w+\/\d{4}$/, // Common format: PREFIX/YEAR codiceDestinatario: /^[A-Z0-9]{6,7}$/, pecEmail: /^[a-zA-Z0-9._%+-]+@pec\.[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ }; for (const file of fatturapaFiles) { try { const xmlBuffer = await CorpusLoader.loadFile(file.path); const xmlString = xmlBuffer.toString('utf-8'); // Track performance const { result: invoice, metric } = await PerformanceTracker.track( 'fatturapa-processing', async () => { const einvoice = new EInvoice(); // FatturaPA has specific XML structure if (xmlString.includes('FatturaElettronica')) { // Process as FatturaPA await einvoice.fromXmlString(xmlString); einvoice.metadata = { ...einvoice.metadata, format: InvoiceFormat.FATTURAPA }; } else { throw new Error('Not a valid FatturaPA file'); } return einvoice; }, { file: file.path, size: file.size } ); results.processingTimes.push(metric.duration); // Extract FatturaPA specific information const formatMatch = xmlString.match(/([^<]+)<\/FormatoTrasmissione>/); const typeMatch = xmlString.match(/([^<]+)<\/TipoDocumento>/); if (formatMatch) { const format = formatMatch[1]; results.transmissionFormats.set(format, (results.transmissionFormats.get(format) || 0) + 1); } if (typeMatch) { const docType = typeMatch[1]; results.documentTypes.set(docType, (results.documentTypes.get(docType) || 0) + 1); } // Validate Italian-specific fields const vatMatch = xmlString.match(/(\d{11})<\/IdCodice>/); const cfMatch = xmlString.match(/([A-Z0-9]{16})<\/CodiceFiscale>/); const destMatch = xmlString.match(/([A-Z0-9]{6,7})<\/CodiceDestinatario>/); let italianFieldsValid = true; if (vatMatch && !italianValidations.vatNumber.test('IT' + vatMatch[1])) { italianFieldsValid = false; t.fail(` - Invalid VAT number format: ${vatMatch[1]}`); } if (cfMatch && !italianValidations.fiscalCode.test(cfMatch[1])) { italianFieldsValid = false; t.fail(` - Invalid Codice Fiscale format: ${cfMatch[1]}`); } if (destMatch && !italianValidations.codiceDestinatario.test(destMatch[1])) { italianFieldsValid = false; t.fail(` - Invalid Codice Destinatario: ${destMatch[1]}`); } // Validate the parsed invoice try { const validationResult = await invoice.validate(ValidationLevel.BASIC); if (validationResult.valid && italianFieldsValid) { results.successful++; t.pass(`✓ ${path.basename(file.path)}: Successfully processed`); // Log key information if (formatMatch) { t.pass(` - Transmission format: ${formatMatch[1]}`); } if (typeMatch) { const docTypeMap: Record = { 'TD01': 'Fattura', 'TD02': 'Acconto/Anticipo', 'TD03': 'Acconto/Anticipo su parcella', 'TD04': 'Nota di Credito', 'TD05': 'Nota di Debito', 'TD06': 'Parcella' }; t.pass(` - Document type: ${docTypeMap[typeMatch[1]] || typeMatch[1]}`); } } else { results.validationErrors++; failures.push({ file: path.basename(file.path), error: validationResult.errors?.[0]?.message || 'Validation failed', type: 'validation' }); } } catch (validationError: any) { results.validationErrors++; failures.push({ file: path.basename(file.path), error: validationError.message, type: 'validation' }); } } catch (error: any) { results.failed++; if (error.message.includes('Not a valid FatturaPA')) { failures.push({ file: path.basename(file.path), error: 'Invalid FatturaPA format', type: 'format' }); } else { results.parseErrors++; failures.push({ file: path.basename(file.path), error: error.message, type: 'parse' }); } t.fail(`✗ ${path.basename(file.path)}: ${error.message}`); } } // Summary report console.log('\n=== FatturaPA Corpus Processing Summary ==='); console.log(`Total files: ${results.total}`); console.log(`Successful: ${results.successful} (${(results.successful/results.total*100).toFixed(1)}%)`); console.log(`Failed: ${results.failed}`); console.log(` - Parse errors: ${results.parseErrors}`); console.log(` - Validation errors: ${results.validationErrors}`); console.log('\nTransmission Formats:'); results.transmissionFormats.forEach((count, format) => { const formatMap: Record = { 'FPA12': 'Pubblica Amministrazione', 'FPR12': 'Privati', 'SDI11': 'Sistema di Interscambio v1.1' }; console.log(` - ${format}: ${formatMap[format] || format} (${count} files)`); }); console.log('\nDocument Types:'); results.documentTypes.forEach((count, type) => { const typeMap: Record = { 'TD01': 'Fattura (Invoice)', 'TD02': 'Acconto/Anticipo (Advance)', 'TD03': 'Acconto/Anticipo su parcella', 'TD04': 'Nota di Credito (Credit Note)', 'TD05': 'Nota di Debito (Debit Note)', 'TD06': 'Parcella (Fee Note)' }; console.log(` - ${type}: ${typeMap[type] || type} (${count} files)`); }); if (failures.length > 0) { console.log('\nFailure Details:'); failures.forEach(f => { console.log(` ${f.file} [${f.type}]: ${f.error}`); }); } // Performance metrics if (results.processingTimes.length > 0) { const avgTime = results.processingTimes.reduce((a, b) => a + b, 0) / results.processingTimes.length; const minTime = Math.min(...results.processingTimes); const maxTime = Math.max(...results.processingTimes); console.log('\nPerformance Metrics:'); console.log(` Average processing time: ${avgTime.toFixed(2)}ms`); console.log(` Min time: ${minTime.toFixed(2)}ms`); console.log(` Max time: ${maxTime.toFixed(2)}ms`); } // FatturaPA specific features test t.test('FatturaPA specific features', async (st) => { if (results.successful > 0) { // Test a sample file for specific features const sampleFile = fatturapaFiles[0]; const xmlBuffer = await CorpusLoader.loadFile(sampleFile.path); const xmlString = xmlBuffer.toString('utf-8'); // Check for mandatory sections const mandatorySections = [ 'FatturaElettronicaHeader', 'CedentePrestatore', // Seller 'CessionarioCommittente', // Buyer 'FatturaElettronicaBody', 'DatiGenerali', 'DatiBeniServizi' ]; for (const section of mandatorySections) { if (xmlString.includes(section)) { st.pass(`✓ Contains mandatory section: ${section}`); } } // Check for digital signature block if (xmlString.includes('