Files
website-secure/lib/generate-packing-pdf.ts
T
pm 9c14a19a87
DevSecOps Enterprise Pipeline / security-gate-and-deploy (push) Failing after 41s
chore: upload parte 1 - logica
2026-06-01 15:35:53 +01:00

140 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 PackingPdfData {
packing_number: string;
created_at: string;
po_number: string;
customer_ref?: string | null;
customer_name: string;
customer_code: string;
customer_email?: string | null;
customer_phone?: string | null;
customer_address?: string | null;
customer_contact?: string | null;
product_name: string;
product_sku: string;
quantity: number;
notes?: string | null;
serials: { serial_number: string }[];
}
export function generatePackingPdf(data: PackingPdfData) {
const { doc, contentY } = createBrandedPdf({
title: "PACKING LIST",
documentNumber: data.packing_number,
date: new Date(data.created_at).toLocaleDateString("en-GB"),
recipient: {
label: "SHIP TO",
name: data.customer_name,
code: data.customer_code,
contact: data.customer_contact,
address: data.customer_address,
phone: data.customer_phone,
email: data.customer_email,
},
});
const pageWidth = doc.internal.pageSize.getWidth();
const margin = 14;
const contentWidth = pageWidth - margin * 2;
// --- Order details row ---
let y = contentY;
doc.setFillColor(...COLORS.bgLight);
doc.setDrawColor(...COLORS.border);
doc.setLineWidth(0.2);
doc.roundedRect(margin, y, contentWidth, 16, 1.5, 1.5, "FD");
const colWidth = contentWidth / 4;
const labels = ["PO Number", "Customer Ref", "Product", "Qty Shipped"];
const values = [
data.po_number,
data.customer_ref || "-",
`${data.product_name} (${data.product_sku})`,
String(data.quantity),
];
labels.forEach((label, i) => {
const x = margin + 4 + i * colWidth;
doc.setFontSize(6.5);
doc.setFont("helvetica", "normal");
doc.setTextColor(...COLORS.muted);
doc.text(label, x, y + 5);
doc.setFontSize(8);
doc.setFont("helvetica", "bold");
doc.setTextColor(...COLORS.primary);
const val = doc.splitTextToSize(values[i], colWidth - 8);
doc.text(val[0], x, y + 11);
});
y += 22;
// --- Serial Numbers section (clean list layout like PO Order Items) ---
doc.setFontSize(9);
doc.setFont("helvetica", "bold");
doc.setTextColor(...COLORS.primary);
doc.text("Serial Numbers", margin, y);
y += 4;
const tableData = data.serials.map((s, i) => [String(i + 1), s.serial_number]);
autoTable(doc, {
startY: y,
head: [["#", "Serial Number"]],
body: tableData,
theme: "plain",
headStyles: {
...TABLE_HEAD_STYLES,
fillColor: COLORS.bgLight,
lineWidth: 0,
},
bodyStyles: {
...TABLE_BODY_STYLES,
font: "courier",
lineWidth: 0,
},
alternateRowStyles: { fillColor: [250, 250, 250] },
columnStyles: {
0: { cellWidth: 14, halign: "center" },
1: { cellWidth: "auto" },
},
margin: { left: margin, right: margin },
styles: {
lineColor: COLORS.border,
lineWidth: 0,
cellPadding: 2,
},
});
// --- 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;
}