fix(pdf): Überweisungs-QR-Code überdeckt keine Positionen und Summen mehr
All checks were successful
Build and Release FEDEO / verify (push) Successful in 1m1s
Build and Release FEDEO / build-and-release (push) Successful in 6m19s

Reichen Positionen oder Summen auf der letzten Seite in den Bereich des QR-Codes, wird er auf einer eigenen Folgeseite gedruckt. Die MCP-Vorschau meldet das und schlägt einen früheren Seitenumbruch vor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-28 08:37:36 +01:00
parent 544d607088
commit 6ae8b7ad9e
3 changed files with 69 additions and 18 deletions

View File

@@ -163,8 +163,14 @@ export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoi
- paymentQrLayout.sizeMm * mm
}
// Top edge (mm from the top) of the QR label at its fixed bottom-right spot.
const getPaymentQrTopMm = (page: any) => page.getHeight() / mm
- (paymentQrLayout.bottomMarginMm + paymentQrLayout.sizeMm + paymentQrLayout.labelGapMm) - 8 / mm
// Set once the amounts are placed: the QR moves to its own page if it would cover them.
let paymentQrOnNewPage = false
const getTextWidthBeforePaymentQr = (page: any, startX: number) => {
if (!paymentQrCode) return 500
if (!paymentQrCode || paymentQrOnNewPage) return 500
return Math.max(
240,
@@ -902,6 +908,8 @@ export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoi
let endTextDiff = 35
const layoutContentEnd = rowHeight
// Visible bottom of the last row (rowHeight is the next baseline); totals extend it below.
let amountsBottomMm = rowHeight - 3
if (!deliveryNoteLikeDocumentTypes.includes(invoiceData.type)) {
pages[pageCounter - 1].drawLine({
@@ -1016,6 +1024,11 @@ export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoi
}
// Totals are baselines 8 mm apart; tax notes (13b/19/12.3) add one more line below.
const totalLines = invoiceData.totalArray.length + (["13b UStG", "19 UStG", "12.3 UStG"].includes(invoiceData.taxType) ? 1 : 0)
amountsBottomMm = rowHeight + (totalLines - 1) * 8 + 1
paymentQrOnNewPage = Boolean(paymentQrCode) && amountsBottomMm + 2 > getPaymentQrTopMm(pages[pageCounter - 1])
const endTextPosition = getCoordinatesForPDFLib(21, rowHeight + endTextDiff + (invoiceData.totalArray.length - 3) * 8, page1)
if (layout) {
@@ -1023,9 +1036,7 @@ export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoi
const lines = String(invoiceData.endText || "").split("\n")
.reduce((sum, line) => sum + Math.max(1, Math.ceil(font.widthOfTextAtSize(line, 10) / maxWidth)), 0)
const topMm = rowHeight + endTextDiff + (invoiceData.totalArray.length - 3) * 8
// Totals are baselines 8 mm apart; tax notes (13b/19/12.3) add one more line below.
const totalLines = invoiceData.totalArray.length + (["13b UStG", "19 UStG", "12.3 UStG"].includes(invoiceData.taxType) ? 1 : 0)
layout.totals = { page: pageCounter, topMm: layoutContentEnd, bottomMm: rowHeight + (totalLines - 1) * 8 + 1 }
layout.totals = { page: pageCounter, topMm: layoutContentEnd, bottomMm: amountsBottomMm }
// drawText places the baseline of the first line; 10 pt line height ≈ 3.53 mm.
layout.endText = { page: pageCounter, topMm: topMm - 3.53, bottomMm: topMm + (lines - 1) * 3.53 + 1 }
}
@@ -1041,6 +1052,16 @@ export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoi
}
if (paymentQrCode) {
// Invoice-like documents decide this before placing the end text.
if (deliveryNoteLikeDocumentTypes.includes(invoiceData.type)) {
paymentQrOnNewPage = amountsBottomMm + 2 > getPaymentQrTopMm(pages[pages.length - 1])
}
if (paymentQrOnNewPage) {
// Positions or totals reach the QR area; never draw the code over amounts.
const qrPage = pdfDoc.addPage()
qrPage.drawPage(secondPageBackground, { x: 0, y: 0 })
pages.push(qrPage)
}
const lastPage = pages[pages.length - 1]
const qrSize = paymentQrLayout.sizeMm * mm
const bottomMargin = paymentQrLayout.bottomMarginMm * mm