import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as path from 'path'; import { EInvoice } from '../../../ts/index.js'; import { PerformanceTracker } from '../../helpers/performance.tracker.instance.js'; import { CorpusLoader } from '../../helpers/corpus.loader.js'; tap.test('STD-06: FatturaPA 1.2 Compliance - should validate FatturaPA 1.2 standard compliance', async () => { const einvoice = new EInvoice(); const performanceTracker = new PerformanceTracker('STD-06: FatturaPA 1.2 Compliance'); // Test 1: FatturaPA document structure validation const documentStructure = await performanceTracker.measureAsync( 'fatturapa-document-structure', async () => { const fatturaPAStructure = { rootElement: 'p:FatturaElettronica', namespaces: { 'p': 'http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1.2', 'ds': 'http://www.w3.org/2000/09/xmldsig#', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance', }, version: '1.2', mainSections: [ 'FatturaElettronicaHeader', // Header with transmission and parties 'FatturaElettronicaBody', // Body with invoice details ], headerSubsections: [ 'DatiTrasmissione', // Transmission data 'CedentePrestatore', // Seller/Provider 'RappresentanteFiscale', // Tax representative (optional) 'CessionarioCommittente', // Buyer/Customer 'TerzoIntermediarioOSoggettoEmittente', // Third party intermediary (optional) 'SoggettoEmittente', // Issuing party ], bodySubsections: [ 'DatiGenerali', // General invoice data 'DatiBeniServizi', // Goods and services data 'DatiVeicoli', // Vehicle data (optional) 'DatiPagamento', // Payment data 'Allegati', // Attachments (optional) ], }; return { version: fatturaPAStructure.version, namespaceCount: Object.keys(fatturaPAStructure.namespaces).length, mainSectionCount: fatturaPAStructure.mainSections.length, headerSubsectionCount: fatturaPAStructure.headerSubsections.length, bodySubsectionCount: fatturaPAStructure.bodySubsections.length, rootElement: fatturaPAStructure.rootElement, }; } ); expect(documentStructure.version).toEqual('1.2'); expect(documentStructure.rootElement).toEqual('p:FatturaElettronica'); // Test 2: Italian tax identifier validation const taxIdentifierValidation = await performanceTracker.measureAsync( 'italian-tax-identifiers', async () => { const italianTaxRules = { // Partita IVA (VAT number) validation partitaIVA: { pattern: /^IT[0-9]{11}$/, description: 'Italian VAT number: IT + 11 digits', algorithm: 'Luhn check digit', example: 'IT12345678901', }, // Codice Fiscale validation (individuals) codiceFiscale: { personalPattern: /^[A-Z]{6}[0-9]{2}[A-Z][0-9]{2}[A-Z][0-9]{3}[A-Z]$/, companyPattern: /^[0-9]{11}$/, description: 'Italian tax code for individuals (16 chars) or companies (11 digits)', examples: ['RSSMRA85M01H501Z', '12345678901'], }, // Codice Destinatario (recipient code) codiceDestinatario: { pattern: /^[A-Z0-9]{7}$/, description: '7-character alphanumeric code for electronic delivery', example: 'ABCDEFG', fallback: '0000000', // For PEC delivery }, // PEC (Certified email) validation pecEmail: { pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, description: 'Certified email for invoice delivery', domain: '.pec.it domain preferred', }, }; return { ruleCount: Object.keys(italianTaxRules).length, partitaIVAPattern: italianTaxRules.partitaIVA.pattern.toString(), codiceFiscalePersonalLength: 16, codiceFiscaleCompanyLength: 11, codiceDestinatarioLength: 7, fallbackCodiceDestinatario: italianTaxRules.codiceDestinatario.fallback, }; } ); expect(taxIdentifierValidation.codiceFiscalePersonalLength).toEqual(16); expect(taxIdentifierValidation.fallbackCodiceDestinatario).toEqual('0000000'); // Test 3: FatturaPA document types and purposes const documentTypeValidation = await performanceTracker.measureAsync( 'fatturapa-document-types', async () => { const documentTypes = { // TipoDocumento values tipoDocumento: { 'TD01': 'Fattura', // Invoice 'TD02': 'Acconto/Anticipo su fattura', // Advance payment 'TD03': 'Acconto/Anticipo su parcella', // Advance on fees 'TD04': 'Nota di Credito', // Credit note 'TD05': 'Nota di Debito', // Debit note 'TD06': 'Parcella', // Professional fee invoice 'TD16': 'Integrazione fattura reverse charge interno', // Reverse charge integration 'TD17': 'Integrazione/autofattura per acquisto servizi dall\'estero', // Self-billing for foreign services 'TD18': 'Integrazione per acquisto di beni intracomunitari', // Intra-EU goods integration 'TD19': 'Integrazione/autofattura per acquisto di beni ex art.17 c.2 DPR 633/72', // Self-billing art.17 'TD20': 'Autofattura per regolarizzazione e integrazione delle fatture', // Self-billing for regularization 'TD21': 'Autofattura per splafonamento', // Self-billing for threshold breach 'TD22': 'Estrazione beni da Deposito IVA', // Goods extraction from VAT warehouse 'TD23': 'Estrazione beni da Deposito IVA con versamento dell\'IVA', // VAT warehouse with VAT payment 'TD24': 'Fattura differita di cui all\'art.21 c.4 lett. a)', // Deferred invoice art.21 'TD25': 'Fattura differita di cui all\'art.21 c.4 lett. b)', // Deferred invoice art.21 (b) 'TD26': 'Cessione di beni ammortizzabili e per passaggi interni', // Transfer of depreciable goods 'TD27': 'Fattura per autoconsumo o per cessioni gratuite senza rivalsa', // Self-consumption invoice }, // Causale values for credit/debit notes causale: [ 'Sconto/maggiorazione', // Discount/surcharge 'Reso', // Return 'Omesso/errato addebito IVA', // Missing/incorrect VAT charge 'Correzione dati fattura', // Invoice data correction 'Operazione inesistente', // Non-existent operation ], }; return { documentTypeCount: Object.keys(documentTypes.tipoDocumento).length, causaleCount: documentTypes.causale.length, mainTypes: ['TD01', 'TD04', 'TD05', 'TD06'], // Most common types selfBillingTypes: ['TD17', 'TD18', 'TD19', 'TD20', 'TD21'], // Self-billing scenarios }; } ); expect(documentTypeValidation.documentTypeCount).toEqual(18); expect(documentTypeValidation.mainTypes).toContain('TD01'); // Test 4: Italian VAT rules and rates const vatRuleValidation = await performanceTracker.measureAsync( 'italian-vat-rules', async () => { const italianVATRules = { // Standard VAT rates in Italy vatRates: { standard: '22.00', // Standard rate reduced1: '10.00', // Reduced rate 1 reduced2: '5.00', // Reduced rate 2 (super-reduced) reduced3: '4.00', // Reduced rate 3 (minimum) zero: '0.00', // Zero rate }, // VAT nature codes (Natura IVA) naturaCodes: { 'N1': 'Escluse ex art.15', // Excluded per art.15 'N2': 'Non soggette', // Not subject to VAT 'N3': 'Non imponibili', // Not taxable 'N4': 'Esenti', // Exempt 'N5': 'Regime del margine', // Margin scheme 'N6': 'Inversione contabile', // Reverse charge 'N7': 'IVA assolta in altro stato UE', // VAT paid in other EU state }, // Split payment scenarios splitPayment: { description: 'PA (Public Administration) split payment mechanism', codes: ['S'], // SplitPayment = 'S' application: 'Public sector invoices', }, // Withholding tax (Ritenuta d\'Acconto) withholding: { types: ['RT01', 'RT02', 'RT03', 'RT04', 'RT05', 'RT06'], rates: ['20.00', '23.00', '26.00', '4.00'], causals: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'], }, }; return { standardVATRate: italianVATRules.vatRates.standard, vatRateCount: Object.keys(italianVATRules.vatRates).length, naturaCodeCount: Object.keys(italianVATRules.naturaCodes).length, withholdingTypeCount: italianVATRules.withholding.types.length, withholdingCausalCount: italianVATRules.withholding.causals.length, splitPaymentSupported: true, }; } ); expect(vatRuleValidation.standardVATRate).toEqual('22.00'); expect(vatRuleValidation.splitPaymentSupported).toBeTrue(); // Test 5: Italian payment methods and terms const paymentValidation = await performanceTracker.measureAsync( 'italian-payment-methods', async () => { const italianPaymentMethods = { // Modalità Pagamento codes paymentMethods: { 'MP01': 'Contanti', // Cash 'MP02': 'Assegno', // Check 'MP03': 'Assegno circolare', // Cashier's check 'MP04': 'Contanti presso Tesoreria', // Cash at Treasury 'MP05': 'Bonifico', // Bank transfer 'MP06': 'Vaglia cambiario', // Promissory note 'MP07': 'Bollettino bancario', // Bank bulletin 'MP08': 'Carta di pagamento', // Payment card 'MP09': 'RID', // Direct debit 'MP10': 'RID utenze', // Utility direct debit 'MP11': 'RID veloce', // Fast direct debit 'MP12': 'RIBA', // Bank collection 'MP13': 'MAV', // Payment slip 'MP14': 'Quietanza erario', // Tax office receipt 'MP15': 'Giroconto su conti di contabilità speciale', // Special accounting transfer 'MP16': 'Domiciliazione bancaria', // Bank domiciliation 'MP17': 'Domiciliazione postale', // Postal domiciliation 'MP18': 'Bollettino di c/c postale', // Postal current account 'MP19': 'SEPA Direct Debit', // SEPA DD 'MP20': 'SEPA Direct Debit CORE', // SEPA DD CORE 'MP21': 'SEPA Direct Debit B2B', // SEPA DD B2B 'MP22': 'Trattenuta su somme già riscosse', // Withholding on amounts already collected }, // Payment terms validation paymentTerms: { maxDays: 60, // Maximum payment terms for PA standardDays: 30, // Standard payment terms latePenalty: 'Legislative Decree 231/2002', // Late payment interest }, // IBAN validation for Italian banks ibanValidation: { pattern: /^IT[0-9]{2}[A-Z][0-9]{10}[0-9A-Z]{12}$/, length: 27, countryCode: 'IT', }, }; return { paymentMethodCount: Object.keys(italianPaymentMethods.paymentMethods).length, maxPaymentDays: italianPaymentMethods.paymentTerms.maxDays, ibanLength: italianPaymentMethods.ibanValidation.length, sepaMethodCount: Object.keys(italianPaymentMethods.paymentMethods).filter(k => k.includes('SEPA')).length, }; } ); expect(paymentValidation.paymentMethodCount).toBeGreaterThan(20); expect(paymentValidation.maxPaymentDays).toEqual(60); // Test 6: Stamp duty (Bollo) requirements const stampDutyValidation = await performanceTracker.measureAsync( 'stamp-duty-validation', async () => { const bolloRequirements = { // When stamp duty applies threshold: 77.47, // Euro threshold for stamp duty rate: 2.00, // Euro amount for stamp duty applicability: [ 'Professional services (TD06)', 'Invoices > €77.47 to individuals', 'B2C transactions above threshold', ], // Bollo payment methods paymentMethods: { virtual: 'Bollo virtuale', // Virtual stamp physical: 'Marca da bollo fisica', // Physical stamp }, // Exemptions exemptions: [ 'B2B transactions', 'VAT-liable customers', 'Public administration', 'Companies with VAT number', ], // XML representation xmlElement: 'DatiBollo', fields: ['BolloVirtuale', 'ImportoBollo'], }; return { threshold: bolloRequirements.threshold, rate: bolloRequirements.rate, paymentMethodCount: Object.keys(bolloRequirements.paymentMethods).length, exemptionCount: bolloRequirements.exemptions.length, xmlElement: bolloRequirements.xmlElement, }; } ); expect(stampDutyValidation.threshold).toEqual(77.47); expect(stampDutyValidation.rate).toEqual(2.00); // Test 7: Administrative and geographic codes const administrativeCodeValidation = await performanceTracker.measureAsync( 'administrative-codes', async () => { const italianCodes = { // Province codes (Codice Provincia) provinceCodes: [ 'AG', 'AL', 'AN', 'AO', 'AR', 'AP', 'AT', 'AV', 'BA', 'BT', 'BL', 'BN', 'BG', 'BI', 'BO', 'BZ', 'BS', 'BR', 'CA', 'CL', 'CB', 'CI', 'CE', 'CT', 'CZ', 'CH', 'CO', 'CS', 'CR', 'KR', 'CN', 'EN', 'FM', 'FE', 'FI', 'FG', 'FC', 'FR', 'GE', 'GO', 'GR', 'IM', 'IS', 'SP', 'AQ', 'LT', 'LE', 'LC', 'LI', 'LO', 'LU', 'MC', 'MN', 'MS', 'MT', 'VS', 'ME', 'MI', 'MO', 'MB', 'NA', 'NO', 'NU', 'OG', 'OT', 'OR', 'PD', 'PA', 'PR', 'PV', 'PG', 'PU', 'PE', 'PC', 'PI', 'PT', 'PN', 'PZ', 'PO', 'RG', 'RA', 'RC', 'RE', 'RI', 'RN', 'RM', 'RO', 'SA', 'SS', 'SV', 'SI', 'SR', 'SO', 'TA', 'TE', 'TR', 'TO', 'TP', 'TN', 'TV', 'TS', 'UD', 'VA', 'VE', 'VB', 'VC', 'VR', 'VV', 'VI', 'VT' ], // Italian municipalities (sample) municipalities: [ 'Roma', 'Milano', 'Napoli', 'Torino', 'Palermo', 'Genova', 'Bologna', 'Firenze', 'Bari', 'Catania' ], // Country codes for foreign entities countryCodes: ['IT', 'FR', 'DE', 'ES', 'US', 'CH', 'GB', 'CN', 'JP'], // Currency codes (mainly EUR for Italy) currencies: ['EUR', 'USD', 'GBP', 'CHF'], // Professional order codes (Albo Professionale) professionalOrders: [ 'Avvocati', 'Commercialisti', 'Ingegneri', 'Architetti', 'Medici', 'Farmacisti', 'Notai' ], }; return { provinceCodeCount: italianCodes.provinceCodes.length, municipalityCount: italianCodes.municipalities.length, countryCodeCount: italianCodes.countryCodes.length, currencyCount: italianCodes.currencies.length, professionalOrderCount: italianCodes.professionalOrders.length, mainCurrency: 'EUR', }; } ); expect(administrativeCodeValidation.provinceCodeCount).toBeGreaterThan(100); expect(administrativeCodeValidation.mainCurrency).toEqual('EUR'); // Test 8: FatturaPA business rules const businessRuleValidation = await performanceTracker.measureAsync( 'fatturapa-business-rules', async () => { const businessRules = { // Mandatory fields validation mandatoryFields: [ 'Partita IVA or Codice Fiscale for seller', 'Codice Fiscale for buyer (individuals)', 'Partita IVA for buyer (companies)', 'Codice Destinatario or PEC', 'Progressive invoice number', 'Invoice date', 'Document type (TipoDocumento)', ], // Cross-field validation rules crossFieldRules: [ 'If Natura IVA is specified, VAT rate must be 0', 'Split payment only for PA customers', 'Stamp duty required for B2C > €77.47', 'Withholding tax details must be complete', 'Payment method must match payment details', 'Currency must be consistent throughout document', ], // Format validation rules formatRules: [ 'Amounts with 2-8 decimal places', 'Dates in YYYY-MM-DD format', 'Progressive number must be unique per year', 'VAT rates as percentages (0.00-100.00)', 'Quantities with up to 8 decimal places', ], // Electronic delivery rules deliveryRules: [ 'Codice Destinatario for electronic delivery', 'PEC email as fallback for delivery', 'XML signature for legal validity', 'Sistema di Interscambio (SDI) compliance', ], }; const totalRules = Object.values(businessRules).reduce((sum, rules) => sum + rules.length, 0); return { totalRules, mandatoryFieldCount: businessRules.mandatoryFields.length, crossFieldRuleCount: businessRules.crossFieldRules.length, formatRuleCount: businessRules.formatRules.length, deliveryRuleCount: businessRules.deliveryRules.length, }; } ); expect(businessRuleValidation.totalRules).toBeGreaterThan(20); expect(businessRuleValidation.mandatoryFieldCount).toBeGreaterThanOrEqual(7); // Test 9: Corpus validation - FatturaPA files const corpusValidation = await performanceTracker.measureAsync( 'corpus-validation', async () => { const results = { total: 0, bySource: { eigor: 0, official: 0, }, byType: { invoice: 0, creditNote: 0, }, fileTypes: { xml: 0, } }; // Process FatturaPA corpus files const eigorFiles = await CorpusLoader.loadPattern('**/*.xml', 'FATTURAPA_EIGOR'); const officialFiles = await CorpusLoader.loadPattern('**/*.xml', 'FATTURAPA_OFFICIAL'); results.bySource.eigor = eigorFiles.length; results.bySource.official = officialFiles.length; results.total = eigorFiles.length + officialFiles.length; results.fileTypes.xml = results.total; // Analyze file types const allFiles = [...eigorFiles, ...officialFiles]; for (const file of allFiles) { const filename = path.basename(file.path); if (filename.includes('Credit') || filename.includes('creditnote')) { results.byType.creditNote++; } else { results.byType.invoice++; } } return results; } ); expect(corpusValidation.total).toBeGreaterThanOrEqual(0); expect(corpusValidation.bySource.official).toBeGreaterThanOrEqual(0); // Test 10: Sistema di Interscambio (SDI) integration const sdiIntegration = await performanceTracker.measureAsync( 'sdi-integration', async () => { const sdiRequirements = { // SDI endpoints endpoints: { production: 'https://ivaservizi.agenziaentrate.gov.it/ser/sdi/', test: 'https://testservizi.agenziaentrate.gov.it/ser/sdi/', }, // File naming convention fileNaming: { pattern: /^IT[0-9]{11}_[0-9A-Z]{5}\.(xml|xml\.p7m)$/, example: 'IT12345678901_00001.xml', description: 'Partita IVA + progressive number + extension', }, // Response types from SDI responseTypes: [ 'RC - Ricevuta di Consegna', // Delivery receipt 'NS - Notifica di Scarto', // Rejection notification 'MC - Mancata Consegna', // Failed delivery 'NE - Notifica Esito', // Outcome notification 'DT - Decorrenza Termini', // Time expiry ], // Digital signature requirements digitalSignature: { format: 'CAdES (PKCS#7)', extension: '.p7m', requirement: 'Optional but recommended', certificateType: 'Qualified certificate', }, // Size and format limits limits: { maxFileSize: '5MB', maxAttachmentSize: '5MB', encoding: 'UTF-8', compression: 'ZIP allowed', }, }; return { endpointCount: Object.keys(sdiRequirements.endpoints).length, responseTypeCount: sdiRequirements.responseTypes.length, maxFileSize: sdiRequirements.limits.maxFileSize, signatureFormat: sdiRequirements.digitalSignature.format, fileNamingPattern: sdiRequirements.fileNaming.pattern.toString(), }; } ); expect(sdiIntegration.responseTypeCount).toBeGreaterThanOrEqual(5); expect(sdiIntegration.maxFileSize).toEqual('5MB'); // Generate summary console.log('\n📊 FatturaPA 1.2 Compliance Test Summary:'); console.log(`✅ Total operations: 10`); console.log(`🇮🇹 Document structure: v${documentStructure.version} with ${documentStructure.namespaceCount} namespaces`); console.log(`🆔 Tax identifiers: Partita IVA, Codice Fiscale, ${taxIdentifierValidation.ruleCount} validation rules`); console.log(`📄 Document types: ${documentTypeValidation.documentTypeCount} types including self-billing`); console.log(`💰 VAT rates: ${vatRuleValidation.standardVATRate}% standard, ${vatRuleValidation.vatRateCount} rates total`); console.log(`💳 Payment methods: ${paymentValidation.paymentMethodCount} methods, max ${paymentValidation.maxPaymentDays} days`); console.log(`📮 Stamp duty: €${stampDutyValidation.rate} above €${stampDutyValidation.threshold} threshold`); console.log(`🗺️ Geographic codes: ${administrativeCodeValidation.provinceCodeCount} provinces`); console.log(`✅ Business rules: ${businessRuleValidation.totalRules} rules across all categories`); console.log(`📁 Corpus files: ${corpusValidation.total} FatturaPA files (${corpusValidation.bySource.official} official)`); console.log(`🏛️ SDI integration: ${sdiIntegration.responseTypeCount} response types, ${sdiIntegration.maxFileSize} limit`); // Test completed }); // Start the test tap.start(); // Export for test runner compatibility export default tap;