const PDFDocument = require('pdfkit'); /** * Generates a PDF invoice based on Shopify order data. * @param {Object} orderData - The Shopify order payload * @returns {Promise} - A promise that resolves to a Buffer containing the PDF data */ const generateInvoicePDF = (orderData) => { return new Promise((resolve, reject) => { try { const doc = new PDFDocument({ margin: 50 }); let buffers = []; doc.on('data', buffers.push.bind(buffers)); doc.on('end', () => { const pdfData = Buffer.concat(buffers); resolve(pdfData); }); // Invoice Header doc.fontSize(20).text('Invoice', { align: 'right' }); doc.moveDown(); doc.fontSize(12) .text(`Order Number: ${orderData.name || orderData.order_number}`) .text(`Date: ${new Date(orderData.created_at).toLocaleDateString()}`) .moveDown(); // Store Info (You can customize this) const shopName = process.env.SHOP_NAME || 'Your Store Name'; doc.fontSize(14).text(shopName); doc.moveDown(); // Customer Info doc.fontSize(14).text('Billed To:'); doc.fontSize(12).text(`${orderData.billing_address?.first_name || ''} ${orderData.billing_address?.last_name || ''}`); doc.text(`${orderData.billing_address?.address1 || ''}`); if (orderData.billing_address?.address2) { doc.text(`${orderData.billing_address.address2}`); } doc.text(`${orderData.billing_address?.city || ''}, ${orderData.billing_address?.province || ''} ${orderData.billing_address?.zip || ''}`); doc.text(`${orderData.billing_address?.country || ''}`); doc.moveDown(2); // Line Items Table Header doc.fontSize(12).font('Helvetica-Bold'); doc.text('Item', 50, doc.y, { continued: true }); doc.text('Qty', 300, doc.y, { continued: true, width: 50, align: 'right' }); doc.text('Price', 350, doc.y, { continued: true, width: 100, align: 'right' }); doc.text('Total', 450, doc.y, { width: 100, align: 'right' }); doc.moveTo(50, doc.y).lineTo(550, doc.y).stroke(); doc.moveDown(0.5); // Line Items Table Rows doc.font('Helvetica'); let currentY = doc.y; if (orderData.line_items && orderData.line_items.length > 0) { orderData.line_items.forEach(item => { doc.text(item.name, 50, currentY, { width: 250 }); doc.text(item.quantity.toString(), 300, currentY, { width: 50, align: 'right' }); doc.text(`${orderData.currency} ${parseFloat(item.price).toFixed(2)}`, 350, currentY, { width: 100, align: 'right' }); const total = parseFloat(item.price) * item.quantity; doc.text(`${orderData.currency} ${total.toFixed(2)}`, 450, currentY, { width: 100, align: 'right' }); doc.moveDown(0.5); currentY = doc.y; }); } doc.moveTo(50, currentY).lineTo(550, currentY).stroke(); doc.moveDown(1); // Totals doc.text(`Subtotal: ${orderData.currency} ${orderData.subtotal_price}`, { align: 'right' }); if (orderData.total_tax > 0) { doc.text(`Tax: ${orderData.currency} ${orderData.total_tax}`, { align: 'right' }); } doc.text(`Shipping: ${orderData.currency} ${orderData.total_shipping_price_set?.shop_money?.amount || '0.00'}`, { align: 'right' }); doc.font('Helvetica-Bold').text(`Total: ${orderData.currency} ${orderData.total_price}`, { align: 'right' }); doc.end(); } catch (error) { reject(error); } }); }; module.exports = { generateInvoicePDF };