546 lines
23 KiB
TypeScript
546 lines
23 KiB
TypeScript
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; |