RJBULK-APP/tmp/render-all-pages.mjs
SJCoetz 4a18b8789e fix: prevent page overlap in delivery reports
Add an ensureSpace check in the customer delivery PDF report function to force page breaks when there isn't enough room for a full customer group, preventing content overlap between consecutive customer sections. The check accounts for customer header, table header, data rows, and subtotal elements.

Add two diagnostic scripts in the tmp/ directory:
- diag-customer-report.mjs: generates a synthetic dataset to reproduce the page overlap bug
- render-all-pages.mjs: renders each page of a generated PDF to PNG images for testing
2026-07-21 13:49:36 +02:00

49 lines
1.8 KiB
JavaScript

/**
* Render every page of the diagnostic PDF using Chromium's built-in PDF viewer
* and the pdf.js `applicationOptions` to size the viewport properly.
*/
import puppeteer from "puppeteer-core";
import { readFileSync, mkdirSync, readdirSync } from "fs";
import { join } from "path";
const CHROME = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
const PDF = "/tmp/rjbulk-pdfs/customer-delivery-diag.pdf";
const OUT_DIR = "/tmp/rjbulk-pdf-images";
mkdirSync(OUT_DIR, { recursive: true });
const browser = await puppeteer.launch({
executablePath: CHROME,
headless: "new",
args: ["--no-sandbox", "--disable-gpu"],
});
// We embed the PDF in an <embed> on a blank HTML page so we can use the
// `#page=N` URL fragment which Chromium's PDF viewer honours.
const html = `<!doctype html><html><body style="margin:0;padding:0">
<embed src="file://${PDF}" type="application/pdf" width="100%" height="1200" id="pdf"/>
</body></html>`;
const hostPath = "/tmp/rjbulk-pdfs/_host.html";
const { writeFileSync } = await import("fs");
writeFileSync(hostPath, html);
const page = await browser.newPage();
await page.setViewport({ width: 900, height: 1300 });
await page.goto(`file://${hostPath}`, { waitUntil: "networkidle2", timeout: 30000 });
await new Promise((r) => setTimeout(r, 1500));
// 1/6 means 6 pages — read it from the toolbar
const totalPages = await page.evaluate(() => {
const m = document.body.innerText.match(/\/\s*(\d+)/);
return m ? parseInt(m[1], 10) : 1;
});
console.log(`Total pages: ${totalPages}`);
for (let i = 1; i <= totalPages; i++) {
await page.goto(`file://${PDF}#page=${i}&zoom=100`, { waitUntil: "networkidle2" });
await new Promise((r) => setTimeout(r, 600));
await page.screenshot({ path: join(OUT_DIR, `diag-page-${String(i).padStart(2, "0")}.png`) });
console.log(` ✓ page ${i}`);
}
await browser.close();