UNPKG

@casoon/invoice-generator

Version:

Generate PDF invoices, XRechnung XML, and ZUGFeRD PDF/A-3 from JSON data with TypeScript support

195 lines 9.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EInvoiceSection = void 0; class EInvoiceSection { constructor(doc, currentY) { this.pageHeight = 842; // A4 Höhe in Punkten this.footerHeight = 120; // Platz für Footer this.doc = doc; this.currentY = currentY; } /** * E-Rechnung Sektion * Strukturierte elektronische Rechnung nach XRechnung-Standard */ draw(invoice) { // E-Rechnung Header this.drawEInvoiceHeader(); // Rechnungssteller (Seller) this.drawSellerSection(invoice); // Rechnungsempfänger (Buyer) this.drawBuyerSection(invoice); // Rechnungsdetails this.drawInvoiceDetails(invoice); // Positionen in strukturierter Form this.drawStructuredItems(invoice); // Summen und Steuern this.drawStructuredTotals(invoice); // Zahlungsinformationen this.drawPaymentInformation(invoice); return this.currentY; } drawEInvoiceHeader() { // E-Rechnung Titel this.doc.font('Helvetica-Bold') .fontSize(18) .fillColor('#008080') .text('E-RECHNUNG', 50, this.currentY, { continued: false }); this.currentY += 25; // XRechnung-konforme Metadaten this.doc.font('Helvetica-Bold') .fontSize(12) .fillColor('black') .text('Elektronische Rechnung nach XRechnung-Standard', 50, this.currentY, { continued: false }); this.currentY += 20; // Trennlinie this.doc.moveTo(50, this.currentY) .lineTo(550, this.currentY) .lineWidth(2) .strokeColor('#008080') .stroke(); this.currentY += 20; } drawSellerSection(invoice) { this.doc.font('Helvetica-Bold') .fontSize(14) .text('Rechnungssteller (Seller)', 50, this.currentY, { continued: false }); this.currentY += 20; // Strukturierte Seller-Informationen this.doc.font('Helvetica') .fontSize(10); this.drawInfoRow('Name:', invoice.sender.name, 50); this.drawInfoRow('Firma:', invoice.sender.company || '', 50); this.drawInfoRow('Straße:', invoice.sender.address.street, 50); this.drawInfoRow('PLZ/Ort:', `${invoice.sender.address.postalCode} ${invoice.sender.address.city}`, 50); this.drawInfoRow('Telefon:', invoice.sender.contactInfo.phone, 50); this.drawInfoRow('E-Mail:', invoice.sender.contactInfo.email, 50); this.drawInfoRow('Website:', invoice.sender.contactInfo.website || '', 50); this.drawInfoRow('Geschäftsinhaber:', invoice.sender.businessOwner || '', 50); this.drawInfoRow('USt-IdNr.:', invoice.sender.vatId || '', 50); this.currentY += 20; } drawBuyerSection(invoice) { this.doc.font('Helvetica-Bold') .fontSize(14) .text('Rechnungsempfänger (Buyer)', 50, this.currentY, { continued: false }); this.currentY += 20; // Strukturierte Buyer-Informationen this.doc.font('Helvetica') .fontSize(10); this.drawInfoRow('Name:', invoice.recipient.name, 50); this.drawInfoRow('Straße:', invoice.recipient.address.street, 50); this.drawInfoRow('PLZ/Ort:', `${invoice.recipient.address.postalCode} ${invoice.recipient.address.city}`, 50); this.currentY += 20; } drawInvoiceDetails(invoice) { this.doc.font('Helvetica-Bold') .fontSize(14) .text('Rechnungsdetails', 50, this.currentY, { continued: false }); this.currentY += 20; // Strukturierte Rechnungsdetails this.doc.font('Helvetica') .fontSize(10); this.drawInfoRow('Rechnungsnummer:', invoice.details.invoiceNumber, 50); this.drawInfoRow('Kundennummer:', invoice.details.customerNumber, 50); this.drawInfoRow('Rechnungsdatum:', invoice.details.invoiceDate, 50); this.drawInfoRow('Lieferdatum:', invoice.details.deliveryDate, 50); this.drawInfoRow('Leistungszeitraum:', invoice.details.servicePeriod, 50); this.currentY += 20; } drawStructuredItems(invoice) { this.doc.font('Helvetica-Bold') .fontSize(14) .text('Rechnungspositionen', 50, this.currentY, { continued: false }); this.currentY += 20; // Tabellenkopf const tableWidth = 500; const colWidths = [250, 50, 50, 50, 100]; // Description, Qty, Unit, VAT, Total this.doc.rect(50, this.currentY, tableWidth, 25) .fill('#f0f0f0') .stroke(); this.doc.font('Helvetica-Bold') .fontSize(9) .fillColor('black') .text('Beschreibung', 55, this.currentY + 8, { width: colWidths[0], continued: false }) .text('Menge', 305, this.currentY + 8, { width: colWidths[1], align: 'center', continued: false }) .text('Einh.', 355, this.currentY + 8, { width: colWidths[2], align: 'center', continued: false }) .text('MwSt.', 405, this.currentY + 8, { width: colWidths[3], align: 'center', continued: false }) .text('Gesamt', 455, this.currentY + 8, { width: colWidths[4], align: 'right', continued: false }); this.currentY += 25; // Positionen invoice.items.forEach((item, index) => { // Prüfe ob genug Platz auf der aktuellen Seite ist if (this.currentY + 20 > this.pageHeight - this.footerHeight) { this.addNewPage(); } const rowColor = index % 2 === 0 ? '#ffffff' : '#f8f8f8'; const rowHeight = 20; // Feste Höhe für E-Rechnung-Tabelle // Zeilen-Hintergrund - exakt mit Zeilenhöhe this.doc.rect(50, this.currentY, tableWidth, rowHeight) .fill(rowColor) .stroke(); this.doc.font('Helvetica') .fontSize(8) .fillColor('black') .text(item.description, 55, this.currentY + 6, { width: colWidths[0], continued: false }) .text(item.quantity.toString(), 305, this.currentY + 6, { width: colWidths[1], align: 'center', continued: false }) .text(item.unit, 355, this.currentY + 6, { width: colWidths[2], align: 'center', continued: false }) .text(`${item.vatRate}%`, 405, this.currentY + 6, { width: colWidths[3], align: 'center', continued: false }) .font('Helvetica-Bold') .text(`${item.total.toFixed(2).replace('.', ',')} ${item.currency}`, 455, this.currentY + 6, { width: colWidths[4], align: 'right', continued: false }); this.currentY += rowHeight; }); this.currentY += 20; } drawStructuredTotals(invoice) { this.doc.font('Helvetica-Bold') .fontSize(14) .text('Summen und Steuern', 50, this.currentY, { continued: false }); this.currentY += 20; // Strukturierte Summen this.doc.font('Helvetica') .fontSize(10); this.drawInfoRow('Nettobetrag:', `${invoice.totals.netAmount.toFixed(2).replace('.', ',')} ${invoice.totals.currency}`, 50); this.drawInfoRow('MwSt.-Satz:', `${invoice.totals.vatRate.toFixed(2).replace('.', ',')}%`, 50); this.drawInfoRow('MwSt.-Betrag:', `${invoice.totals.vatAmount.toFixed(2).replace('.', ',')} ${invoice.totals.currency}`, 50); this.currentY += 15; // Gesamtbetrag hervorgehoben this.doc.font('Helvetica-Bold') .fontSize(16) .text(`Gesamtbetrag: ${invoice.totals.grossAmount.toFixed(2).replace('.', ',')} ${invoice.totals.currency}`, 50, this.currentY, { continued: false }); this.currentY += 30; } drawPaymentInformation(invoice) { this.doc.font('Helvetica-Bold') .fontSize(14) .text('Zahlungsinformationen', 50, this.currentY, { continued: false }); this.currentY += 20; // Strukturierte Zahlungsinformationen this.doc.font('Helvetica') .fontSize(10); const paymentText = `Zahlbar ohne Abzug bis zum ${invoice.paymentInfo.dueDate}.`; this.drawInfoRow('Zahlungsziel:', paymentText, 50); this.drawInfoRow('Bank:', invoice.paymentInfo.bank, 50); this.drawInfoRow('Kontoinhaber:', invoice.paymentInfo.accountHolder, 50); this.drawInfoRow('IBAN:', invoice.paymentInfo.iban, 50); this.drawInfoRow('BIC/SWIFT:', invoice.paymentInfo.bic, 50); this.currentY += 20; } drawInfoRow(label, value, x) { if (!value) return; // Überspringe leere Werte this.doc.font('Helvetica-Bold') .fontSize(10) .text(label, x, this.currentY, { width: 150, continued: false }) .font('Helvetica') .text(value, x + 160, this.currentY, { continued: false }); this.currentY += 15; } addNewPage() { this.doc.addPage(); this.currentY = 50; } } exports.EInvoiceSection = EInvoiceSection; //# sourceMappingURL=e-invoice-section.js.map