xinvoice/test/test.facturx-circular.ts

148 lines
3.9 KiB
TypeScript
Raw Normal View History

2025-04-03 16:41:10 +00:00
import { tap, expect } from '@push.rocks/tapbundle';
2025-04-03 15:53:08 +00:00
import { FacturXDecoder } from '../ts/formats/cii/facturx/facturx.decoder.js';
import { FacturXEncoder } from '../ts/formats/cii/facturx/facturx.encoder.js';
import { FacturXValidator } from '../ts/formats/cii/facturx/facturx.validator.js';
import type { TInvoice } from '../ts/interfaces/common.js';
import { ValidationLevel } from '../ts/interfaces/common.js';
import * as fs from 'fs/promises';
import * as path from 'path';
2025-04-03 16:41:10 +00:00
// Test for circular encoding/decoding of Factur-X
tap.test('Factur-X should maintain data integrity through encode/decode cycle', async () => {
// Create a sample invoice
const invoice = createSampleInvoice();
2025-04-03 15:53:08 +00:00
2025-04-03 16:41:10 +00:00
// Create encoder
const encoder = new FacturXEncoder();
// Encode to XML
const xml = await encoder.encode(invoice);
// Save XML for inspection
const testDir = path.join(process.cwd(), 'test', 'output');
await fs.mkdir(testDir, { recursive: true });
await fs.writeFile(path.join(testDir, 'facturx-circular-encoded.xml'), xml);
// Create decoder
const decoder = new FacturXDecoder(xml);
// Decode XML
const decodedInvoice = await decoder.decode();
// Check that decoded invoice is not null
expect(decodedInvoice).toBeTruthy();
// Check that key properties match
expect(decodedInvoice.id).toEqual(invoice.id);
expect(decodedInvoice.from.name).toEqual(invoice.from.name);
expect(decodedInvoice.to.name).toEqual(invoice.to.name);
// Create validator
const validator = new FacturXValidator(xml);
// Validate XML
const result = validator.validate(ValidationLevel.SYNTAX);
// Check that validation passed
expect(result.valid).toBeTrue();
expect(result.errors).toHaveLength(0);
});
2025-04-03 15:53:08 +00:00
/**
* Creates a sample invoice for testing
* @returns Sample invoice
*/
function createSampleInvoice(): TInvoice {
return {
type: 'invoice',
id: 'INV-2023-001',
invoiceId: 'INV-2023-001',
invoiceType: 'debitnote',
date: new Date('2023-01-01').getTime(),
status: 'invoice',
versionInfo: {
type: 'final',
version: '1.0.0'
},
language: 'en',
incidenceId: 'INV-2023-001',
from: {
type: 'company',
name: 'Supplier Company',
description: 'Supplier',
address: {
streetName: 'Supplier Street',
houseNumber: '123',
postalCode: '12345',
city: 'Supplier City',
country: 'DE',
countryCode: 'DE'
},
status: 'active',
foundedDate: {
year: 2000,
month: 1,
day: 1
},
registrationDetails: {
vatId: 'DE123456789',
registrationId: 'HRB12345',
registrationName: 'Supplier Company GmbH'
}
},
to: {
type: 'company',
name: 'Customer Company',
description: 'Customer',
address: {
streetName: 'Customer Street',
houseNumber: '456',
postalCode: '54321',
city: 'Customer City',
country: 'DE',
countryCode: 'DE'
},
status: 'active',
foundedDate: {
year: 2005,
month: 6,
day: 15
},
registrationDetails: {
vatId: 'DE987654321',
registrationId: 'HRB54321',
registrationName: 'Customer Company GmbH'
}
},
subject: 'Invoice INV-2023-001',
items: [
{
position: 1,
name: 'Product A',
articleNumber: 'PROD-A',
unitType: 'EA',
unitQuantity: 2,
unitNetPrice: 100,
vatPercentage: 19
},
{
position: 2,
name: 'Service B',
articleNumber: 'SERV-B',
unitType: 'HUR',
unitQuantity: 5,
unitNetPrice: 80,
vatPercentage: 19
}
],
dueInDays: 30,
reverseCharge: false,
currency: 'EUR',
notes: ['Thank you for your business'],
objectActions: []
} as TInvoice;
}
2025-04-03 16:41:10 +00:00
// Run the tests
tap.start();