pdf page spliting done

This commit is contained in:
suryac 2026-08-10 13:35:00 +05:30
parent e528f63236
commit 3f12e80f38

View File

@ -45,95 +45,143 @@ export function DailySalesReportPage() {
fetchSOs();
}, []);
const downloadPDF = () => {
const generatePdfDoc = () => {
const doc = new jsPDF({ orientation: 'landscape' });
const pageWidth = doc.internal.pageSize.getWidth();
const centerX = pageWidth / 2;
const rightX = pageWidth - 14;
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' });
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);
// 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}`, rightX, 40, { align: 'right' });
const selectedSo = soOptions.find(o => o.value === soEmail);
doc.text(`SO Name : ${selectedSo ? selectedSo.label : soEmail}`, rightX, 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',
styles: { fontSize: 8, textColor: [0, 0, 0], lineColor: [0, 0, 0], lineWidth: 0.2 },
headStyles: { fillColor: [243, 244, 246], fontStyle: 'bold', halign: 'center' },
columnStyles: {
0: { cellWidth: 12 }
},
// 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) => {
const val = row.products?.[sku];
rowData.push(val === '0' || val === 0 ? '' : val || '');
});
if (isLastChunk) {
const val = row.total;
rowData.push(val === '0' || val === 0 ? '' : val || '');
}
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) => {
const val = reportData.response.total_row.products?.[sku];
totalRowData.push(val === '0' || val === 0 ? '' : val || '');
});
if (isLastChunk) {
const val = reportData.response.total_row.total;
totalRowData.push(val === '0' || val === 0 ? '' : val || '');
}
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({ orientation: 'landscape' });
const pageWidth = doc.internal.pageSize.getWidth();
const centerX = pageWidth / 2;
const rightX = 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}`, rightX, 40, { align: 'right' });
const selectedSo = soOptions.find(o => o.value === soEmail);
doc.text(`SO Name : ${selectedSo ? selectedSo.label : soEmail}`, rightX, 45, { align: 'right' });
// Table
autoTable(doc, {
html: '#report-table',
startY: 50,
theme: 'grid',
styles: { fontSize: 8, textColor: [0, 0, 0], lineColor: [0, 0, 0], lineWidth: 0.2 },
headStyles: { fillColor: [243, 244, 246], fontStyle: 'bold', halign: 'center' },
columnStyles: {
0: { cellWidth: 12 }
},
});
const doc = generatePdfDoc();
const blob = doc.output('blob');
// Fallback for PC / unsupported browsers
@ -275,10 +323,10 @@ export function DailySalesReportPage() {
<td className="py-2 px-3 text-strong whitespace-nowrap">{row.store}</td>
{reportData.response.headers?.flatMap((h: any) => h.skus || []).map((sku: string, idx: number) => (
<td key={`${sku}-${idx}`} className="py-2 px-3 text-strong text-center border-l border-black">
{row.products?.[sku] || ''}
{row.products?.[sku] === '0' || row.products?.[sku] === 0 ? '' : row.products?.[sku] || ''}
</td>
))}
<td className="py-2 px-3 text-strong font-bold text-center border-l border-black bg-black/5">{row.total || ''}</td>
<td className="py-2 px-3 text-strong font-bold text-center border-l border-black bg-black/5">{row.total === '0' || row.total === 0 ? '' : row.total || ''}</td>
</tr>
))}
{reportData.response.total_row && (
@ -287,10 +335,10 @@ export function DailySalesReportPage() {
<td className="py-2 px-3 text-strong whitespace-nowrap text-right">{reportData.response.total_row.store}</td>
{reportData.response.headers?.flatMap((h: any) => h.skus || []).map((sku: string, idx: number) => (
<td key={`total-${sku}-${idx}`} className="py-2 px-3 text-strong text-center border-l border-black">
{reportData.response.total_row.products?.[sku] || ''}
{reportData.response.total_row.products?.[sku] === '0' || reportData.response.total_row.products?.[sku] === 0 ? '' : reportData.response.total_row.products?.[sku] || ''}
</td>
))}
<td className="py-2 px-3 text-strong text-center border-l border-black">{reportData.response.total_row.total || ''}</td>
<td className="py-2 px-3 text-strong text-center border-l border-black">{reportData.response.total_row.total === '0' || reportData.response.total_row.total === 0 ? '' : reportData.response.total_row.total || ''}</td>
</tr>
)}
</tbody>