"fix-pdf-guests-same-page"

This commit is contained in:
deploy
2026-04-29 15:04:48 +02:00
parent 8b125d4ecf
commit e9bee29a8a
+80 -28
View File
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// @ts-ignore — pdf-lib est complet lors d'un npm install propre sur le VPS
const { PDFDocument, rgb, StandardFonts, PageSizes } = require('pdf-lib');
// @ts-ignore
const { PDFDocument, rgb, StandardFonts } = require('pdf-lib');
import fs from 'fs/promises';
import path from 'path';
@@ -10,6 +10,12 @@ export interface PdfGuest {
company?: string | null;
}
/**
* Génère le PDF de la facture.
* - Une page par image (ticket/reçu)
* - Si des invités sont présents, la liste est ajoutée EN BAS de la dernière
* page d'image (même page, sous le ticket), sans page séparée.
*/
export async function generateInvoicePdf(
imagePaths: string[],
guests: PdfGuest[],
@@ -17,46 +23,92 @@ export async function generateInvoicePdf(
): Promise<void> {
const pdfDoc = await PDFDocument.create();
for (const imgPath of imagePaths) {
const font = guests.length > 0 ? await pdfDoc.embedFont(StandardFonts.Helvetica) : null;
const fontBold = guests.length > 0 ? await pdfDoc.embedFont(StandardFonts.HelveticaBold) : null;
for (let idx = 0; idx < imagePaths.length; idx++) {
const imgPath = imagePaths[idx];
const imgBytes = await fs.readFile(imgPath);
const ext = path.extname(imgPath).toLowerCase();
const image = ext === '.png'
? await pdfDoc.embedPng(imgBytes)
: await pdfDoc.embedJpg(imgBytes);
const dims = image.scale(1);
const page = pdfDoc.addPage([dims.width, dims.height]);
page.drawImage(image, { x: 0, y: 0, width: dims.width, height: dims.height });
}
if (guests.length > 0) {
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
const fontBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
const [W, H] = PageSizes.A4;
const M = 50;
const LH = 24;
const page = pdfDoc.addPage([W, H]);
let y = H - M;
const imgW = image.width;
const imgH = image.height;
page.drawText('Liste des invites', { x: M, y, size: 18, font: fontBold, color: rgb(0.1, 0.1, 0.1) });
y -= LH * 1.5;
const isLast = idx === imagePaths.length - 1;
const addList = isLast && guests.length > 0;
page.drawLine({ start: { x: M, y }, end: { x: W - M, y }, thickness: 1, color: rgb(0.2, 0.2, 0.2) });
y -= LH;
// Hauteur supplémentaire pour la liste d'invités (sous le ticket)
const PADDING = 20; // marge entre ticket et liste
const LINE_H = 22; // hauteur par ligne d'invité
const HEADER_H = 50; // titre + séparateur
const listH = addList
? HEADER_H + guests.length * LINE_H + PADDING * 2
: 0;
page.drawText('Nom', { x: M, y, size: 11, font: fontBold, color: rgb(0.3, 0.3, 0.3) });
page.drawText('Entreprise', { x: M + 230, y, size: 11, font: fontBold, color: rgb(0.3, 0.3, 0.3) });
y -= 6;
const pageW = imgW;
const pageH = imgH + listH;
page.drawLine({ start: { x: M, y }, end: { x: W - M, y }, thickness: 0.5, color: rgb(0.7, 0.7, 0.7) });
y -= LH;
const page = pdfDoc.addPage([pageW, pageH]);
// ── Image (placée en haut de la page) ──────────────────────
page.drawImage(image, { x: 0, y: listH, width: imgW, height: imgH });
// ── Liste des invités (en bas, sous l'image) ───────────────
if (addList && font && fontBold) {
const M = 30; // marge gauche/droite
let y = listH - PADDING;
// Ligne de séparation entre ticket et liste
page.drawLine({
start: { x: M, y: listH - 1 },
end: { x: pageW - M, y: listH - 1 },
thickness: 1,
color: rgb(0.8, 0.8, 0.8),
});
// Titre
page.drawText('Invités', {
x: M, y,
size: 13,
font: fontBold,
color: rgb(0.15, 0.15, 0.15),
});
y -= HEADER_H - PADDING - 8;
// Séparateur sous le titre
page.drawLine({
start: { x: M, y },
end: { x: pageW - M, y },
thickness: 0.5,
color: rgb(0.75, 0.75, 0.75),
});
y -= 16;
// Lignes invités
for (const guest of guests) {
if (y < M + LH) break;
page.drawText(guest.name, { x: M, y, size: 11, font, color: rgb(0.1, 0.1, 0.1), maxWidth: 220 });
if (y < 4) break;
page.drawText(guest.name, {
x: M, y,
size: 11,
font: fontBold,
color: rgb(0.1, 0.1, 0.1),
maxWidth: guest.company ? (pageW - M * 2) / 2 - 10 : pageW - M * 2,
});
if (guest.company) {
page.drawText(guest.company, { x: M + 230, y, size: 11, font, color: rgb(0.1, 0.1, 0.1), maxWidth: W - M - 230 - M });
page.drawText(guest.company, {
x: M + (pageW - M * 2) / 2,
y,
size: 11,
font,
color: rgb(0.35, 0.35, 0.35),
maxWidth: (pageW - M * 2) / 2,
});
}
y -= LINE_H;
}
y -= LH;
}
}