pdf page split done
This commit is contained in:
parent
3d79125127
commit
1235d851ab
@ -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' });
|
||||
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}`, 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() {
|
||||
<table id="report-table" className="w-full text-sm text-left border border-black border-collapse mt-2">
|
||||
<thead>
|
||||
<tr className="border-b border-black bg-black/5">
|
||||
<th className="py-2 px-3 font-bold text-black align-bottom border-r border-black" rowSpan={2}>Sl No</th>
|
||||
<th className="py-2 px-3 font-bold text-black align-bottom border-r border-black whitespace-nowrap" rowSpan={2}>Sl No</th>
|
||||
<th className="py-2 px-3 font-bold text-black align-bottom" rowSpan={2}>Store</th>
|
||||
{reportData.response.headers?.map((h: any) => (
|
||||
<th key={h.br_code} colSpan={h.skus?.length || 1} className="py-1 px-3 font-bold text-black text-center border-l border-black">
|
||||
@ -279,7 +325,7 @@ export function DailySalesReportPage() {
|
||||
<tbody>
|
||||
{reportData.response.rows?.map((row: any) => (
|
||||
<tr key={row.sl_no} className="border-b border-black hover:bg-black/5 transition-colors">
|
||||
<td className="py-2 px-3 text-strong border-r border-black">{row.sl_no}</td>
|
||||
<td className="py-2 px-3 text-strong border-r border-black whitespace-nowrap">{row.sl_no}</td>
|
||||
<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">
|
||||
@ -291,7 +337,7 @@ export function DailySalesReportPage() {
|
||||
))}
|
||||
{reportData.response.total_row && (
|
||||
<tr className="border-b border-black bg-black/10 font-bold">
|
||||
<td className="py-2 px-3 text-strong border-r border-black">{reportData.response.total_row.sl_no}</td>
|
||||
<td className="py-2 px-3 text-strong border-r border-black whitespace-nowrap">{reportData.response.total_row.sl_no}</td>
|
||||
<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">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user