"fix-pdf-guests-same-page"
This commit is contained in:
+80
-28
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
// @ts-ignore — pdf-lib est complet lors d'un npm install propre sur le VPS
|
// @ts-ignore
|
||||||
const { PDFDocument, rgb, StandardFonts, PageSizes } = require('pdf-lib');
|
const { PDFDocument, rgb, StandardFonts } = require('pdf-lib');
|
||||||
|
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
@@ -10,6 +10,12 @@ export interface PdfGuest {
|
|||||||
company?: string | null;
|
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(
|
export async function generateInvoicePdf(
|
||||||
imagePaths: string[],
|
imagePaths: string[],
|
||||||
guests: PdfGuest[],
|
guests: PdfGuest[],
|
||||||
@@ -17,46 +23,92 @@ export async function generateInvoicePdf(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const pdfDoc = await PDFDocument.create();
|
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 imgBytes = await fs.readFile(imgPath);
|
||||||
const ext = path.extname(imgPath).toLowerCase();
|
const ext = path.extname(imgPath).toLowerCase();
|
||||||
const image = ext === '.png'
|
const image = ext === '.png'
|
||||||
? await pdfDoc.embedPng(imgBytes)
|
? await pdfDoc.embedPng(imgBytes)
|
||||||
: await pdfDoc.embedJpg(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 imgW = image.width;
|
||||||
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
|
const imgH = image.height;
|
||||||
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;
|
|
||||||
|
|
||||||
page.drawText('Liste des invites', { x: M, y, size: 18, font: fontBold, color: rgb(0.1, 0.1, 0.1) });
|
const isLast = idx === imagePaths.length - 1;
|
||||||
y -= LH * 1.5;
|
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) });
|
// Hauteur supplémentaire pour la liste d'invités (sous le ticket)
|
||||||
y -= LH;
|
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) });
|
const pageW = imgW;
|
||||||
page.drawText('Entreprise', { x: M + 230, y, size: 11, font: fontBold, color: rgb(0.3, 0.3, 0.3) });
|
const pageH = imgH + listH;
|
||||||
y -= 6;
|
|
||||||
|
|
||||||
page.drawLine({ start: { x: M, y }, end: { x: W - M, y }, thickness: 0.5, color: rgb(0.7, 0.7, 0.7) });
|
const page = pdfDoc.addPage([pageW, pageH]);
|
||||||
y -= LH;
|
|
||||||
|
|
||||||
|
// ── 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) {
|
for (const guest of guests) {
|
||||||
if (y < M + LH) break;
|
if (y < 4) break;
|
||||||
page.drawText(guest.name, { x: M, y, size: 11, font, color: rgb(0.1, 0.1, 0.1), maxWidth: 220 });
|
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) {
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user