fetch product images from Shopify API and add to order data for invoice generation
This commit is contained in:
parent
46713fc66b
commit
8281f95c71
@ -222,9 +222,9 @@ const generateInvoicePDF = async (orderData) => {
|
||||
for (let i = 0; i < orderData.line_items.length; i++) {
|
||||
const item = orderData.line_items[i];
|
||||
|
||||
// Background color for alternating rows
|
||||
// Background color for alternating rows (slightly taller: 46 height)
|
||||
if (i % 2 === 1) {
|
||||
doc.rect(40, tableY - 4, 515, 38).fill(rowAltColor);
|
||||
doc.rect(40, tableY - 6, 515, 46).fill(rowAltColor);
|
||||
}
|
||||
|
||||
doc.fontSize(9)
|
||||
@ -232,41 +232,57 @@ const generateInvoicePDF = async (orderData) => {
|
||||
.fillColor(textColor);
|
||||
|
||||
// S.No
|
||||
doc.text((i + 1).toString(), 40, tableY);
|
||||
doc.text((i + 1).toString(), 40, tableY + 10);
|
||||
|
||||
// Handle product image
|
||||
let textX = 85;
|
||||
let textWidth = 270;
|
||||
if (item.image_url) {
|
||||
const imgBuffer = await fetchImageBuffer(item.image_url);
|
||||
if (imgBuffer) {
|
||||
try {
|
||||
doc.image(imgBuffer, 85, tableY - 2, { fit: [35, 35] });
|
||||
textX = 130;
|
||||
textWidth = 225;
|
||||
} catch (e) {
|
||||
console.error('Error rendering line item image:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Product Name and Variant/Quantity details
|
||||
const productText = item.title || item.name;
|
||||
doc.text(productText, 85, tableY, { width: 270, height: 15, ellipsis: true });
|
||||
doc.text(productText, textX, tableY, { width: textWidth, height: 15, ellipsis: true });
|
||||
|
||||
// Display quantity/variant info if available
|
||||
if (item.variant_title) {
|
||||
doc.fontSize(8)
|
||||
.fillColor('#64748b')
|
||||
.text(item.variant_title, 85, tableY + 12, { width: 270 });
|
||||
.text(item.variant_title, textX, tableY + 14, { width: textWidth });
|
||||
}
|
||||
|
||||
// Reset font size
|
||||
doc.fontSize(9).fillColor(textColor);
|
||||
|
||||
// Quantity
|
||||
doc.text(item.quantity.toString(), 365, tableY, { width: 50, align: 'right' });
|
||||
doc.text(item.quantity.toString(), 365, tableY + 10, { width: 50, align: 'right' });
|
||||
|
||||
// Unit Price
|
||||
const unitPrice = parseFloat(item.price).toFixed(2);
|
||||
doc.text(`${currencySymbol}${unitPrice}`, 425, tableY, { width: 60, align: 'right' });
|
||||
doc.text(`${currencySymbol}${unitPrice}`, 425, tableY + 10, { width: 60, align: 'right' });
|
||||
|
||||
// Total Price
|
||||
const totalPrice = (parseFloat(item.price) * item.quantity).toFixed(2);
|
||||
doc.text(`${currencySymbol}${totalPrice}`, 495, tableY, { width: 60, align: 'right' });
|
||||
doc.text(`${currencySymbol}${totalPrice}`, 495, tableY + 10, { width: 60, align: 'right' });
|
||||
|
||||
// Divider Line
|
||||
doc.moveTo(40, tableY + 28)
|
||||
.lineTo(555, tableY + 28)
|
||||
doc.moveTo(40, tableY + 38)
|
||||
.lineTo(555, tableY + 38)
|
||||
.lineWidth(0.5)
|
||||
.strokeColor('#f1f5f9')
|
||||
.stroke();
|
||||
|
||||
tableY += 34;
|
||||
tableY += 44;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
37
server.js
37
server.js
@ -52,6 +52,43 @@ app.post('/webhooks/orders/create', verifyShopifyWebhook, async (req, res) => {
|
||||
const processMessage = `[${new Date().toISOString()}] Processing Order ${orderData.order_number}\n`;
|
||||
fs.appendFileSync('webhook.log', processMessage);
|
||||
|
||||
// Fetch product images from Shopify Admin API (requires read_products scope)
|
||||
if (orderData.line_items && orderData.line_items.length > 0) {
|
||||
await Promise.all(orderData.line_items.map(async (item) => {
|
||||
if (!item.product_id) return;
|
||||
try {
|
||||
const shopifyUrl = `https://${process.env.SHOPIFY_STORE_DOMAIN}/admin/api/2024-01/products/${item.product_id}.json`;
|
||||
const response = await fetch(shopifyUrl, {
|
||||
headers: {
|
||||
'X-Shopify-Access-Token': process.env.SHOPIFY_ADMIN_API_TOKEN
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
const product = data.product;
|
||||
if (product) {
|
||||
// Find variant-specific image
|
||||
let imgUrl = null;
|
||||
if (item.variant_id && product.variants) {
|
||||
const variant = product.variants.find(v => v.id === item.variant_id);
|
||||
if (variant && variant.image_id && product.images) {
|
||||
const variantImg = product.images.find(img => img.id === variant.image_id);
|
||||
if (variantImg) imgUrl = variantImg.src;
|
||||
}
|
||||
}
|
||||
// Fallback to main product image
|
||||
item.image_url = imgUrl || product.image?.src || (product.images && product.images[0]?.src) || null;
|
||||
}
|
||||
} else {
|
||||
const errText = await response.text();
|
||||
console.error(`Shopify API error fetching product ${item.product_id}: Status ${response.status} - ${errText}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Failed to fetch image for product ${item.product_id}:`, err);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// 1. Generate the PDF invoice
|
||||
const pdfBuffer = await generateInvoicePDF(orderData);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user