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.

320 lines 20.1 kB
import * as plugins from './plugins.js'; import * as xmldom from 'xmldom'; /** * A class to convert a given XML string (ZUGFeRD/Factur-X, UBL or fatturaPA) * into a structured ILetter with invoice data. * * Handles different invoice XML formats: * - ZUGFeRD/Factur-X (CII) * - UBL * - FatturaPA */ export class FacturXDecoder { constructor(xmlString) { this.xmlDoc = null; if (!xmlString) { throw new Error('No XML string provided to decoder'); } this.xmlString = xmlString; // Simple format detection based on string contents this.xmlFormat = this.detectFormat(); // Parse XML to DOM try { const parser = new xmldom.DOMParser(); this.xmlDoc = parser.parseFromString(this.xmlString, 'text/xml'); } catch (error) { console.error('Error parsing XML:', error); } } /** * Detects the XML invoice format using simple string checks */ detectFormat() { // ZUGFeRD/Factur-X (CII format) if (this.xmlString.includes('CrossIndustryInvoice') || this.xmlString.includes('un/cefact') || this.xmlString.includes('rsm:')) { return 'CII'; } // UBL format if (this.xmlString.includes('Invoice') || this.xmlString.includes('oasis:names:specification:ubl')) { return 'UBL'; } // FatturaPA format if (this.xmlString.includes('FatturaElettronica') || this.xmlString.includes('fatturapa.gov.it')) { return 'FatturaPA'; } // Default to generic return 'unknown'; } /** * Extracts text from the first element matching the XPath-like selector */ 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 XML to a structured letter object */ async getLetterData() { try { if (this.xmlFormat === 'CII') { return this.parseCII(); } else if (this.xmlFormat === 'UBL') { // For now, use the default implementation return this.parseGeneric(); } else if (this.xmlFormat === 'FatturaPA') { // For now, use the default implementation return this.parseGeneric(); } else { return this.parseGeneric(); } } catch (error) { console.error('Error converting XML to letter data:', error); // If all else fails, return a minimal letter object return this.createDefaultLetter(); } } /** * Parse CII (ZUGFeRD/Factur-X) formatted XML */ parseCII() { // 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 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, }; } /** * Parse generic XML using default approach */ parseGeneric() { // Create a default letter with some extraction attempts return this.createDefaultLetter(); } /** * Creates a default letter object with minimal data */ createDefaultLetter() { // Create a default seller const seller = { name: 'Unknown Seller', type: 'company', description: 'Unknown Seller', // Required by IContact interface address: { streetName: 'Unknown', houseNumber: '0', // Required by IAddress interface city: 'Unknown', country: 'Unknown', postalCode: 'Unknown', }, }; // Create a default buyer const buyer = { name: 'Unknown Buyer', type: 'company', description: 'Unknown Buyer', // Required by IContact interface address: { streetName: 'Unknown', houseNumber: '0', // Required by IAddress interface city: 'Unknown', country: 'Unknown', postalCode: 'Unknown', }, }; // Create default invoice data const invoiceData = { id: 'Unknown', status: null, type: 'debitnote', billedBy: seller, billedTo: buyer, deliveryDate: Date.now(), dueInDays: 30, periodOfPerformance: null, printResult: null, currency: 'EUR', notes: [], items: [ { name: 'Unknown Item', unitQuantity: 1, unitNetPrice: 0, vatPercentage: 0, position: 0, unitType: 'units', } ], reverseCharge: false, }; // Return a default letter return { versionInfo: { type: 'draft', version: '1.0.0', }, type: 'invoice', date: Date.now(), subject: `Extracted Invoice (${this.xmlFormat} format)`, 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, }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5kZWNvZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5kZWNvZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBRWpDOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxPQUFPLGNBQWM7SUFLekIsWUFBWSxTQUFpQjtRQUZyQixXQUFNLEdBQW9CLElBQUksQ0FBQztRQUdyQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDZixNQUFNLElBQUksS0FBSyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7UUFDdkQsQ0FBQztRQUVELElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1FBRTNCLG1EQUFtRDtRQUNuRCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUVyQyxtQkFBbUI7UUFDbkIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDdEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDbkUsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPLENBQUMsS0FBSyxDQUFDLG9CQUFvQixFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzdDLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxZQUFZO1FBQ2xCLGdDQUFnQztRQUNoQyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLHNCQUFzQixDQUFDO1lBQy9DLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQztZQUNwQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENB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