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 * as path from 'path'; /** * Test ID: STD-08 * Test Description: CII D16B Compliance * Priority: High * * This test validates compliance with the UN/CEFACT Cross Industry Invoice (CII) D16B standard, * ensuring proper structure, data types, and business term mappings. */ tap.test('STD-08: CII D16B Compliance - should validate CII D16B standard compliance', async (t) => { // CII D16B namespace and structure requirements const ciiNamespaces = { rsm: 'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100', qdt: 'urn:un:unece:uncefact:data:standard:QualifiedDataType:100', ram: 'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100', udt: 'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100' }; // Test 1: Namespace and Root Element Compliance t.test('CII D16B namespace and root element', async (st) => { const ciiFiles = await CorpusLoader.getFiles('XML_RECHNUNG_CII'); const testFiles = ciiFiles.slice(0, 5); for (const file of testFiles) { const xmlBuffer = await CorpusLoader.loadFile(file); const xmlString = xmlBuffer.toString('utf-8'); // Check root element const hasCorrectRoot = xmlString.includes(' { const invoice = new EInvoice(); invoice.id = 'CII-CTX-001'; invoice.issueDate = new Date(); invoice.from = { name: 'Seller', address: { country: 'DE' } }; invoice.to = { name: 'Buyer', address: { country: 'DE' } }; invoice.items = [{ name: 'Product', quantity: 1, unitPrice: 100 }]; const ciiXml = await invoice.toXmlString('cii'); // Check for ExchangedDocumentContext expect(ciiXml.includes('ExchangedDocumentContext')).toBeTrue(); // Check for GuidelineSpecifiedDocumentContextParameter const hasGuideline = ciiXml.includes('GuidelineSpecifiedDocumentContextParameter') || ciiXml.includes('SpecifiedDocumentContextParameter'); expect(hasGuideline).toBeTrue(); st.pass('✓ CII D16B document context is present'); }); // Test 3: Header Structure Compliance t.test('CII D16B header structure', async (st) => { const requiredHeaders = [ 'ExchangedDocument', 'SupplyChainTradeTransaction', 'ApplicableHeaderTradeAgreement', 'ApplicableHeaderTradeDelivery', 'ApplicableHeaderTradeSettlement' ]; const invoice = new EInvoice(); invoice.id = 'CII-HDR-001'; invoice.issueDate = new Date(); invoice.currency = 'EUR'; invoice.from = { name: 'Test Supplier', address: { street: 'Main St', city: 'Berlin', postalCode: '10115', country: 'DE' }, vatNumber: 'DE123456789' }; invoice.to = { name: 'Test Buyer', address: { street: 'Market St', city: 'Munich', postalCode: '80331', country: 'DE' } }; invoice.items = [{ name: 'Service', description: 'Consulting', quantity: 10, unitPrice: 150, taxPercent: 19 }]; const xml = await invoice.toXmlString('cii'); for (const header of requiredHeaders) { expect(xml.includes(header)).toBeTrue(); st.pass(`✓ Required header element: ${header}`); } }); // Test 4: Trade Party Information Compliance t.test('CII D16B trade party information', async (st) => { const invoice = new EInvoice(); invoice.id = 'CII-PARTY-001'; invoice.issueDate = new Date(); invoice.from = { name: 'Seller Company GmbH', address: { street: 'Hauptstraße 1', city: 'Berlin', postalCode: '10115', country: 'DE' }, vatNumber: 'DE123456789', email: 'info@seller.de' }; invoice.to = { name: 'Buyer AG', address: { street: 'Marktplatz 5', city: 'München', postalCode: '80331', country: 'DE' }, registrationNumber: 'HRB 12345' }; invoice.items = [{ name: 'Item', quantity: 1, unitPrice: 100 }]; const xml = await invoice.toXmlString('cii'); // Check seller party structure expect(xml.includes('SellerTradeParty')).toBeTrue(); expect(xml.includes('Seller Company GmbH')).toBeTrue(); expect(xml.includes('DE123456789')).toBeTrue(); // Check buyer party structure expect(xml.includes('BuyerTradeParty')).toBeTrue(); expect(xml.includes('Buyer AG')).toBeTrue(); // Check address structure expect(xml.includes('PostalTradeAddress')).toBeTrue(); expect(xml.includes('10115')).toBeTrue(); // Postal code st.pass('✓ CII D16B trade party information is compliant'); }); // Test 5: Line Item Structure Compliance t.test('CII D16B line item structure', async (st) => { const invoice = new EInvoice(); invoice.id = 'CII-LINE-001'; invoice.issueDate = new Date(); invoice.from = { name: 'Seller', address: { country: 'DE' } }; invoice.to = { name: 'Buyer', address: { country: 'DE' } }; invoice.items = [{ id: 'ITEM-001', name: 'Professional Service', description: 'Consulting service for project X', quantity: 20, unitPrice: 250, unit: 'HUR', // Hours taxPercent: 19, articleNumber: 'SRV-001' }]; const xml = await invoice.toXmlString('cii'); // Check line item structure expect(xml.includes('IncludedSupplyChainTradeLineItem')).toBeTrue(); expect(xml.includes('AssociatedDocumentLineDocument')).toBeTrue(); expect(xml.includes('SpecifiedTradeProduct')).toBeTrue(); expect(xml.includes('SpecifiedLineTradeAgreement')).toBeTrue(); expect(xml.includes('SpecifiedLineTradeDelivery')).toBeTrue(); expect(xml.includes('SpecifiedLineTradeSettlement')).toBeTrue(); // Check specific values expect(xml.includes('Professional Service')).toBeTrue(); expect(xml.includes('20')).toBeTrue(); // Quantity st.pass('✓ CII D16B line item structure is compliant'); }); // Test 6: Monetary Summation Compliance t.test('CII D16B monetary summation', async (st) => { const invoice = new EInvoice(); invoice.id = 'CII-SUM-001'; invoice.issueDate = new Date(); invoice.currency = 'EUR'; invoice.from = { name: 'Seller', address: { country: 'DE' } }; invoice.to = { name: 'Buyer', address: { country: 'DE' } }; invoice.items = [ { name: 'Item 1', quantity: 10, unitPrice: 100, taxPercent: 19 }, { name: 'Item 2', quantity: 5, unitPrice: 200, taxPercent: 19 } ]; const xml = await invoice.toXmlString('cii'); // Check monetary summation structure expect(xml.includes('SpecifiedTradeSettlementHeaderMonetarySummation')).toBeTrue(); expect(xml.includes('LineTotalAmount')).toBeTrue(); expect(xml.includes('TaxBasisTotalAmount')).toBeTrue(); expect(xml.includes('TaxTotalAmount')).toBeTrue(); expect(xml.includes('GrandTotalAmount')).toBeTrue(); expect(xml.includes('DuePayableAmount')).toBeTrue(); // Verify calculation (10*100 + 5*200 = 2000, tax = 380, total = 2380) expect(xml.includes('2000')).toBeTrue(); // Line total expect(xml.includes('2380')).toBeTrue(); // Grand total st.pass('✓ CII D16B monetary summation is compliant'); }); // Test 7: Date/Time Format Compliance t.test('CII D16B date/time format', async (st) => { const invoice = new EInvoice(); invoice.id = 'CII-DATE-001'; invoice.issueDate = new Date('2024-03-15'); invoice.dueDate = new Date('2024-04-15'); invoice.from = { name: 'Seller', address: { country: 'DE' } }; invoice.to = { name: 'Buyer', address: { country: 'DE' } }; invoice.items = [{ name: 'Item', quantity: 1, unitPrice: 100 }]; const xml = await invoice.toXmlString('cii'); // CII uses YYYYMMDD format for dates const datePattern = />(\d{8}) m[1]); expect(dates.length).toBeGreaterThan(0); // Check format for (const date of dates) { expect(date).toMatch(/^\d{8}$/); st.pass(`✓ Valid CII date format: ${date}`); } }); // Test 8: Code List Compliance t.test('CII D16B code list compliance', async (st) => { // Test various code lists used in CII const codeLists = { currencyCode: { value: 'EUR', list: 'ISO 4217' }, countryCode: { value: 'DE', list: 'ISO 3166-1' }, taxCategoryCode: { value: 'S', list: 'UNCL5305' }, unitCode: { value: 'C62', list: 'UNECE Rec 20' } }; for (const [codeType, info] of Object.entries(codeLists)) { // In real implementation, would validate against actual code lists expect(info.value.length).toBeGreaterThan(0); st.pass(`✓ Valid ${codeType}: ${info.value} (${info.list})`); } }); // Performance summary const perfSummary = await PerformanceTracker.getSummary('cii-compliance'); if (perfSummary) { console.log('\nCII D16B Compliance Test Performance:'); console.log(` Average: ${perfSummary.average.toFixed(2)}ms`); } }); tap.start();