From 1235d851ab69d58580b6cc2b013c9a19dcefb941 Mon Sep 17 00:00:00 2001 From: suryac Date: Mon, 10 Aug 2026 13:28:21 +0530 Subject: [PATCH] pdf page split done --- src/screens/DailySalesReportPage.tsx | 196 +++++++++++++++++---------- 1 file changed, 121 insertions(+), 75 deletions(-) diff --git a/src/screens/DailySalesReportPage.tsx b/src/screens/DailySalesReportPage.tsx index 57773ad..28e0f2b 100644 --- a/src/screens/DailySalesReportPage.tsx +++ b/src/screens/DailySalesReportPage.tsx @@ -46,93 +46,139 @@ export function DailySalesReportPage() { fetchSOs(); }, []); - const downloadPDF = () => { + const generatePdfDoc = () => { const doc = new jsPDF('landscape'); const pageWidth = doc.internal.pageSize.getWidth(); const centerX = pageWidth / 2; const rightMargin = pageWidth - 14; - // Headers - doc.setFontSize(16); - doc.setFont('helvetica', 'bold'); - doc.text('Krishna Flour Mills (Bangalore) Pvt. Limited', centerX, 15, { align: 'center' }); + const drawPageHeader = () => { + // Headers + doc.setFontSize(16); + doc.setFont('helvetica', 'bold'); + doc.text('Krishna Flour Mills (Bangalore) Pvt. Limited', centerX, 15, { align: 'center' }); - doc.setFontSize(11); - doc.setFont('helvetica', 'normal'); - doc.text('19, Platform Road, Bengaluru - 560 020', centerX, 22, { align: 'center' }); + doc.setFontSize(11); + doc.setFont('helvetica', 'normal'); + doc.text('19, Platform Road, Bengaluru - 560 020', centerX, 22, { align: 'center' }); - doc.setFontSize(12); - doc.setFont('helvetica', 'bold'); - doc.text('DAILY ORDER REPORT', centerX, 30, { align: 'center' }); - - // Simple underline for DAILY ORDER REPORT - const textWidth = doc.getTextWidth('DAILY ORDER REPORT'); - doc.setLineWidth(0.5); - doc.line(centerX - textWidth / 2, 31, centerX + textWidth / 2, 31); + doc.setFontSize(12); + doc.setFont('helvetica', 'bold'); + doc.text('DAILY ORDER REPORT', centerX, 30, { align: 'center' }); + + // Simple underline for DAILY ORDER REPORT + const textWidth = doc.getTextWidth('DAILY ORDER REPORT'); + doc.setLineWidth(0.5); + doc.line(centerX - textWidth / 2, 31, centerX + textWidth / 2, 31); - // Meta Info - doc.setFontSize(10); - doc.text(`Distributor Name : ${distributor}`, 14, 40); - doc.text(`Date : ${date}`, rightMargin, 40, { align: 'right' }); - const selectedSo = soOptions.find(o => o.value === soEmail); - doc.text(`SO Name : ${selectedSo ? selectedSo.label : soEmail}`, rightMargin, 45, { align: 'right' }); + // Meta Info + doc.setFontSize(10); + doc.text(`Distributor Name : ${distributor}`, 14, 40); + doc.text(`Date : ${date}`, rightMargin, 40, { align: 'right' }); + const selectedSo = soOptions.find(o => o.value === soEmail); + doc.text(`SO Name : ${selectedSo ? selectedSo.label : soEmail}`, rightMargin, 45, { align: 'right' }); + }; - // Table - autoTable(doc, { - html: '#report-table', - startY: 50, - theme: 'grid', - horizontalPageBreak: true, - horizontalPageBreakRepeat: 0, - styles: { fontSize: 6, textColor: [0, 0, 0], lineColor: [0, 0, 0], lineWidth: 0.2, cellPadding: 1, minCellWidth: 10 }, - headStyles: { fillColor: [243, 244, 246], fontStyle: 'bold', halign: 'center' }, + // Split headers into chunks to avoid jspdf-autotable's horizontal page break bugs + // This allows us to keep the 2-tier header perfectly intact and break at heading boundaries. + const MAX_SKUS_PER_CHUNK = 14; + const headerChunks: any[][] = []; + let currentChunk: any[] = []; + let currentSkuCount = 0; + + reportData?.response?.headers?.forEach((h: any) => { + const skus = h.skus || []; + if (currentSkuCount + skus.length > MAX_SKUS_PER_CHUNK && currentSkuCount > 0) { + headerChunks.push(currentChunk); + currentChunk = []; + currentSkuCount = 0; + } + currentChunk.push(h); + currentSkuCount += skus.length; + }); + if (currentChunk.length > 0) { + headerChunks.push(currentChunk); + } + + if (headerChunks.length === 0) { + drawPageHeader(); // Fallback if no data + } + + headerChunks.forEach((chunkHeaders, index) => { + if (index === 0) { + drawPageHeader(); + } else { + doc.addPage(); + drawPageHeader(); + } + + const headRow1: any[] = [ + { content: 'Sl No', rowSpan: 2, styles: { halign: 'center', valign: 'middle' } }, + { content: 'Store', rowSpan: 2, styles: { halign: 'center', valign: 'middle' } } + ]; + const headRow2: any[] = []; + + chunkHeaders.forEach((h: any) => { + headRow1.push({ content: h.br_code, colSpan: h.skus?.length || 1, styles: { halign: 'center' } }); + h.skus?.forEach((sku: string) => { + headRow2.push({ content: sku, styles: { halign: 'center' } }); + }); + }); + + const isLastChunk = index === headerChunks.length - 1; + if (isLastChunk) { + headRow1.push({ content: 'Total', rowSpan: 2, styles: { halign: 'center', valign: 'middle' } }); + } + + const body = reportData?.response?.rows?.map((row: any) => { + const rowData = [row.sl_no, row.store]; + chunkHeaders.flatMap((h: any) => h.skus || []).forEach((sku: string) => { + rowData.push(row.products?.[sku] ?? 0); + }); + if (isLastChunk) { + rowData.push(row.total ?? 0); + } + return rowData; + }) || []; + + if (reportData?.response?.total_row) { + const totalRowData = [reportData.response.total_row.sl_no, reportData.response.total_row.store]; + chunkHeaders.flatMap((h: any) => h.skus || []).forEach((sku: string) => { + totalRowData.push(reportData.response.total_row.products?.[sku] ?? 0); + }); + if (isLastChunk) { + totalRowData.push(reportData.response.total_row.total ?? 0); + } + body.push(totalRowData); + } + + autoTable(doc, { + head: [headRow1, headRow2], + body: body, + startY: 50, + theme: 'grid', + horizontalPageBreak: false, + styles: { fontSize: 6, textColor: [0, 0, 0], lineColor: [0, 0, 0], lineWidth: 0.2, cellPadding: 1, minCellWidth: 10 }, + headStyles: { fillColor: [243, 244, 246], fontStyle: 'bold', halign: 'center' }, + didParseCell: (data) => { + if (data.section === 'body' && reportData?.response?.total_row && data.row.index === body.length - 1) { + data.cell.styles.fontStyle = 'bold'; + data.cell.styles.fillColor = [230, 230, 230]; + } + } + }); }); + return doc; + }; + + const downloadPDF = () => { + const doc = generatePdfDoc(); doc.save(`Daily_Sales_Report_${date || 'Draft'}.pdf`); }; const printReport = async () => { - const doc = new jsPDF('landscape'); - const pageWidth = doc.internal.pageSize.getWidth(); - const centerX = pageWidth / 2; - const rightMargin = pageWidth - 14; - - // Headers - doc.setFontSize(16); - doc.setFont('helvetica', 'bold'); - doc.text('Krishna Flour Mills (Bangalore) Pvt. Limited', centerX, 15, { align: 'center' }); - - doc.setFontSize(11); - doc.setFont('helvetica', 'normal'); - doc.text('19, Platform Road, Bengaluru - 560 020', centerX, 22, { align: 'center' }); - - doc.setFontSize(12); - doc.setFont('helvetica', 'bold'); - doc.text('DAILY ORDER REPORT', centerX, 30, { align: 'center' }); - - // Simple underline for DAILY ORDER REPORT - const textWidth = doc.getTextWidth('DAILY ORDER REPORT'); - doc.setLineWidth(0.5); - doc.line(centerX - textWidth / 2, 31, centerX + textWidth / 2, 31); - - // Meta Info - doc.setFontSize(10); - doc.text(`Distributor Name : ${distributor}`, 14, 40); - doc.text(`Date : ${date}`, rightMargin, 40, { align: 'right' }); - const selectedSo = soOptions.find(o => o.value === soEmail); - doc.text(`SO Name : ${selectedSo ? selectedSo.label : soEmail}`, rightMargin, 45, { align: 'right' }); - - // Table - autoTable(doc, { - html: '#report-table', - startY: 50, - theme: 'grid', - horizontalPageBreak: true, - horizontalPageBreakRepeat: 0, - styles: { fontSize: 6, textColor: [0, 0, 0], lineColor: [0, 0, 0], lineWidth: 0.2, cellPadding: 1, minCellWidth: 10 }, - headStyles: { fillColor: [243, 244, 246], fontStyle: 'bold', halign: 'center' }, - }); - + const doc = generatePdfDoc(); const blob = doc.output('blob'); // Attempt mobile native share (which includes OS-level Print) @@ -259,7 +305,7 @@ export function DailySalesReportPage() { - + {reportData.response.headers?.map((h: any) => ( {reportData.response.rows?.map((row: any) => ( - + {reportData.response.headers?.flatMap((h: any) => h.skus || []).map((sku: string, idx: number) => ( - + {reportData.response.headers?.flatMap((h: any) => h.skus || []).map((sku: string, idx: number) => (
Sl NoSl No Store @@ -279,7 +325,7 @@ export function DailySalesReportPage() {
{row.sl_no}{row.sl_no} {row.store} @@ -291,7 +337,7 @@ export function DailySalesReportPage() { ))} {reportData.response.total_row && (
{reportData.response.total_row.sl_no}{reportData.response.total_row.sl_no} {reportData.response.total_row.store}