const fs = require("fs"); const PDFDocument = require("pdfkit"); function createInvoice(invoice, path) { let doc = new PDFDocument({ size: "A4", margin: 50 }); generateHeader(doc); generateCustomerInformation(doc, invoice); generateInvoiceTable(doc, invoice); generateFooter(doc); doc.end(); doc.pipe(fs.createWriteStream(path)); } function generateHeader(doc) { doc .image("logo.png", 50, 45, { width: 50 }) .fillColor("#444444") .fontSize(20) .text("ACME Inc.", 110, 57) .fontSize(10) .text("ACME Inc.", 200, 50, { align: "right" }) .text("123 Main Street", 200, 65, { align: "right" }) .text("New York, NY, 10025", 200, 80, { align: "right" }) .moveDown(); } function generateCustomerInformation(doc, invoice) { doc .fillColor("#444444") .fontSize(20) .text("Invoice", 50, 160); generateHr(doc, 185); const customerInformationTop = 200; doc .fontSize(10) .text("Invoice Number:", 50, customerInformationTop) .font("Helvetica-Bold") .text(invoice.invoice_nr, 150, customerInformationTop) .font("Helvetica") .text("Invoice Date:", 50, customerInformationTop + 15) .text(formatDate(new Date()), 150, customerInformationTop + 15) .text("Balance Due:", 50, customerInformationTop + 30) .text( formatCurrency(invoice.subtotal - invoice.paid), 150, customerInformationTop + 30 ) .font("Helvetica-Bold") .text(invoice.shipping.name, 300, customerInformationTop) .font("Helvetica") .text(invoice.shipping.address, 300, customerInformationTop + 15) .text( invoice.shipping.city + ", " + invoice.shipping.state + ", " + invoice.shipping.country, 300, customerInformationTop + 30 ) .moveDown(); generateHr(doc, 252); } function generateInvoiceTable(doc, invoice) { let i; const invoiceTableTop = 330; doc.font("Helvetica-Bold"); generateTableRow( doc, invoiceTableTop, "Item", "Description", "Unit Cost", "Quantity", "Line Total" ); generateHr(doc, invoiceTableTop + 20); doc.font("Helvetica"); for (i = 0; i < invoice.items.length; i++) { const item = invoice.items[i]; const position = invoiceTableTop + (i + 1) * 30; generateTableRow( doc, position, item.item, item.description, formatCurrency(item.amount / item.quantity), item.quantity, formatCurrency(item.amount) ); generateHr(doc, position + 20); } const subtotalPosition = invoiceTableTop + (i + 1) * 30; generateTableRow( doc, subtotalPosition, "", "", "Subtotal", "", formatCurrency(invoice.subtotal) ); const paidToDatePosition = subtotalPosition + 20; generateTableRow( doc, paidToDatePosition, "", "", "Paid To Date", "", formatCurrency(invoice.paid) ); const duePosition = paidToDatePosition + 25; doc.font("Helvetica-Bold"); generateTableRow( doc, duePosition, "", "", "Balance Due", "", formatCurrency(invoice.subtotal - invoice.paid) ); doc.font("Helvetica"); } function generateFooter(doc) { doc .fontSize(10) .text( "Payment is due within 15 days. Thank you for your business.", 50, 780, { align: "center", width: 500 } ); } function generateTableRow( doc, y, item, description, unitCost, quantity, lineTotal ) { doc .fontSize(10) .text(item, 50, y) .text(description, 150, y) .text(unitCost, 280, y, { width: 90, align: "right" }) .text(quantity, 370, y, { width: 90, align: "right" }) .text(lineTotal, 0, y, { align: "right" }); } function generateHr(doc, y) { doc .strokeColor("#aaaaaa") .lineWidth(1) .moveTo(50, y) .lineTo(550, y) .stroke(); } function formatCurrency(cents) { return "$" + (cents / 100).toFixed(2); } function formatDate(date) { const day = date.getDate(); const month = date.getMonth() + 1; const year = date.getFullYear(); return year + "/" + month + "/" + day; } module.exports = { createInvoice };