fix(tests): update test patterns and fix assertion syntax
- Change tap test signatures from async (t) => to async () => - Replace t.ok(), t.notOk(), t.equal() with expect() assertions - Fix import paths for helpers to use correct ../../helpers/ path - Update PerformanceTracker to use instance version - Add missing expect imports from tapbundle - Remove t.end() calls that are no longer needed - Ensure all tests have tap.start() for proper execution
This commit is contained in:
@ -1,7 +1,8 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import { EInvoice } from '../../../ts/index.js';
|
||||
import { InvoiceFormat } from '../../../ts/interfaces/common.js';
|
||||
import { CorpusLoader, PerformanceTracker } from '../../helpers/test-utils.js';
|
||||
import { CorpusLoader } from '../../helpers/corpus.loader.js';
|
||||
import { PerformanceTracker } from '../../helpers/performance.tracker.instance.js';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
@ -13,305 +14,303 @@ import * as path from 'path';
|
||||
* including XRechnung (Germany), FatturaPA (Italy), and PEPPOL BIS variations.
|
||||
*/
|
||||
|
||||
tap.test('STD-10: Country-Specific Extensions - should handle country extensions correctly', async (t) => {
|
||||
// Test 1: German XRechnung Extensions
|
||||
tap.test('STD-10: German XRechnung specific requirements', async () => {
|
||||
const invoice = new EInvoice();
|
||||
|
||||
// Test 1: German XRechnung Extensions
|
||||
t.test('German XRechnung specific requirements', async (st) => {
|
||||
const invoice = new EInvoice();
|
||||
|
||||
// XRechnung specific fields
|
||||
invoice.id = 'XRECHNUNG-001';
|
||||
invoice.issueDate = new Date();
|
||||
invoice.metadata = {
|
||||
format: InvoiceFormat.XRECHNUNG,
|
||||
extensions: {
|
||||
'BT-DE-1': 'Payment conditions text', // German specific
|
||||
'BT-DE-2': 'Buyer reference', // Leitweg-ID
|
||||
'BT-DE-3': 'Project reference',
|
||||
'BT-DE-4': 'Contract reference',
|
||||
'BT-DE-5': 'Order reference'
|
||||
}
|
||||
};
|
||||
|
||||
// Leitweg-ID validation (German routing ID)
|
||||
const leitwegId = '04011000-12345-67';
|
||||
const leitwegPattern = /^\d{8,12}-\d{1,30}-\d{1,2}$/;
|
||||
|
||||
expect(leitwegPattern.test(leitwegId)).toBeTrue();
|
||||
st.pass('✓ Valid Leitweg-ID format');
|
||||
|
||||
// Bank transfer requirements
|
||||
invoice.paymentTerms = {
|
||||
method: 'SEPA',
|
||||
iban: 'DE89370400440532013000',
|
||||
bic: 'DEUTDEFF',
|
||||
reference: 'RF18539007547034'
|
||||
};
|
||||
|
||||
// IBAN validation for Germany
|
||||
const germanIbanPattern = /^DE\d{20}$/;
|
||||
expect(germanIbanPattern.test(invoice.paymentTerms.iban)).toBeTrue();
|
||||
st.pass('✓ Valid German IBAN format');
|
||||
|
||||
// XRechnung profile requirements
|
||||
const xrechnungProfiles = [
|
||||
'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0',
|
||||
'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1',
|
||||
'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2'
|
||||
];
|
||||
|
||||
expect(xrechnungProfiles.length).toBeGreaterThan(0);
|
||||
st.pass('✓ XRechnung profile identifiers defined');
|
||||
});
|
||||
|
||||
// Test 2: Italian FatturaPA Extensions
|
||||
t.test('Italian FatturaPA specific requirements', async (st) => {
|
||||
// FatturaPA specific structure
|
||||
const fatturapaRequirements = {
|
||||
transmissionFormat: {
|
||||
FormatoTrasmissione: 'FPR12', // Private B2B
|
||||
CodiceDestinatario: '0000000', // 7 digits
|
||||
PECDestinatario: 'pec@example.it'
|
||||
},
|
||||
cedentePrestatore: {
|
||||
DatiAnagrafici: {
|
||||
IdFiscaleIVA: {
|
||||
IdPaese: 'IT',
|
||||
IdCodice: '12345678901' // 11 digits
|
||||
},
|
||||
CodiceFiscale: 'RSSMRA80A01H501U' // 16 chars
|
||||
}
|
||||
},
|
||||
documentType: '1.2.1' // Version
|
||||
};
|
||||
|
||||
// Validate Italian VAT number
|
||||
const italianVATPattern = /^IT\d{11}$/;
|
||||
const testVAT = 'IT' + fatturapaRequirements.cedentePrestatore.DatiAnagrafici.IdFiscaleIVA.IdCodice;
|
||||
expect(italianVATPattern.test(testVAT)).toBeTrue();
|
||||
st.pass('✓ Valid Italian VAT number format');
|
||||
|
||||
// Validate Codice Fiscale
|
||||
const codiceFiscalePattern = /^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/;
|
||||
expect(codiceFiscalePattern.test(fatturapaRequirements.cedentePrestatore.DatiAnagrafici.CodiceFiscale)).toBeTrue();
|
||||
st.pass('✓ Valid Italian Codice Fiscale format');
|
||||
|
||||
// Validate Codice Destinatario
|
||||
expect(fatturapaRequirements.transmissionFormat.CodiceDestinatario).toMatch(/^\d{7}$/);
|
||||
st.pass('✓ Valid Codice Destinatario format');
|
||||
|
||||
// Document numbering requirements
|
||||
const italianInvoiceNumber = '2024/001';
|
||||
expect(italianInvoiceNumber).toMatch(/^\d{4}\/\d+$/);
|
||||
st.pass('✓ Valid Italian invoice number format');
|
||||
});
|
||||
|
||||
// Test 3: French Factur-X Extensions
|
||||
t.test('French Factur-X specific requirements', async (st) => {
|
||||
const invoice = new EInvoice();
|
||||
invoice.id = 'FX-FR-001';
|
||||
invoice.issueDate = new Date();
|
||||
|
||||
// French specific requirements
|
||||
const frenchExtensions = {
|
||||
siret: '12345678901234', // 14 digits
|
||||
naf: '6201Z', // NAF/APE code
|
||||
tvaIntracommunautaire: 'FR12345678901',
|
||||
mentionsLegales: 'SARL au capital de 10000 EUR',
|
||||
chorus: {
|
||||
serviceCode: 'SERVICE123',
|
||||
engagementNumber: 'ENG123456'
|
||||
}
|
||||
};
|
||||
|
||||
// Validate SIRET (14 digits)
|
||||
expect(frenchExtensions.siret).toMatch(/^\d{14}$/);
|
||||
st.pass('✓ Valid French SIRET format');
|
||||
|
||||
// Validate French VAT number
|
||||
const frenchVATPattern = /^FR[0-9A-Z]{2}\d{9}$/;
|
||||
expect(frenchVATPattern.test(frenchExtensions.tvaIntracommunautaire)).toBeTrue();
|
||||
st.pass('✓ Valid French VAT number format');
|
||||
|
||||
// Validate NAF/APE code
|
||||
expect(frenchExtensions.naf).toMatch(/^\d{4}[A-Z]$/);
|
||||
st.pass('✓ Valid French NAF/APE code format');
|
||||
|
||||
// Chorus Pro integration (French public sector)
|
||||
if (frenchExtensions.chorus.serviceCode) {
|
||||
st.pass('✓ Chorus Pro service code present');
|
||||
// XRechnung specific fields
|
||||
invoice.id = 'XRECHNUNG-001';
|
||||
invoice.issueDate = new Date();
|
||||
invoice.metadata = {
|
||||
format: InvoiceFormat.XRECHNUNG,
|
||||
extensions: {
|
||||
'BT-DE-1': 'Payment conditions text', // German specific
|
||||
'BT-DE-2': 'Buyer reference', // Leitweg-ID
|
||||
'BT-DE-3': 'Project reference',
|
||||
'BT-DE-4': 'Contract reference',
|
||||
'BT-DE-5': 'Order reference'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Test 4: Belgian Extensions
|
||||
t.test('Belgian e-invoicing extensions', async (st) => {
|
||||
const belgianExtensions = {
|
||||
merchantAgreementReference: 'BE-MERCH-001',
|
||||
vatNumber: 'BE0123456789',
|
||||
bancontact: {
|
||||
enabled: true,
|
||||
reference: 'BC123456'
|
||||
},
|
||||
languages: ['nl', 'fr', 'de'], // Belgium has 3 official languages
|
||||
regionalCodes: {
|
||||
flanders: 'VL',
|
||||
wallonia: 'WA',
|
||||
brussels: 'BR'
|
||||
// Leitweg-ID validation (German routing ID)
|
||||
const leitwegId = '04011000-12345-67';
|
||||
const leitwegPattern = /^\d{8,12}-\d{1,30}-\d{1,2}$/;
|
||||
|
||||
expect(leitwegPattern.test(leitwegId)).toBeTrue();
|
||||
console.log('✓ Valid Leitweg-ID format');
|
||||
|
||||
// Bank transfer requirements
|
||||
invoice.paymentTerms = {
|
||||
method: 'SEPA',
|
||||
iban: 'DE89370400440532013000',
|
||||
bic: 'DEUTDEFF',
|
||||
reference: 'RF18539007547034'
|
||||
};
|
||||
|
||||
// IBAN validation for Germany
|
||||
const germanIbanPattern = /^DE\d{20}$/;
|
||||
expect(germanIbanPattern.test(invoice.paymentTerms.iban)).toBeTrue();
|
||||
console.log('✓ Valid German IBAN format');
|
||||
|
||||
// XRechnung profile requirements
|
||||
const xrechnungProfiles = [
|
||||
'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0',
|
||||
'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1',
|
||||
'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2'
|
||||
];
|
||||
|
||||
expect(xrechnungProfiles.length).toBeGreaterThan(0);
|
||||
console.log('✓ XRechnung profile identifiers defined');
|
||||
});
|
||||
|
||||
// Test 2: Italian FatturaPA Extensions
|
||||
tap.test('STD-10: Italian FatturaPA specific requirements', async () => {
|
||||
// FatturaPA specific structure
|
||||
const fatturapaRequirements = {
|
||||
transmissionFormat: {
|
||||
FormatoTrasmissione: 'FPR12', // Private B2B
|
||||
CodiceDestinatario: '0000000', // 7 digits
|
||||
PECDestinatario: 'pec@example.it'
|
||||
},
|
||||
cedentePrestatore: {
|
||||
DatiAnagrafici: {
|
||||
IdFiscaleIVA: {
|
||||
IdPaese: 'IT',
|
||||
IdCodice: '12345678901' // 11 digits
|
||||
},
|
||||
CodiceFiscale: 'RSSMRA80A01H501U' // 16 chars
|
||||
}
|
||||
};
|
||||
|
||||
// Validate Belgian VAT number (BE followed by 10 digits)
|
||||
expect(belgianExtensions.vatNumber).toMatch(/^BE\d{10}$/);
|
||||
st.pass('✓ Valid Belgian VAT number format');
|
||||
|
||||
// Language requirements
|
||||
expect(belgianExtensions.languages).toContain('nl');
|
||||
expect(belgianExtensions.languages).toContain('fr');
|
||||
st.pass('✓ Supports required Belgian languages');
|
||||
});
|
||||
},
|
||||
documentType: '1.2.1' // Version
|
||||
};
|
||||
|
||||
// Test 5: Nordic Countries Extensions
|
||||
t.test('Nordic countries specific requirements', async (st) => {
|
||||
// Swedish requirements
|
||||
const swedishExtensions = {
|
||||
organisationNumber: '1234567890', // 10 digits
|
||||
vatNumber: 'SE123456789001',
|
||||
bankgiro: '123-4567',
|
||||
plusgiro: '12 34 56-7',
|
||||
referenceType: 'OCR', // Swedish payment reference
|
||||
ocrReference: '12345678901234567890'
|
||||
};
|
||||
|
||||
// Norwegian requirements
|
||||
const norwegianExtensions = {
|
||||
organisationNumber: '123456789', // 9 digits
|
||||
vatNumber: 'NO123456789MVA',
|
||||
kidNumber: '1234567890123', // Payment reference
|
||||
iban: 'NO9386011117947'
|
||||
};
|
||||
|
||||
// Danish requirements
|
||||
const danishExtensions = {
|
||||
cvrNumber: '12345678', // 8 digits
|
||||
eanLocation: '5790000123456', // 13 digits
|
||||
vatNumber: 'DK12345678',
|
||||
nemKonto: true // Danish public payment system
|
||||
};
|
||||
|
||||
// Validate formats
|
||||
expect(swedishExtensions.vatNumber).toMatch(/^SE\d{12}$/);
|
||||
st.pass('✓ Valid Swedish VAT format');
|
||||
|
||||
expect(norwegianExtensions.vatNumber).toMatch(/^NO\d{9}MVA$/);
|
||||
st.pass('✓ Valid Norwegian VAT format');
|
||||
|
||||
expect(danishExtensions.cvrNumber).toMatch(/^\d{8}$/);
|
||||
st.pass('✓ Valid Danish CVR format');
|
||||
});
|
||||
// Validate Italian VAT number
|
||||
const italianVATPattern = /^IT\d{11}$/;
|
||||
const testVAT = 'IT' + fatturapaRequirements.cedentePrestatore.DatiAnagrafici.IdFiscaleIVA.IdCodice;
|
||||
expect(italianVATPattern.test(testVAT)).toBeTrue();
|
||||
console.log('✓ Valid Italian VAT number format');
|
||||
|
||||
// Test 6: PEPPOL BIS Country Variations
|
||||
t.test('PEPPOL BIS country-specific profiles', async (st) => {
|
||||
const peppolProfiles = {
|
||||
'PEPPOL-BIS-3.0': 'Base profile',
|
||||
'PEPPOL-BIS-3.0-AU': 'Australian extension',
|
||||
'PEPPOL-BIS-3.0-NZ': 'New Zealand extension',
|
||||
'PEPPOL-BIS-3.0-SG': 'Singapore extension',
|
||||
'PEPPOL-BIS-3.0-MY': 'Malaysian extension'
|
||||
};
|
||||
|
||||
// Country-specific identifiers
|
||||
const countryIdentifiers = {
|
||||
AU: { scheme: '0151', name: 'ABN' }, // Australian Business Number
|
||||
NZ: { scheme: '0088', name: 'NZBN' }, // NZ Business Number
|
||||
SG: { scheme: '0195', name: 'UEN' }, // Unique Entity Number
|
||||
MY: { scheme: '0199', name: 'MyBRN' } // Malaysian Business Registration
|
||||
};
|
||||
|
||||
// Test identifier schemes
|
||||
for (const [country, identifier] of Object.entries(countryIdentifiers)) {
|
||||
expect(identifier.scheme).toMatch(/^\d{4}$/);
|
||||
st.pass(`✓ ${country}: Valid PEPPOL identifier scheme ${identifier.scheme} (${identifier.name})`);
|
||||
}
|
||||
});
|
||||
// Validate Codice Fiscale
|
||||
const codiceFiscalePattern = /^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/;
|
||||
expect(codiceFiscalePattern.test(fatturapaRequirements.cedentePrestatore.DatiAnagrafici.CodiceFiscale)).toBeTrue();
|
||||
console.log('✓ Valid Italian Codice Fiscale format');
|
||||
|
||||
// Test 7: Tax Regime Variations
|
||||
t.test('Country-specific tax requirements', async (st) => {
|
||||
const countryTaxRequirements = {
|
||||
DE: {
|
||||
standardRate: 19,
|
||||
reducedRate: 7,
|
||||
reverseCharge: 'Steuerschuldnerschaft des Leistungsempfängers'
|
||||
},
|
||||
FR: {
|
||||
standardRate: 20,
|
||||
reducedRates: [10, 5.5, 2.1],
|
||||
autoliquidation: 'Autoliquidation de la TVA'
|
||||
},
|
||||
IT: {
|
||||
standardRate: 22,
|
||||
reducedRates: [10, 5, 4],
|
||||
splitPayment: true // Italian split payment mechanism
|
||||
},
|
||||
ES: {
|
||||
standardRate: 21,
|
||||
reducedRates: [10, 4],
|
||||
canaryIslands: 'IGIC', // Different tax system
|
||||
recargo: true // Equivalence surcharge
|
||||
}
|
||||
};
|
||||
|
||||
// Validate tax rates
|
||||
for (const [country, tax] of Object.entries(countryTaxRequirements)) {
|
||||
expect(tax.standardRate).toBeGreaterThan(0);
|
||||
expect(tax.standardRate).toBeLessThan(30);
|
||||
st.pass(`✓ ${country}: Valid tax rates defined`);
|
||||
}
|
||||
});
|
||||
// Validate Codice Destinatario
|
||||
expect(fatturapaRequirements.transmissionFormat.CodiceDestinatario).toMatch(/^\d{7}$/);
|
||||
console.log('✓ Valid Codice Destinatario format');
|
||||
|
||||
// Test 8: Country-Specific Validation Rules
|
||||
t.test('Country-specific validation rules', async (st) => {
|
||||
// Test with real corpus files
|
||||
const countryFiles = {
|
||||
DE: await CorpusLoader.getFiles('XML_RECHNUNG_CII'),
|
||||
IT: await CorpusLoader.getFiles('FATTURAPA')
|
||||
};
|
||||
|
||||
// German validation rules
|
||||
if (countryFiles.DE.length > 0) {
|
||||
const germanFile = countryFiles.DE[0];
|
||||
const xmlBuffer = await CorpusLoader.loadFile(germanFile);
|
||||
const xmlString = xmlBuffer.toString('utf-8');
|
||||
|
||||
// Check for German-specific elements
|
||||
const hasLeitwegId = xmlString.includes('BuyerReference') ||
|
||||
xmlString.includes('BT-10');
|
||||
|
||||
if (hasLeitwegId) {
|
||||
st.pass('✓ German invoice contains buyer reference (Leitweg-ID)');
|
||||
}
|
||||
// Document numbering requirements
|
||||
const italianInvoiceNumber = '2024/001';
|
||||
expect(italianInvoiceNumber).toMatch(/^\d{4}\/\d+$/);
|
||||
console.log('✓ Valid Italian invoice number format');
|
||||
});
|
||||
|
||||
// Test 3: French Factur-X Extensions
|
||||
tap.test('STD-10: French Factur-X specific requirements', async () => {
|
||||
const invoice = new EInvoice();
|
||||
invoice.id = 'FX-FR-001';
|
||||
invoice.issueDate = new Date();
|
||||
|
||||
// French specific requirements
|
||||
const frenchExtensions = {
|
||||
siret: '12345678901234', // 14 digits
|
||||
naf: '6201Z', // NAF/APE code
|
||||
tvaIntracommunautaire: 'FR12345678901',
|
||||
mentionsLegales: 'SARL au capital de 10000 EUR',
|
||||
chorus: {
|
||||
serviceCode: 'SERVICE123',
|
||||
engagementNumber: 'ENG123456'
|
||||
}
|
||||
|
||||
// Italian validation rules
|
||||
if (countryFiles.IT.length > 0) {
|
||||
const italianFile = countryFiles.IT[0];
|
||||
const xmlBuffer = await CorpusLoader.loadFile(italianFile);
|
||||
const xmlString = xmlBuffer.toString('utf-8');
|
||||
|
||||
// Check for Italian-specific structure
|
||||
const hasFatturaPA = xmlString.includes('FatturaElettronica') ||
|
||||
xmlString.includes('FormatoTrasmissione');
|
||||
|
||||
if (hasFatturaPA) {
|
||||
st.pass('✓ Italian invoice follows FatturaPA structure');
|
||||
}
|
||||
};
|
||||
|
||||
// Validate SIRET (14 digits)
|
||||
expect(frenchExtensions.siret).toMatch(/^\d{14}$/);
|
||||
console.log('✓ Valid French SIRET format');
|
||||
|
||||
// Validate French VAT number
|
||||
const frenchVATPattern = /^FR[0-9A-Z]{2}\d{9}$/;
|
||||
expect(frenchVATPattern.test(frenchExtensions.tvaIntracommunautaire)).toBeTrue();
|
||||
console.log('✓ Valid French VAT number format');
|
||||
|
||||
// Validate NAF/APE code
|
||||
expect(frenchExtensions.naf).toMatch(/^\d{4}[A-Z]$/);
|
||||
console.log('✓ Valid French NAF/APE code format');
|
||||
|
||||
// Chorus Pro integration (French public sector)
|
||||
if (frenchExtensions.chorus.serviceCode) {
|
||||
console.log('✓ Chorus Pro service code present');
|
||||
}
|
||||
});
|
||||
|
||||
// Test 4: Belgian Extensions
|
||||
tap.test('STD-10: Belgian e-invoicing extensions', async () => {
|
||||
const belgianExtensions = {
|
||||
merchantAgreementReference: 'BE-MERCH-001',
|
||||
vatNumber: 'BE0123456789',
|
||||
bancontact: {
|
||||
enabled: true,
|
||||
reference: 'BC123456'
|
||||
},
|
||||
languages: ['nl', 'fr', 'de'], // Belgium has 3 official languages
|
||||
regionalCodes: {
|
||||
flanders: 'VL',
|
||||
wallonia: 'WA',
|
||||
brussels: 'BR'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Validate Belgian VAT number (BE followed by 10 digits)
|
||||
expect(belgianExtensions.vatNumber).toMatch(/^BE\d{10}$/);
|
||||
console.log('✓ Valid Belgian VAT number format');
|
||||
|
||||
// Language requirements
|
||||
expect(belgianExtensions.languages).toContain('nl');
|
||||
expect(belgianExtensions.languages).toContain('fr');
|
||||
console.log('✓ Supports required Belgian languages');
|
||||
});
|
||||
|
||||
// Test 5: Nordic Countries Extensions
|
||||
tap.test('STD-10: Nordic countries specific requirements', async () => {
|
||||
// Swedish requirements
|
||||
const swedishExtensions = {
|
||||
organisationNumber: '1234567890', // 10 digits
|
||||
vatNumber: 'SE123456789001',
|
||||
bankgiro: '123-4567',
|
||||
plusgiro: '12 34 56-7',
|
||||
referenceType: 'OCR', // Swedish payment reference
|
||||
ocrReference: '12345678901234567890'
|
||||
};
|
||||
|
||||
// Norwegian requirements
|
||||
const norwegianExtensions = {
|
||||
organisationNumber: '123456789', // 9 digits
|
||||
vatNumber: 'NO123456789MVA',
|
||||
kidNumber: '1234567890123', // Payment reference
|
||||
iban: 'NO9386011117947'
|
||||
};
|
||||
|
||||
// Danish requirements
|
||||
const danishExtensions = {
|
||||
cvrNumber: '12345678', // 8 digits
|
||||
eanLocation: '5790000123456', // 13 digits
|
||||
vatNumber: 'DK12345678',
|
||||
nemKonto: true // Danish public payment system
|
||||
};
|
||||
|
||||
// Validate formats
|
||||
expect(swedishExtensions.vatNumber).toMatch(/^SE\d{12}$/);
|
||||
console.log('✓ Valid Swedish VAT format');
|
||||
|
||||
expect(norwegianExtensions.vatNumber).toMatch(/^NO\d{9}MVA$/);
|
||||
console.log('✓ Valid Norwegian VAT format');
|
||||
|
||||
expect(danishExtensions.cvrNumber).toMatch(/^\d{8}$/);
|
||||
console.log('✓ Valid Danish CVR format');
|
||||
});
|
||||
|
||||
// Test 6: PEPPOL BIS Country Variations
|
||||
tap.test('STD-10: PEPPOL BIS country-specific profiles', async () => {
|
||||
const peppolProfiles = {
|
||||
'PEPPOL-BIS-3.0': 'Base profile',
|
||||
'PEPPOL-BIS-3.0-AU': 'Australian extension',
|
||||
'PEPPOL-BIS-3.0-NZ': 'New Zealand extension',
|
||||
'PEPPOL-BIS-3.0-SG': 'Singapore extension',
|
||||
'PEPPOL-BIS-3.0-MY': 'Malaysian extension'
|
||||
};
|
||||
|
||||
// Country-specific identifiers
|
||||
const countryIdentifiers = {
|
||||
AU: { scheme: '0151', name: 'ABN' }, // Australian Business Number
|
||||
NZ: { scheme: '0088', name: 'NZBN' }, // NZ Business Number
|
||||
SG: { scheme: '0195', name: 'UEN' }, // Unique Entity Number
|
||||
MY: { scheme: '0199', name: 'MyBRN' } // Malaysian Business Registration
|
||||
};
|
||||
|
||||
// Test identifier schemes
|
||||
for (const [country, identifier] of Object.entries(countryIdentifiers)) {
|
||||
expect(identifier.scheme).toMatch(/^\d{4}$/);
|
||||
console.log(`✓ ${country}: Valid PEPPOL identifier scheme ${identifier.scheme} (${identifier.name})`);
|
||||
}
|
||||
});
|
||||
|
||||
// Test 7: Tax Regime Variations
|
||||
tap.test('STD-10: Country-specific tax requirements', async () => {
|
||||
const countryTaxRequirements = {
|
||||
DE: {
|
||||
standardRate: 19,
|
||||
reducedRate: 7,
|
||||
reverseCharge: 'Steuerschuldnerschaft des Leistungsempfängers'
|
||||
},
|
||||
FR: {
|
||||
standardRate: 20,
|
||||
reducedRates: [10, 5.5, 2.1],
|
||||
autoliquidation: 'Autoliquidation de la TVA'
|
||||
},
|
||||
IT: {
|
||||
standardRate: 22,
|
||||
reducedRates: [10, 5, 4],
|
||||
splitPayment: true // Italian split payment mechanism
|
||||
},
|
||||
ES: {
|
||||
standardRate: 21,
|
||||
reducedRates: [10, 4],
|
||||
canaryIslands: 'IGIC', // Different tax system
|
||||
recargo: true // Equivalence surcharge
|
||||
}
|
||||
};
|
||||
|
||||
// Validate tax rates
|
||||
for (const [country, tax] of Object.entries(countryTaxRequirements)) {
|
||||
expect(tax.standardRate).toBeGreaterThan(0);
|
||||
expect(tax.standardRate).toBeLessThan(30);
|
||||
console.log(`✓ ${country}: Valid tax rates defined`);
|
||||
}
|
||||
});
|
||||
|
||||
// Test 8: Country-Specific Validation Rules
|
||||
tap.test('STD-10: Country-specific validation rules', async () => {
|
||||
// Test with real corpus files
|
||||
const countryFiles = {
|
||||
DE: await CorpusLoader.getFiles('CII_XMLRECHNUNG'),
|
||||
IT: await CorpusLoader.getFiles('FATTURAPA_OFFICIAL')
|
||||
};
|
||||
|
||||
// German validation rules
|
||||
if (countryFiles.DE.length > 0) {
|
||||
const germanFile = countryFiles.DE[0];
|
||||
const xmlBuffer = await CorpusLoader.loadFile(germanFile);
|
||||
const xmlString = xmlBuffer.toString('utf-8');
|
||||
|
||||
// Check for German-specific elements
|
||||
const hasLeitwegId = xmlString.includes('BuyerReference') ||
|
||||
xmlString.includes('BT-10');
|
||||
|
||||
if (hasLeitwegId) {
|
||||
console.log('✓ German invoice contains buyer reference (Leitweg-ID)');
|
||||
}
|
||||
}
|
||||
|
||||
// Italian validation rules
|
||||
if (countryFiles.IT.length > 0) {
|
||||
const italianFile = countryFiles.IT[0];
|
||||
const xmlBuffer = await CorpusLoader.loadFile(italianFile);
|
||||
const xmlString = xmlBuffer.toString('utf-8');
|
||||
|
||||
// Check for Italian-specific structure
|
||||
const hasFatturaPA = xmlString.includes('FatturaElettronica') ||
|
||||
xmlString.includes('FormatoTrasmissione');
|
||||
|
||||
if (hasFatturaPA) {
|
||||
console.log('✓ Italian invoice follows FatturaPA structure');
|
||||
}
|
||||
}
|
||||
|
||||
// Performance summary
|
||||
const perfSummary = await PerformanceTracker.getSummary('country-extensions');
|
||||
const tracker = new PerformanceTracker('country-extensions');
|
||||
const perfSummary = await tracker.getSummary();
|
||||
if (perfSummary) {
|
||||
console.log('\nCountry Extensions Test Performance:');
|
||||
console.log(` Average: ${perfSummary.average.toFixed(2)}ms`);
|
||||
console.log(` Average: ${perfSummary.average}ms`);
|
||||
}
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user