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.

332 lines 25.1 kB
import * as plugins from '../plugins.js'; import * as xmldom from 'xmldom'; import { BaseDecoder } from './base.decoder.js'; /** * A decoder specifically for XInvoice/XRechnung format. * XRechnung is the German implementation of the European standard EN16931 * for electronic invoices to the German public sector. */ export class XInvoiceDecoder extends BaseDecoder { constructor(xmlString) { super(xmlString); this.xmlDoc = null; this.namespaces = { cbc: 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2', cac: 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', ubl: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2' }; // Parse XML to DOM try { const parser = new xmldom.DOMParser(); this.xmlDoc = parser.parseFromString(this.xmlString, 'text/xml'); // Try to detect if this is actually UBL (which XRechnung is based on) if (this.xmlString.includes('oasis:names:specification:ubl')) { // Set up appropriate namespaces this.setupNamespaces(); } } catch (error) { console.error('Error parsing XInvoice XML:', error); } } /** * Set up namespaces from the document */ setupNamespaces() { if (!this.xmlDoc) return; // Try to extract namespaces from the document const root = this.xmlDoc.documentElement; if (root) { // Look for common UBL namespaces for (let i = 0; i < root.attributes.length; i++) { const attr = root.attributes[i]; if (attr.name.startsWith('xmlns:')) { const prefix = attr.name.substring(6); this.namespaces[prefix] = attr.value; } } } } /** * Extract element text by tag name with namespace awareness */ getElementText(tagName) { if (!this.xmlDoc) { return ''; } try { // Handle namespace prefixes if (tagName.includes(':')) { const [nsPrefix, localName] = tagName.split(':'); // Find elements with this tag name const elements = this.xmlDoc.getElementsByTagNameNS(this.namespaces[nsPrefix] || '', localName); if (elements.length > 0) { return elements[0].textContent || ''; } } // Fallback to direct tag name lookup const elements = this.xmlDoc.getElementsByTagName(tagName); if (elements.length > 0) { return elements[0].textContent || ''; } return ''; } catch (error) { console.error(`Error extracting XInvoice element ${tagName}:`, error); return ''; } } /** * Converts XInvoice/XRechnung XML to a structured letter object */ async getLetterData() { try { // Extract invoice ID - typically in cbc:ID or Invoice/cbc:ID let invoiceId = this.getElementText('cbc:ID'); if (!invoiceId) { invoiceId = this.getElementText('Invoice/cbc:ID') || 'Unknown'; } // Extract invoice issue date const issueDateStr = this.getElementText('cbc:IssueDate') || ''; const issueDate = issueDateStr ? new Date(issueDateStr).getTime() : Date.now(); // Extract seller information const sellerName = this.getElementText('cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name') || this.getElementText('cac:SellerSupplierParty/cac:Party/cac:PartyName/cbc:Name') || 'Unknown Seller'; // Extract seller address const sellerStreet = this.getElementText('cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cbc:StreetName') || 'Unknown'; const sellerCity = this.getElementText('cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cbc:CityName') || 'Unknown'; const sellerPostcode = this.getElementText('cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cbc:PostalZone') || 'Unknown'; const sellerCountry = this.getElementText('cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cac:Country/cbc:IdentificationCode') || 'Unknown'; // Extract buyer information const buyerName = this.getElementText('cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc:Name') || this.getElementText('cac:BuyerCustomerParty/cac:Party/cac:PartyName/cbc:Name') || 'Unknown Buyer'; // Create seller contact const seller = { name: sellerName, type: 'company', description: sellerName, address: { streetName: sellerStreet, houseNumber: '0', city: sellerCity, country: sellerCountry, postalCode: sellerPostcode, }, registrationDetails: { vatId: this.getElementText('cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID') || 'Unknown', registrationId: this.getElementText('cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID') || 'Unknown', registrationName: sellerName }, foundedDate: { year: 2000, month: 1, day: 1 }, closedDate: { year: 9999, month: 12, day: 31 }, status: 'active' }; // Create buyer contact const buyer = { name: buyerName, type: 'company', description: buyerName, address: { streetName: 'Unknown', houseNumber: '0', city: 'Unknown', country: 'Unknown', postalCode: 'Unknown', }, registrationDetails: { vatId: this.getElementText('cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID') || 'Unknown', registrationId: this.getElementText('cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID') || 'Unknown', registrationName: buyerName }, foundedDate: { year: 2000, month: 1, day: 1 }, closedDate: { year: 9999, month: 12, day: 31 }, status: 'active' }; // Extract invoice type let invoiceType = 'debitnote'; const typeCode = this.getElementText('cbc:InvoiceTypeCode'); if (typeCode === '380') { invoiceType = 'debitnote'; // Standard invoice } else if (typeCode === '381') { invoiceType = 'creditnote'; // Credit note } // Create invoice data const invoiceData = { id: invoiceId, status: null, type: invoiceType, billedBy: seller, billedTo: buyer, deliveryDate: issueDate, dueInDays: 30, periodOfPerformance: null, printResult: null, currency: (this.getElementText('cbc:DocumentCurrencyCode') || 'EUR'), notes: [], items: this.extractInvoiceItems(), reverseCharge: false, }; // Return a letter return { versionInfo: { type: 'draft', version: '1.0.0', }, type: 'invoice', date: issueDate, subject: `XInvoice: ${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 XInvoice XML to letter data:', error); return this.createDefaultLetter(); } } /** * Extracts invoice items from XInvoice document */ extractInvoiceItems() { if (!this.xmlDoc) { return [ { name: 'Unknown Item', unitQuantity: 1, unitNetPrice: 0, vatPercentage: 0, position: 0, unitType: 'units', } ]; } try { const items = []; // Get all invoice line elements const lines = this.xmlDoc.getElementsByTagName('cac:InvoiceLine'); if (!lines || lines.length === 0) { // Fallback to a default item return [ { name: 'Item from XInvoice XML', unitQuantity: 1, unitNetPrice: 0, vatPercentage: 0, position: 0, unitType: 'units', } ]; } // Process each line for (let i = 0; i < lines.length; i++) { const line = lines[i]; // Extract item details let name = ''; let quantity = 1; let price = 0; let vatRate = 0; // Find description element const descElements = line.getElementsByTagName('cbc:Description'); if (descElements.length > 0) { name = descElements[0].textContent || ''; } // Fallback to item name if description is empty if (!name) { const itemNameElements = line.getElementsByTagName('cbc:Name'); if (itemNameElements.length > 0) { name = itemNameElements[0].textContent || ''; } } // Find quantity const quantityElements = line.getElementsByTagName('cbc:InvoicedQuantity'); if (quantityElements.length > 0) { const quantityText = quantityElements[0].textContent || '1'; quantity = parseFloat(quantityText) || 1; } // Find price const priceElements = line.getElementsByTagName('cbc:PriceAmount'); if (priceElements.length > 0) { const priceText = priceElements[0].textContent || '0'; price = parseFloat(priceText) || 0; } // Find VAT rate - this is a bit more complex in UBL/XRechnung const taxCategoryElements = line.getElementsByTagName('cac:ClassifiedTaxCategory'); if (taxCategoryElements.length > 0) { const rateElements = taxCategoryElements[0].getElementsByTagName('cbc:Percent'); if (rateElements.length > 0) { const rateText = rateElements[0].textContent || '0'; vatRate = parseFloat(rateText) || 0; } } // Add the item to the list items.push({ name: name || `Item ${i + 1}`, unitQuantity: quantity, unitNetPrice: price, vatPercentage: vatRate, position: i, unitType: 'units', }); } return items.length > 0 ? items : [ { name: 'Item from XInvoice XML', unitQuantity: 1, unitNetPrice: 0, vatPercentage: 0, position: 0, unitType: 'units', } ]; } catch (error) { console.error('Error extracting XInvoice items:', error); return [ { name: 'Error extracting items', unitQuantity: 1, unitNetPrice: 0, vatPercentage: 0, position: 0, unitType: 'units', } ]; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieGludm9pY2UuZGVjb2Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2Zvcm1hdHMveGludm9pY2UuZGVjb2Rlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEtBQUssTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUNqQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFaEQ7Ozs7R0FJRztBQUNILE1BQU0sT0FBTyxlQUFnQixTQUFRLFdBQVc7SUFROUMsWUFBWSxTQUFpQjtRQUMzQixLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7UUFSWCxXQUFNLEdBQW9CLElBQUksQ0FBQztRQUMvQixlQUFVLEdBQThCO1lBQzlDLEdBQUcsRUFBRSxzRUFBc0U7WUFDM0UsR0FBRyxFQUFFLDBFQUEwRTtZQUMvRSxHQUFHLEVBQUUsd0RBQXdEO1NBQzlELENBQUM7UUFLQSxtQkFBbUI7UUFDbkIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDdEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFFakUsc0VBQXNFO1lBQ3RFLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsK0JBQStCLENBQUMsRUFBRSxDQUFDO2dCQUM3RCxnQ0FBZ0M7Z0JBQ2hDLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN6QixDQUFDO1FBQ0gsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPLENBQUMsS0FBSyxDQUFDLDZCQUE2QixFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3RELENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxlQUFlO1FBQ3JCLElBQUksQ0FBQyxJ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