102 lines
3.2 KiB
JavaScript
102 lines
3.2 KiB
JavaScript
import PDFDocument from 'pdfkit';
|
|
|
|
function addSectionTitle(doc, title) {
|
|
doc.moveDown(0.5);
|
|
doc.fontSize(14).font('Helvetica-Bold').text(title);
|
|
doc.moveDown(0.3);
|
|
doc.fontSize(10).font('Helvetica');
|
|
}
|
|
|
|
function ensurePageSpace(doc, neededHeight = 80) {
|
|
if (doc.y + neededHeight > doc.page.height - doc.page.margins.bottom) {
|
|
doc.addPage();
|
|
}
|
|
}
|
|
|
|
function keyValue(doc, key, value) {
|
|
doc.font('Helvetica-Bold').text(`${key}: `, { continued: true });
|
|
doc.font('Helvetica').text(String(value ?? '-'));
|
|
}
|
|
|
|
function tableRow(doc, cols, widths, opts = {}) {
|
|
const startX = doc.x;
|
|
const y = doc.y;
|
|
const lineHeight = opts.lineHeight || 14;
|
|
|
|
let x = startX;
|
|
for (let i = 0; i < cols.length; i++) {
|
|
const text = cols[i] == null ? '-' : String(cols[i]);
|
|
doc.text(text, x, y, {
|
|
width: widths[i],
|
|
lineBreak: false
|
|
});
|
|
x += widths[i];
|
|
}
|
|
doc.y = y + lineHeight;
|
|
}
|
|
|
|
export function generateOrderDossierPdf({ orderId, createdAt, customerName, config, cuttingList, packing }) {
|
|
return new Promise((resolve, reject) => {
|
|
const doc = new PDFDocument({ size: 'A4', margin: 40 });
|
|
const chunks = [];
|
|
|
|
doc.on('data', (chunk) => chunks.push(chunk));
|
|
doc.on('end', () => resolve(Buffer.concat(chunks)));
|
|
doc.on('error', reject);
|
|
|
|
doc.fontSize(18).font('Helvetica-Bold').text(`Dossier technique commande #${orderId}`);
|
|
doc.fontSize(10).font('Helvetica').text(`Généré le ${new Date().toLocaleString('fr-CH')}`);
|
|
if (createdAt) doc.text(`Commande du ${new Date(createdAt).toLocaleString('fr-CH')}`);
|
|
if (customerName) doc.text(`Client: ${customerName}`);
|
|
|
|
addSectionTitle(doc, 'Configuration');
|
|
keyValue(doc, 'Dimensions', `${config.widthMm} x ${config.heightMm} x ${config.depthMm} mm`);
|
|
keyValue(doc, 'Installation', config.installationType === 'niche' ? 'Encastree' : 'Libre');
|
|
keyValue(doc, 'Portes', config.doorType === 'sliding' ? 'Coulissantes' : 'Battantes');
|
|
keyValue(doc, 'Modules', config.moduleCount || 0);
|
|
|
|
addSectionTitle(doc, 'Liste de decoupage');
|
|
const cutWidths = [170, 130, 40, 130];
|
|
tableRow(doc, ['Piece', 'L x H x Ep.', 'Qte', 'Finition'], cutWidths, { lineHeight: 16 });
|
|
doc.moveTo(doc.x, doc.y).lineTo(doc.page.width - doc.page.margins.right, doc.y).stroke();
|
|
doc.moveDown(0.2);
|
|
|
|
for (const piece of (cuttingList?.pieces || [])) {
|
|
ensurePageSpace(doc, 18);
|
|
tableRow(
|
|
doc,
|
|
[
|
|
piece.description,
|
|
`${piece.widthMm}x${piece.heightMm}x${piece.thicknessMm}`,
|
|
piece.quantity,
|
|
piece.finishLabel || '-'
|
|
],
|
|
cutWidths
|
|
);
|
|
}
|
|
|
|
addSectionTitle(doc, 'Colisage');
|
|
const packWidths = [50, 170, 70, 70];
|
|
tableRow(doc, ['Colis', 'Niveau', 'Poids', 'Pieces'], packWidths, { lineHeight: 16 });
|
|
doc.moveTo(doc.x, doc.y).lineTo(doc.page.width - doc.page.margins.right, doc.y).stroke();
|
|
doc.moveDown(0.2);
|
|
|
|
for (const box of (packing?.boxes || [])) {
|
|
ensurePageSpace(doc, 18);
|
|
tableRow(
|
|
doc,
|
|
[
|
|
box.id,
|
|
box.level || '-',
|
|
`${Number(box.totalWeightKg || 0).toFixed(1)} kg`,
|
|
box.pieces?.length || 0
|
|
],
|
|
packWidths
|
|
);
|
|
}
|
|
|
|
doc.end();
|
|
});
|
|
}
|
|
|