diff --git a/backend/src/utils/pdf.ts b/backend/src/utils/pdf.ts index 61588a1..18fba50 100644 --- a/backend/src/utils/pdf.ts +++ b/backend/src/utils/pdf.ts @@ -128,6 +128,15 @@ export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoi const fontBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold) const paymentQrCodeBuffer = await getPaymentQrCodeBuffer(invoiceData) const paymentQrCode = paymentQrCodeBuffer ? await pdfDoc.embedPng(paymentQrCodeBuffer) : null + const mm = 2.83 + const paymentQrLayout = { + sizeMm: 32, + rightMarginMm: 20, + bottomMarginMm: 40, + labelGapMm: 5, + labelHeightMm: 4, + safeGapMm: 5, + } let pages = [] let pageCounter = 1 @@ -139,6 +148,85 @@ export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoi const firstPageBackground = await pdfDoc.embedPage(backgroudPdf.getPages()[0]) const secondPageBackground = await pdfDoc.embedPage(backgroudPdf.getPages()[backgroudPdf.getPages().length > 1 ? 1 : 0]) + const drawFoldMarks = (page: any, lengthMm: number) => { + page.drawLine({ + start: getCoordinatesForPDFLib(0, 105, page), + end: getCoordinatesForPDFLib(lengthMm, 105, page), + thickness: 0.25, + color: rgb(0, 0, 0), + opacity: 1 + }) + + page.drawLine({ + start: getCoordinatesForPDFLib(0, 148.5, page), + end: getCoordinatesForPDFLib(lengthMm, 148.5, page), + thickness: 0.25, + color: rgb(0, 0, 0), + opacity: 1 + }) + + page.drawLine({ + start: getCoordinatesForPDFLib(0, 210, page), + end: getCoordinatesForPDFLib(lengthMm, 210, page), + thickness: 0.25, + color: rgb(0, 0, 0), + opacity: 1 + }) + } + + const addFinalContinuationPage = () => { + const page = pdfDoc.addPage() + + page.drawPage(secondPageBackground, { + x: 0, + y: 0, + }) + + drawFoldMarks(page, 7) + + pageCounter += 1 + pageIndex = 0 + pages.push(page) + + return page + } + + const getPaymentQrReservedTopMm = (page: any) => { + return page.getHeight() / mm + - paymentQrLayout.bottomMarginMm + - paymentQrLayout.sizeMm + - paymentQrLayout.labelGapMm + - paymentQrLayout.labelHeightMm + - paymentQrLayout.safeGapMm + } + + const getTextLineCount = (text: any, maxSplitLength: number) => { + return String(text || "") + .split(/\r?\n/) + .reduce((sum, line) => sum + Math.max(1, splitStringBySpace(line, maxSplitLength).length), 0) + } + + const getFinalBlockEndMm = (startRowHeight: number) => { + let estimatedRowHeight = startRowHeight + 6 + const titleSumKeys = Object.keys(invoiceData.total.titleSums || {}) + + titleSumKeys.forEach((key) => { + estimatedRowHeight += splitStringBySpace(key, 60).length * 5 + }) + + if (titleSumKeys.length > 0) estimatedRowHeight += 5 + + const totalArrayLength = invoiceData.totalArray.length + const totalArrayBottom = estimatedRowHeight + Math.max(0, totalArrayLength - 1) * 8 + 6 + const taxNoteBottom = ["13b UStG", "19 UStG", "12.3 UStG"].includes(invoiceData.taxType) + ? estimatedRowHeight + totalArrayLength * 8 + 6 + : estimatedRowHeight + const endTextTop = estimatedRowHeight + endTextDiff + (totalArrayLength - 3) * 8 + const endTextBottom = endTextTop + getTextLineCount(invoiceData.endText, 85) * 5 + + return Math.max(totalArrayBottom, taxNoteBottom, endTextBottom) + } + // const page1 = pdfDoc.addPage() @@ -862,6 +950,11 @@ export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoi let endTextDiff = 35 if (!deliveryNoteLikeDocumentTypes.includes(invoiceData.type)) { + if (paymentQrCode && getFinalBlockEndMm(rowHeight) > getPaymentQrReservedTopMm(pages[pageCounter - 1])) { + addFinalContinuationPage() + rowHeight = 30 + } + pages[pageCounter - 1].drawLine({ start: getCoordinatesForPDFLib(20, rowHeight, page1), end: getCoordinatesForPDFLib(198, rowHeight, page1), @@ -987,11 +1080,10 @@ export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoi if (paymentQrCode) { const lastPage = pages[pages.length - 1] - const mm = 2.83 - const qrSize = 32 * mm - const rightMargin = 20 * mm - const bottomMargin = 40 * mm - const labelGap = 5 * mm + const qrSize = paymentQrLayout.sizeMm * mm + const rightMargin = paymentQrLayout.rightMarginMm * mm + const bottomMargin = paymentQrLayout.bottomMarginMm * mm + const labelGap = paymentQrLayout.labelGapMm * mm const qrX = lastPage.getWidth() - rightMargin - qrSize const qrY = bottomMargin