xinvoice/ts/classes.xinvoice.ts
2024-04-22 16:30:55 +02:00

116 lines
3.5 KiB
TypeScript

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<void> {
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<interfaces.IXInvoice>} Parsed XML data
*/
public async getParsedXmlData(): Promise<interfaces.IXInvoice> {
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,
};
}
}