UNPKG

@fin.cx/einvoice

Version:

A TypeScript module for creating, manipulating, and embedding XML data within PDF files specifically tailored for electronic invoice (einvoice) packages.

178 lines 12.6 kB
import * as plugins from '../plugins.js'; import * as xmldom from 'xmldom'; import { BaseDecoder } from './base.decoder.js'; /** * A decoder for Factur-X/ZUGFeRD XML format (based on UN/CEFACT CII). * Converts XML into structured ILetter with invoice data. */ export class FacturXDecoder extends BaseDecoder { constructor(xmlString) { super(xmlString); this.xmlDoc = null; // Parse XML to DOM for easier element extraction try { const parser = new xmldom.DOMParser(); this.xmlDoc = parser.parseFromString(this.xmlString, 'text/xml'); } catch (error) { console.error('Error parsing Factur-X XML:', error); } } /** * Extracts text from the first element matching the tag name */ getElementText(tagName) { if (!this.xmlDoc) { return ''; } try { // Basic handling for namespaced tags let namespace = ''; let localName = tagName; if (tagName.includes(':')) { const parts = tagName.split(':'); namespace = parts[0]; localName = parts[1]; } // Find all elements with this name const elements = this.xmlDoc.getElementsByTagName(tagName); if (elements.length > 0) { return elements[0].textContent || ''; } // Try with just the local name if we didn't find it with the namespace if (namespace) { const elements = this.xmlDoc.getElementsByTagName(localName); if (elements.length > 0) { return elements[0].textContent || ''; } } return ''; } catch (error) { console.error(`Error extracting element ${tagName}:`, error); return ''; } } /** * Converts Factur-X/ZUGFeRD XML to a structured letter object */ async getLetterData() { try { // Extract invoice ID let invoiceId = this.getElementText('ram:ID'); if (!invoiceId) { // Try alternative locations invoiceId = this.getElementText('rsm:ExchangedDocument ram:ID') || 'Unknown'; } // Extract seller name let sellerName = this.getElementText('ram:Name'); if (!sellerName) { sellerName = this.getElementText('ram:SellerTradeParty ram:Name') || 'Unknown Seller'; } // Extract buyer name let buyerName = ''; // Try to find BuyerTradeParty Name specifically if (this.xmlDoc) { const buyerParties = this.xmlDoc.getElementsByTagName('ram:BuyerTradeParty'); if (buyerParties.length > 0) { const nameElements = buyerParties[0].getElementsByTagName('ram:Name'); if (nameElements.length > 0) { buyerName = nameElements[0].textContent || ''; } } } if (!buyerName) { buyerName = 'Unknown Buyer'; } // Create seller const seller = { name: sellerName, type: 'company', description: sellerName, address: { streetName: this.getElementText('ram:LineOne') || 'Unknown', houseNumber: '0', // Required by IAddress interface city: this.getElementText('ram:CityName') || 'Unknown', country: this.getElementText('ram:CountryID') || 'Unknown', postalCode: this.getElementText('ram:PostcodeCode') || 'Unknown', }, }; // Create buyer const buyer = { name: buyerName, type: 'company', description: buyerName, address: { streetName: 'Unknown', houseNumber: '0', city: 'Unknown', country: 'Unknown', postalCode: 'Unknown', }, }; // Extract invoice type let invoiceType = 'debitnote'; const typeCode = this.getElementText('ram:TypeCode'); if (typeCode === '381') { invoiceType = 'creditnote'; } // Create invoice data const invoiceData = { id: invoiceId, status: null, type: invoiceType, billedBy: seller, billedTo: buyer, deliveryDate: Date.now(), dueInDays: 30, periodOfPerformance: null, printResult: null, currency: (this.getElementText('ram:InvoiceCurrencyCode') || 'EUR'), notes: [], items: [ { name: 'Item from Factur-X XML', unitQuantity: 1, unitNetPrice: 0, vatPercentage: 0, position: 0, unitType: 'units', } ], reverseCharge: false, }; // Return a letter return { versionInfo: { type: 'draft', version: '1.0.0', }, type: 'invoice', date: Date.now(), subject: `Invoice: ${invoiceId}`, from: seller, to: buyer, content: { invoiceData: invoiceData, textData: null, timesheetData: null, contractData: null, }, needsCoverSheet: false, objectActions: [], pdf: null, incidenceId: null, language: null, legalContact: null, logoUrl: null, pdfAttachments: null, accentColor: null, }; } catch (error) { console.error('Error converting Factur-X XML to letter data:', error); return this.createDefaultLetter(); } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeC5kZWNvZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvZm9ybWF0cy9mYWN0b3J4LmRlY29kZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxLQUFLLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDakMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRWhEOzs7R0FHRztBQUNILE1BQU0sT0FBTyxjQUFlLFNBQVEsV0FBVztJQUc3QyxZQUFZLFNBQWlCO1FBQzNCLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUhYLFdBQU0sR0FBb0IsSUFBSSxDQUFDO1FBS3JDLGlEQUFpRDtRQUNqRCxJQUFJLENBQUM7WUFDSCxNQUFNLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN0QyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNuRSxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsNkJBQTZCLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdEQsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLGNBQWMsQ0FBQyxPQUFlO1FBQ3BDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDakIsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gscUNBQXFDO1lBQ3JDLElBQUksU0FBUyxHQUFHLEVBQUUsQ0FBQztZQUNuQixJQUFJLFNBQVMsR0FBRyxPQUFPLENBQUM7WUFFeEIsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzFCLE1BQU0sS0FBSyxHQUFHLE9BQU8s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