Initial local backup snapshot
This commit is contained in:
commit
acd9e14ba5
367 changed files with 118038 additions and 0 deletions
89
server/salleAdministrativeDecisionPdf.ts
Normal file
89
server/salleAdministrativeDecisionPdf.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import PDFDocument from "pdfkit";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const CCDS_LOGO_PATH = path.resolve(process.cwd(), "client/src/assets/ccds.png");
|
||||
|
||||
function drawLogo(doc: PDFKit.PDFDocument, x: number, y: number, width: number, height: number) {
|
||||
if (!fs.existsSync(CCDS_LOGO_PATH)) return;
|
||||
try {
|
||||
doc.image(CCDS_LOGO_PATH, x, y, { fit: [width, height], align: "center", valign: "center" });
|
||||
} catch (error) {
|
||||
console.warn("[SalleAdministrativeDecisionPdf] Impossible de charger le logo CCDS:", error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateSalleAdministrativeDecisionPdf(input: {
|
||||
requestId: number;
|
||||
decisionText: string;
|
||||
signedAt?: string | Date | null;
|
||||
signedByLabel?: string | null;
|
||||
}) {
|
||||
const pdfBuffer = await new Promise<Buffer>((resolve, reject) => {
|
||||
try {
|
||||
const doc = new PDFDocument({
|
||||
size: "A4",
|
||||
margins: { top: 42, bottom: 42, left: 42, right: 42 },
|
||||
});
|
||||
const chunks: Buffer[] = [];
|
||||
doc.on("data", (chunk: Buffer) => chunks.push(chunk));
|
||||
doc.on("end", () => resolve(Buffer.concat(chunks)));
|
||||
doc.on("error", reject);
|
||||
|
||||
const width = doc.page.width - doc.page.margins.left - doc.page.margins.right;
|
||||
let y = doc.page.margins.top;
|
||||
drawLogo(doc, doc.page.margins.left + (width - 90) / 2, y, 90, 90);
|
||||
y += 102;
|
||||
|
||||
doc.font("Helvetica-Bold").fontSize(18).fillColor("#0f2d63").text(
|
||||
"DÉCISION ADMINISTRATIVE PRIORITAIRE",
|
||||
doc.page.margins.left,
|
||||
y,
|
||||
{ width, align: "center" }
|
||||
);
|
||||
y += 22;
|
||||
doc.font("Helvetica").fontSize(10).fillColor("#475569").text(
|
||||
`Dossier salle #${input.requestId}`,
|
||||
doc.page.margins.left,
|
||||
y,
|
||||
{ width, align: "center" }
|
||||
);
|
||||
y += 34;
|
||||
|
||||
const bodyHeight = input.signedAt ? 360 : 420;
|
||||
doc.roundedRect(doc.page.margins.left, y, width, bodyHeight, 10).stroke("#cbd5e1");
|
||||
doc.font("Helvetica").fontSize(11).fillColor("#1f2937").text(
|
||||
input.decisionText,
|
||||
doc.page.margins.left + 18,
|
||||
y + 18,
|
||||
{ width: width - 36, lineGap: 4 }
|
||||
);
|
||||
|
||||
if (input.signedAt) {
|
||||
const signatureY = y + bodyHeight + 18;
|
||||
doc.roundedRect(doc.page.margins.left, signatureY, width, 62, 8).fillAndStroke("#eef6ff", "#93c5fd");
|
||||
doc.font("Helvetica-Bold").fontSize(11).fillColor("#1d4ed8").text(
|
||||
"Visa de la Direction",
|
||||
doc.page.margins.left + 16,
|
||||
signatureY + 12,
|
||||
{ width: width - 32 }
|
||||
);
|
||||
doc.font("Helvetica").fontSize(10).fillColor("#1f2937").text(
|
||||
`Validation électronique le ${new Date(input.signedAt).toLocaleString("fr-FR")}${input.signedByLabel ? ` par ${input.signedByLabel}` : ""}.`,
|
||||
doc.page.margins.left + 16,
|
||||
signatureY + 32,
|
||||
{ width: width - 32 }
|
||||
);
|
||||
}
|
||||
|
||||
doc.end();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
buffer: pdfBuffer,
|
||||
fileName: `decision-administrative-salle-${input.requestId}.pdf`,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue