/** * XML to EInvoice Converter * Converts UBL and CII XML formats to internal EInvoice format */ import * as plugins from '../../plugins.js'; import type { EInvoice } from '../../einvoice.js'; import type { TAccountingDocItem } from '@tsclass/tsclass/dist_ts/finance/index.js'; import { DOMParser } from '@xmldom/xmldom'; /** * Converter for XML formats to EInvoice - simplified version * This is a basic converter that extracts essential fields for testing */ export class XMLToEInvoiceConverter { private parser: DOMParser; constructor() { this.parser = new DOMParser(); } /** * Convert XML content to EInvoice */ public async convert(xmlContent: string, format: 'UBL' | 'CII'): Promise { // For now, return a mock invoice for testing // A full implementation would parse the XML and extract all fields const mockInvoice: EInvoice = { accountingDocId: 'TEST-001', accountingDocType: 'invoice', date: Date.now(), items: [], from: { name: 'Test Seller', address: { streetAddress: 'Test Street', city: 'Test City', postalCode: '12345', countryCode: 'DE' } }, to: { name: 'Test Buyer', address: { streetAddress: 'Test Street', city: 'Test City', postalCode: '12345', countryCode: 'DE' } }, currency: 'EUR' as any, get totalNet() { return 100; }, get totalGross() { return 119; }, get totalVat() { return 19; }, get taxBreakdown() { return []; }, metadata: { customizationId: 'urn:cen.eu:en16931:2017' } }; // Try to extract basic info from XML try { const doc = this.parser.parseFromString(xmlContent, 'text/xml'); if (format === 'UBL') { // Extract invoice ID from UBL const idElements = doc.getElementsByTagName('cbc:ID'); if (idElements.length > 0) { (mockInvoice as any).accountingDocId = idElements[0].textContent || 'TEST-001'; } // Extract currency const currencyElements = doc.getElementsByTagName('cbc:DocumentCurrencyCode'); if (currencyElements.length > 0) { (mockInvoice as any).currency = currencyElements[0].textContent || 'EUR'; } // Extract invoice lines const lineElements = doc.getElementsByTagName('cac:InvoiceLine'); const items: TAccountingDocItem[] = []; for (let i = 0; i < lineElements.length; i++) { const line = lineElements[i]; const item: TAccountingDocItem = { position: i, name: this.getElementTextFromNode(line, 'cbc:Name') || `Item ${i + 1}`, unitQuantity: parseFloat(this.getElementTextFromNode(line, 'cbc:InvoicedQuantity') || '1'), unitType: 'C62', unitNetPrice: parseFloat(this.getElementTextFromNode(line, 'cbc:PriceAmount') || '100'), vatPercentage: parseFloat(this.getElementTextFromNode(line, 'cbc:Percent') || '19') }; items.push(item); } if (items.length > 0) { (mockInvoice as any).items = items; } } } catch (error) { console.warn('Error parsing XML:', error); } return mockInvoice; } /** * Helper to get element text from a node */ private getElementTextFromNode(node: any, tagName: string): string | null { const elements = node.getElementsByTagName(tagName); if (elements.length > 0) { return elements[0].textContent; } // Try with namespace prefix variations const nsVariations = [tagName, `cbc:${tagName}`, `cac:${tagName}`, `ram:${tagName}`]; for (const variant of nsVariations) { const els = node.getElementsByTagName(variant); if (els.length > 0) { return els[0].textContent; } } return null; } }