150 lines
5.5 KiB
TypeScript
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(); |