xinvoice/test/test.xinvoice-decoder.ts
2025-03-17 16:30:23 +00:00

150 lines
5.5 KiB
TypeScript

import { tap, expect } from '@push.rocks/tapbundle';
import * as getInvoices from './assets/getasset.js';
import { XInvoiceEncoder, XInvoiceDecoder } from '../ts/index.js';
import * as tsclass from '@tsclass/tsclass';
// Sample test letter data from our test assets
const testLetterData = getInvoices.letterObjects.letter1.demoLetter;
// Test for XInvoice/XRechnung XML format
tap.test('Generate XInvoice XML from letter data', async () => {
// Create the encoder
const encoder = new XInvoiceEncoder();
// Generate XInvoice XML
const xml = encoder.createXInvoiceXml(testLetterData);
// Verify the XML was created properly
expect(xml).toBeTypeOf('string');
expect(xml.length).toBeGreaterThan(100);
// Check for UBL/XInvoice structure
expect(xml).toInclude('oasis:names:specification:ubl');
expect(xml).toInclude('Invoice');
expect(xml).toInclude('cbc:ID');
expect(xml).toInclude(testLetterData.content.invoiceData.id);
// Check for mandatory XRechnung elements
expect(xml).toInclude('CustomizationID');
expect(xml).toInclude('xrechnung');
expect(xml).toInclude('cbc:UBLVersionID');
console.log('Successfully generated XInvoice XML');
});
// Test for special handling of credit notes
tap.test('Generate XInvoice credit note XML', async () => {
// Create a modified version of the test letter - change type to credit note
const creditNoteLetter = {...testLetterData};
creditNoteLetter.content = {...testLetterData.content};
creditNoteLetter.content.invoiceData = {...testLetterData.content.invoiceData};
creditNoteLetter.content.invoiceData.type = 'creditnote';
creditNoteLetter.content.invoiceData.id = 'CN-' + testLetterData.content.invoiceData.id;
// Create encoder
const encoder = new XInvoiceEncoder();
// Generate XML for credit note
const xml = encoder.createXInvoiceXml(creditNoteLetter);
// Check that it's a credit note (type code 381)
expect(xml).toInclude('cbc:InvoiceTypeCode');
expect(xml).toInclude('381');
expect(xml).toInclude(creditNoteLetter.content.invoiceData.id);
console.log('Successfully generated XInvoice credit note XML');
});
// Test decoding XInvoice XML
tap.test('Decode XInvoice XML to structured data', async () => {
// First, create XML to test with
const encoder = new XInvoiceEncoder();
const xml = encoder.createXInvoiceXml(testLetterData);
// Create the decoder
const decoder = new XInvoiceDecoder(xml);
// Decode back to structured data
const decodedLetter = await decoder.getLetterData();
// Verify we got a letter back
expect(decodedLetter).toBeTypeOf('object');
expect(decodedLetter.content?.invoiceData).toBeDefined();
// Check that essential information was extracted
expect(decodedLetter.content?.invoiceData?.id).toBeDefined();
expect(decodedLetter.content?.invoiceData?.billedBy).toBeDefined();
expect(decodedLetter.content?.invoiceData?.billedTo).toBeDefined();
console.log('Successfully decoded XInvoice XML');
});
// Test namespace handling for UBL
tap.test('Handle UBL namespaces correctly', async () => {
// Create valid UBL XML with namespaces
const ublXml = `<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:ID>${testLetterData.content.invoiceData.id}</cbc:ID>
<cbc:IssueDate>2023-12-31</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cac:AccountingSupplierParty>
<cac:Party>
<cac:PartyName>
<cbc:Name>${testLetterData.content.invoiceData.billedBy.name}</cbc:Name>
</cac:PartyName>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cac:PartyName>
<cbc:Name>${testLetterData.content.invoiceData.billedTo.name}</cbc:Name>
</cac:PartyName>
</cac:Party>
</cac:AccountingCustomerParty>
</Invoice>`;
// Create decoder for the UBL XML
const decoder = new XInvoiceDecoder(ublXml);
// Extract the data
const decodedLetter = await decoder.getLetterData();
// Verify extraction worked with namespaces
expect(decodedLetter.content?.invoiceData?.id).toBeDefined();
expect(decodedLetter.content?.invoiceData?.billedBy.name).toBeDefined();
console.log('Successfully handled UBL namespaces');
});
// Test extraction of invoice items
tap.test('Extract invoice items from XInvoice XML', async () => {
// Create an invoice with items
const encoder = new XInvoiceEncoder();
const xml = encoder.createXInvoiceXml(testLetterData);
// Decode the XML
const decoder = new XInvoiceDecoder(xml);
const decodedLetter = await decoder.getLetterData();
// Verify items were extracted
expect(decodedLetter.content?.invoiceData?.items).toBeDefined();
if (decodedLetter.content?.invoiceData?.items) {
// At least one item should be extracted
expect(decodedLetter.content.invoiceData.items.length).toBeGreaterThan(0);
// Check first item has needed properties
const firstItem = decodedLetter.content.invoiceData.items[0];
expect(firstItem.name).toBeDefined();
expect(firstItem.unitQuantity).toBeDefined();
expect(firstItem.unitNetPrice).toBeDefined();
}
console.log('Successfully extracted invoice items');
});
// Start the test suite
tap.start();