Files
apex/server/services/exportPdf.js
T
lejayandCursor 6c0d7e47b8 v2.0
Co-authored-by: Cursor <[email protected]>
2026-05-28 07:20:38 +02:00

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();
});
}