136 lines
3.8 KiB
TypeScript
136 lines
3.8 KiB
TypeScript
import autoTable from "jspdf-autotable";
|
|
import {
|
|
createBrandedPdf,
|
|
addBrandedFooter,
|
|
COLORS,
|
|
TABLE_HEAD_STYLES,
|
|
TABLE_BODY_STYLES,
|
|
TABLE_STYLES,
|
|
} from "./pdf-template";
|
|
|
|
interface SupplierPackingPdfItem {
|
|
part_number: string;
|
|
component_name: string;
|
|
quantity: number;
|
|
used_in_products: string | null;
|
|
}
|
|
|
|
interface SupplierPackingPdfData {
|
|
packing_number: string;
|
|
created_at: string;
|
|
supplier_name: string;
|
|
supplier_code: string;
|
|
supplier_email?: string | null;
|
|
supplier_phone?: string | null;
|
|
supplier_address?: string | null;
|
|
supplier_contact?: string | null;
|
|
notes?: string | null;
|
|
items: SupplierPackingPdfItem[];
|
|
}
|
|
|
|
export function generateSupplierPackingPdf(data: SupplierPackingPdfData) {
|
|
const { doc, contentY } = createBrandedPdf({
|
|
title: "SUPPLIER PACKING LIST",
|
|
documentNumber: data.packing_number,
|
|
date: new Date(data.created_at).toLocaleDateString("en-GB"),
|
|
recipient: {
|
|
label: "SUPPLIER",
|
|
name: data.supplier_name,
|
|
code: data.supplier_code,
|
|
contact: data.supplier_contact,
|
|
address: data.supplier_address,
|
|
phone: data.supplier_phone,
|
|
email: data.supplier_email,
|
|
},
|
|
});
|
|
|
|
const pageWidth = doc.internal.pageSize.getWidth();
|
|
const margin = 14;
|
|
const contentWidth = pageWidth - margin * 2;
|
|
|
|
// --- Summary bar ---
|
|
let y = contentY;
|
|
const totalQty = data.items.reduce((sum, item) => sum + item.quantity, 0);
|
|
|
|
doc.setFillColor(...COLORS.bgLight);
|
|
doc.setDrawColor(...COLORS.border);
|
|
doc.setLineWidth(0.2);
|
|
doc.roundedRect(margin, y, contentWidth, 14, 1.5, 1.5, "FD");
|
|
|
|
const summaryItems = [
|
|
{ label: "Total Components", value: String(data.items.length) },
|
|
{ label: "Total Quantity", value: String(totalQty) },
|
|
];
|
|
|
|
summaryItems.forEach((item, i) => {
|
|
const x = margin + 4 + i * (contentWidth / 2);
|
|
doc.setFontSize(6.5);
|
|
doc.setFont("helvetica", "normal");
|
|
doc.setTextColor(...COLORS.muted);
|
|
doc.text(item.label, x, y + 5);
|
|
doc.setFontSize(9);
|
|
doc.setFont("helvetica", "bold");
|
|
doc.setTextColor(...COLORS.primary);
|
|
doc.text(item.value, x, y + 11);
|
|
});
|
|
|
|
y += 20;
|
|
|
|
// --- Components table ---
|
|
doc.setFontSize(9);
|
|
doc.setFont("helvetica", "bold");
|
|
doc.setTextColor(...COLORS.primary);
|
|
doc.text("Components", margin, y);
|
|
y += 4;
|
|
|
|
const tableData = data.items.map((item, i) => [
|
|
String(i + 1),
|
|
item.part_number,
|
|
item.component_name,
|
|
String(item.quantity),
|
|
item.used_in_products || "-",
|
|
]);
|
|
|
|
autoTable(doc, {
|
|
startY: y,
|
|
head: [["#", "Part Number", "Name", "Qty", "Used In Products"]],
|
|
body: tableData,
|
|
theme: "grid",
|
|
headStyles: TABLE_HEAD_STYLES,
|
|
bodyStyles: TABLE_BODY_STYLES,
|
|
alternateRowStyles: { fillColor: [252, 252, 252] },
|
|
columnStyles: {
|
|
0: { cellWidth: 12, halign: "center" },
|
|
1: { cellWidth: 32, font: "courier" },
|
|
2: { cellWidth: 45 },
|
|
3: { cellWidth: 16, halign: "center" },
|
|
4: { cellWidth: "auto" },
|
|
},
|
|
margin: { left: margin, right: margin },
|
|
styles: TABLE_STYLES,
|
|
});
|
|
|
|
// --- Notes ---
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const finalY = (doc as any).lastAutoTable?.finalY || y + 30;
|
|
if (data.notes) {
|
|
const noteY = finalY + 6;
|
|
doc.setFillColor(...COLORS.bgLight);
|
|
doc.setDrawColor(...COLORS.border);
|
|
doc.setLineWidth(0.2);
|
|
doc.roundedRect(margin, noteY, contentWidth, 16, 1.5, 1.5, "FD");
|
|
doc.setFontSize(6.5);
|
|
doc.setFont("helvetica", "bold");
|
|
doc.setTextColor(...COLORS.accent);
|
|
doc.text("NOTES", margin + 4, noteY + 5);
|
|
doc.setFontSize(7.5);
|
|
doc.setFont("helvetica", "normal");
|
|
doc.setTextColor(...COLORS.secondary);
|
|
const noteLines = doc.splitTextToSize(data.notes, contentWidth - 8);
|
|
doc.text(noteLines, margin + 4, noteY + 11);
|
|
}
|
|
|
|
addBrandedFooter(doc);
|
|
return doc;
|
|
}
|