import * as plugins from './plugins.js'; import * as interfaces from './interfaces.js'; import { PDFDocument, PDFDict, PDFName, PDFRawStream } from 'pdf-lib'; export class XInvoice { public pdfUint8Array: Uint8Array; constructor(pdfBuffer: Uint8Array | Buffer) { this.pdfUint8Array = Uint8Array.from(pdfBuffer); } public async embedXml(xmlString: string): Promise { try { const pdfDoc = await PDFDocument.load(this.pdfUint8Array); const xmlBuffer = new TextEncoder().encode(xmlString); pdfDoc.attach(xmlBuffer, plugins.path.basename('invoice.xml'), { mimeType: 'application/xml', description: 'XRechnung XML Invoice', }); const modifiedPdfBytes = await pdfDoc.save(); this.pdfUint8Array = modifiedPdfBytes; console.log(`PDF Buffer updated with new XML attachment!`); } catch (error) { console.error('Error embedding XML into PDF:', error); throw error; } } /** * reads the xml part and returns parsed structured data * @returns {Promise} Parsed XML data */ public async getParsedXmlData(): Promise { try { const pdfBuffer = this.pdfUint8Array; const pdfDoc = await PDFDocument.load(pdfBuffer); const namesDict = pdfDoc.catalog.get(PDFName.of('Names')) as PDFDict; if (!namesDict) throw new Error('No Names dictionary found in PDF!'); const embeddedFilesDict = namesDict.get(PDFName.of('EmbeddedFiles')) as PDFDict; if (!embeddedFilesDict) throw new Error('No EmbeddedFiles dictionary found!'); const filesSpecDict = embeddedFilesDict.get(PDFName.of('Names')) as PDFDict; if (!filesSpecDict) throw new Error('No files specified in EmbeddedFiles dictionary!'); let xmlFile: PDFRawStream | undefined = undefined; const entries = filesSpecDict.entries(); for (const [key, fileSpecValue] of entries) { const fileSpec = fileSpecValue as PDFDict; const efDict = fileSpec.get(PDFName.of('EF')) as PDFDict; xmlFile = efDict.get(PDFName.of('F')) as PDFRawStream; if (xmlFile) break; } if (!xmlFile) throw new Error('XML file stream not found!'); const xmlBytes = xmlFile.getContents(); const xmlContent = new TextDecoder().decode(xmlBytes); console.log(`Read embedded XML: ${xmlContent}`); return this.parseXmlToInvoice(xmlContent); } catch (error) { console.error('Error extracting or parsing embedded XML from PDF:', error); throw error; } } private parseXmlToInvoice(xmlContent: string): interfaces.IXInvoice { // Implement XML parsing logic here // Placeholder return, replace with actual parsing result return { InvoiceNumber: '12345', DateIssued: '2023-04-01', Seller: { Name: 'Seller Co', Address: { Street: '1234 Market St', City: 'Sample City', PostalCode: '12345', Country: 'DE', }, Contact: { Email: 'contact@sellerco.com', Phone: '123-456-7890', }, }, Buyer: { Name: 'Buyer Inc', Address: { Street: '5678 Trade Rd', City: 'Trade City', PostalCode: '67890', Country: 'DE', }, Contact: { Email: 'info@buyerinc.com', Phone: '987-654-3210', }, }, Items: [ { Description: 'Item 1', Quantity: 10, UnitPrice: 9.99, TotalPrice: 99.9, }, ], TotalAmount: 99.9, }; } }