Spaces:
Sleeping
Sleeping
Update utils/LedgerPdfGenerator.ts
Browse files- utils/LedgerPdfGenerator.ts +239 -239
utils/LedgerPdfGenerator.ts
CHANGED
|
@@ -1,240 +1,240 @@
|
|
| 1 |
-
import jsPDF from 'jspdf';
|
| 2 |
-
import autoTable from 'jspdf-autotable';
|
| 3 |
-
import { Party, Transaction } from '../types';
|
| 4 |
-
|
| 5 |
-
// --- CONFIGURATION ---
|
| 6 |
-
const BG_COLOR: [number, number, number] = [240, 234, 214]; // Beige
|
| 7 |
-
const BORDER_COLOR: [number, number, number] = [0, 0, 0]; // Black
|
| 8 |
-
|
| 9 |
-
// Helper: Currency Format
|
| 10 |
-
const FORMAT_CURRENCY = (amount: number) => {
|
| 11 |
-
return new Intl.NumberFormat('en-IN', {
|
| 12 |
-
minimumFractionDigits: 2,
|
| 13 |
-
maximumFractionDigits: 2
|
| 14 |
-
}).format(amount);
|
| 15 |
-
};
|
| 16 |
-
|
| 17 |
-
// Helper: Date Format
|
| 18 |
-
const FORMAT_DATE = (dateStr: string) => {
|
| 19 |
-
if (!dateStr) return "";
|
| 20 |
-
const dateObj = new Date(dateStr);
|
| 21 |
-
return `${dateObj.getDate().toString().padStart(2, '0')}/${(dateObj.getMonth() + 1).toString().padStart(2, '0')}/${dateObj.getFullYear().toString().slice(-2)}`;
|
| 22 |
-
};
|
| 23 |
-
|
| 24 |
-
export const generateLedgerPDF = (party: Party, transactions: Transaction[]) => {
|
| 25 |
-
const doc = new jsPDF();
|
| 26 |
-
|
| 27 |
-
// --- 1. PAGE CONFIGURATION ---
|
| 28 |
-
const PAGE_WIDTH = 210;
|
| 29 |
-
const PAGE_HEIGHT = 297;
|
| 30 |
-
const MARGIN = 14;
|
| 31 |
-
const CONTENT_WIDTH = PAGE_WIDTH - (MARGIN * 2);
|
| 32 |
-
|
| 33 |
-
// --- 2. SETUP & BACKGROUND ---
|
| 34 |
-
doc.setFillColor(...BG_COLOR);
|
| 35 |
-
doc.rect(0, 0, PAGE_WIDTH, PAGE_HEIGHT, 'F');
|
| 36 |
-
|
| 37 |
-
// --- 3. DATA PREPARATION ---
|
| 38 |
-
const sortedTxs = [...transactions].sort((a, b) =>
|
| 39 |
-
new Date(a.bill_date).getTime() - new Date(b.bill_date).getTime()
|
| 40 |
-
);
|
| 41 |
-
|
| 42 |
-
let runningBalance = 0;
|
| 43 |
-
|
| 44 |
-
const tableRows = sortedTxs.flatMap(tx => {
|
| 45 |
-
const rows = [];
|
| 46 |
-
const dateStr = FORMAT_DATE(tx.bill_date);
|
| 47 |
-
|
| 48 |
-
// --- DETERMINE TYPE (AWAAK vs JAWAAK) ---
|
| 49 |
-
// AWAAK = Purchase (We Owe - Credit)
|
| 50 |
-
// JAWAAK = Sales (They Owe - Debit)
|
| 51 |
-
const typeStr = String(tx.bill_type).toUpperCase();
|
| 52 |
-
const numStr = tx.bill_number ? tx.bill_number.toUpperCase() : "";
|
| 53 |
-
|
| 54 |
-
const isAwaak = typeStr === 'AWAAK' || numStr.includes('AWAAK');
|
| 55 |
-
|
| 56 |
-
// --- A. BILL ROW ---
|
| 57 |
-
// 1. Particulars Construction
|
| 58 |
-
let itemDetails = "";
|
| 59 |
-
if (tx.items && tx.items.length > 0) {
|
| 60 |
-
tx.items.forEach(item => {
|
| 61 |
-
let wStr = "";
|
| 62 |
-
if (Array.isArray(item.poti_weights)) wStr = item.poti_weights.join(",");
|
| 63 |
-
else if (item.poti_weights) wStr = String(item.poti_weights);
|
| 64 |
-
|
| 65 |
-
const prefix = itemDetails ? "\n" : "";
|
| 66 |
-
itemDetails += `${prefix}${item.mirchi_name}`;
|
| 67 |
-
if (wStr) itemDetails += ` (${wStr})`;
|
| 68 |
-
});
|
| 69 |
-
}
|
| 70 |
-
|
| 71 |
-
let billParticulars = `
|
| 72 |
-
if (tx.is_return) billParticulars += " (RETURN)";
|
| 73 |
-
if (itemDetails) billParticulars += `\n${itemDetails}`;
|
| 74 |
-
|
| 75 |
-
let totalPoti = 0;
|
| 76 |
-
tx.items?.forEach(i => totalPoti += Number(i.poti_count) || 0);
|
| 77 |
-
|
| 78 |
-
// 2. FINANCIAL LOGIC (THE FIX)
|
| 79 |
-
let billDebit = 0;
|
| 80 |
-
let billCredit = 0;
|
| 81 |
-
|
| 82 |
-
if (isAwaak) {
|
| 83 |
-
// AWAAK (Purchase):
|
| 84 |
-
// - Normal Bill: CREDIT (Liability increases)
|
| 85 |
-
// - Return Bill: DEBIT (Liability decreases)
|
| 86 |
-
if (tx.is_return) billDebit = tx.total_amount;
|
| 87 |
-
else billCredit = tx.total_amount;
|
| 88 |
-
} else {
|
| 89 |
-
// JAWAAK (Sales):
|
| 90 |
-
// - Normal Bill: DEBIT (Asset increases - They owe us)
|
| 91 |
-
// - Return Bill: CREDIT (Asset decreases)
|
| 92 |
-
if (tx.is_return) billCredit = tx.total_amount;
|
| 93 |
-
else billDebit = tx.total_amount;
|
| 94 |
-
}
|
| 95 |
-
|
| 96 |
-
// Running Balance = Old + Debit - Credit
|
| 97 |
-
runningBalance = runningBalance + billDebit - billCredit;
|
| 98 |
-
|
| 99 |
-
// Push Bill Row
|
| 100 |
-
rows.push({
|
| 101 |
-
date: dateStr,
|
| 102 |
-
particulars: billParticulars,
|
| 103 |
-
poti: totalPoti > 0 ? totalPoti.toString() : "-",
|
| 104 |
-
credit: billCredit > 0 ? FORMAT_CURRENCY(billCredit) : "-",
|
| 105 |
-
debit: billDebit > 0 ? FORMAT_CURRENCY(billDebit) : "-",
|
| 106 |
-
balance: `${FORMAT_CURRENCY(Math.abs(runningBalance))} ${runningBalance >= 0 ? 'Dr' : 'Cr'}`,
|
| 107 |
-
isMainRow: true
|
| 108 |
-
});
|
| 109 |
-
|
| 110 |
-
// --- B. PAYMENT ROWS ---
|
| 111 |
-
if (tx.payments && tx.payments.length > 0) {
|
| 112 |
-
const validPayments = tx.payments.filter(p => p.mode.toLowerCase() !== 'due');
|
| 113 |
-
|
| 114 |
-
validPayments.forEach(p => {
|
| 115 |
-
let payDebit = 0;
|
| 116 |
-
let payCredit = 0;
|
| 117 |
-
|
| 118 |
-
if (isAwaak) {
|
| 119 |
-
// AWAAK (Purchase) Payment:
|
| 120 |
-
// - We Pay Money: DEBIT (Liability decreases)
|
| 121 |
-
// - Refund (Return): CREDIT
|
| 122 |
-
if (tx.is_return) payCredit = p.amount;
|
| 123 |
-
else payDebit = p.amount;
|
| 124 |
-
} else {
|
| 125 |
-
// JAWAAK (Sales) Payment:
|
| 126 |
-
// - They Pay Money: CREDIT (Asset decreases - Debt paid off)
|
| 127 |
-
// - Refund (Return): DEBIT
|
| 128 |
-
if (tx.is_return) payDebit = p.amount;
|
| 129 |
-
else payCredit = p.amount;
|
| 130 |
-
}
|
| 131 |
-
|
| 132 |
-
runningBalance = runningBalance + payDebit - payCredit;
|
| 133 |
-
|
| 134 |
-
// Description
|
| 135 |
-
const modeStr = p.mode.charAt(0).toUpperCase() + p.mode.slice(1);
|
| 136 |
-
let payDesc = ` [${modeStr}]`;
|
| 137 |
-
if (p.reference) payDesc += ` ${p.reference}`;
|
| 138 |
-
|
| 139 |
-
rows.push({
|
| 140 |
-
date: dateStr,
|
| 141 |
-
particulars: payDesc,
|
| 142 |
-
poti: "-",
|
| 143 |
-
credit: payCredit > 0 ? FORMAT_CURRENCY(payCredit) : "-",
|
| 144 |
-
debit: payDebit > 0 ? FORMAT_CURRENCY(payDebit) : "-",
|
| 145 |
-
balance: `${FORMAT_CURRENCY(Math.abs(runningBalance))} ${runningBalance >= 0 ? 'Dr' : 'Cr'}`,
|
| 146 |
-
isMainRow: false
|
| 147 |
-
});
|
| 148 |
-
});
|
| 149 |
-
}
|
| 150 |
-
return rows;
|
| 151 |
-
});
|
| 152 |
-
|
| 153 |
-
// --- 4. GENERATE TABLE ---
|
| 154 |
-
autoTable(doc, {
|
| 155 |
-
startY: 35,
|
| 156 |
-
tableWidth: CONTENT_WIDTH,
|
| 157 |
-
margin: { left: MARGIN, right: MARGIN },
|
| 158 |
-
|
| 159 |
-
head: [[
|
| 160 |
-
'Date',
|
| 161 |
-
'Particulars',
|
| 162 |
-
'Poti',
|
| 163 |
-
'Credit\n(Jama)',
|
| 164 |
-
'Debit\n(Nave)',
|
| 165 |
-
'Balance'
|
| 166 |
-
]],
|
| 167 |
-
|
| 168 |
-
body: tableRows.map(r => [r.date, r.particulars, r.poti, r.credit, r.debit, r.balance]),
|
| 169 |
-
|
| 170 |
-
theme: 'grid',
|
| 171 |
-
|
| 172 |
-
styles: {
|
| 173 |
-
fillColor: false,
|
| 174 |
-
textColor: 0,
|
| 175 |
-
lineColor: 0,
|
| 176 |
-
lineWidth: 0.1,
|
| 177 |
-
font: 'helvetica',
|
| 178 |
-
fontSize: 9,
|
| 179 |
-
valign: 'top',
|
| 180 |
-
cellPadding: 3,
|
| 181 |
-
overflow: 'linebreak'
|
| 182 |
-
},
|
| 183 |
-
|
| 184 |
-
headStyles: {
|
| 185 |
-
fillColor: false,
|
| 186 |
-
textColor: 0,
|
| 187 |
-
fontStyle: 'bold',
|
| 188 |
-
halign: 'center',
|
| 189 |
-
valign: 'middle',
|
| 190 |
-
lineWidth: 0.1,
|
| 191 |
-
},
|
| 192 |
-
|
| 193 |
-
columnStyles: {
|
| 194 |
-
0: { cellWidth: 20, halign: 'center' }, // Date
|
| 195 |
-
1: { cellWidth: 72, halign: 'left' }, // Particulars
|
| 196 |
-
2: { cellWidth: 12, halign: 'center' }, // Poti
|
| 197 |
-
3: { cellWidth: 26, halign: 'right' }, // Credit
|
| 198 |
-
4: { cellWidth: 26, halign: 'right' }, // Debit
|
| 199 |
-
5: { cellWidth: 26, halign: 'right', fontStyle: 'bold' } // Balance
|
| 200 |
-
},
|
| 201 |
-
|
| 202 |
-
didParseCell: (data) => {
|
| 203 |
-
const rowIdx = data.row.index;
|
| 204 |
-
const rowData = tableRows[rowIdx];
|
| 205 |
-
if (data.section === 'body' && data.column.index === 1 && rowData?.isMainRow) {
|
| 206 |
-
data.cell.styles.fontStyle = 'bold';
|
| 207 |
-
}
|
| 208 |
-
},
|
| 209 |
-
|
| 210 |
-
didDrawPage: (data) => {
|
| 211 |
-
// Border
|
| 212 |
-
doc.setDrawColor(...BORDER_COLOR);
|
| 213 |
-
doc.setLineWidth(0.4);
|
| 214 |
-
doc.rect(MARGIN, MARGIN, CONTENT_WIDTH, PAGE_HEIGHT - (MARGIN * 2));
|
| 215 |
-
|
| 216 |
-
// Header
|
| 217 |
-
if (data.pageNumber === 1) {
|
| 218 |
-
const startX = MARGIN + 4;
|
| 219 |
-
const startY = 25;
|
| 220 |
-
|
| 221 |
-
doc.setFontSize(14);
|
| 222 |
-
doc.setFont("helvetica", "bold");
|
| 223 |
-
doc.text("Name of A/c :", startX, startY);
|
| 224 |
-
|
| 225 |
-
const labelWidth = doc.getTextWidth("Name of A/c : ");
|
| 226 |
-
doc.text(party.name, startX + labelWidth, startY);
|
| 227 |
-
|
| 228 |
-
if (party.city || party.phone) {
|
| 229 |
-
doc.setFontSize(9);
|
| 230 |
-
doc.setFont("helvetica", "normal");
|
| 231 |
-
const subText = [party.city, party.phone].filter(Boolean).join(" - ");
|
| 232 |
-
doc.text(subText, startX, startY + 6);
|
| 233 |
-
}
|
| 234 |
-
}
|
| 235 |
-
}
|
| 236 |
-
});
|
| 237 |
-
|
| 238 |
-
const cleanName = party.name.replace(/[^a-zA-Z0-9]/g, '_');
|
| 239 |
-
doc.save(`${cleanName}_Ledger.pdf`);
|
| 240 |
};
|
|
|
|
| 1 |
+
import jsPDF from 'jspdf';
|
| 2 |
+
import autoTable from 'jspdf-autotable';
|
| 3 |
+
import { Party, Transaction } from '../types';
|
| 4 |
+
|
| 5 |
+
// --- CONFIGURATION ---
|
| 6 |
+
const BG_COLOR: [number, number, number] = [240, 234, 214]; // Beige
|
| 7 |
+
const BORDER_COLOR: [number, number, number] = [0, 0, 0]; // Black
|
| 8 |
+
|
| 9 |
+
// Helper: Currency Format
|
| 10 |
+
const FORMAT_CURRENCY = (amount: number) => {
|
| 11 |
+
return new Intl.NumberFormat('en-IN', {
|
| 12 |
+
minimumFractionDigits: 2,
|
| 13 |
+
maximumFractionDigits: 2
|
| 14 |
+
}).format(amount);
|
| 15 |
+
};
|
| 16 |
+
|
| 17 |
+
// Helper: Date Format
|
| 18 |
+
const FORMAT_DATE = (dateStr: string) => {
|
| 19 |
+
if (!dateStr) return "";
|
| 20 |
+
const dateObj = new Date(dateStr);
|
| 21 |
+
return `${dateObj.getDate().toString().padStart(2, '0')}/${(dateObj.getMonth() + 1).toString().padStart(2, '0')}/${dateObj.getFullYear().toString().slice(-2)}`;
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
export const generateLedgerPDF = (party: Party, transactions: Transaction[]) => {
|
| 25 |
+
const doc = new jsPDF();
|
| 26 |
+
|
| 27 |
+
// --- 1. PAGE CONFIGURATION ---
|
| 28 |
+
const PAGE_WIDTH = 210;
|
| 29 |
+
const PAGE_HEIGHT = 297;
|
| 30 |
+
const MARGIN = 14;
|
| 31 |
+
const CONTENT_WIDTH = PAGE_WIDTH - (MARGIN * 2);
|
| 32 |
+
|
| 33 |
+
// --- 2. SETUP & BACKGROUND ---
|
| 34 |
+
doc.setFillColor(...BG_COLOR);
|
| 35 |
+
doc.rect(0, 0, PAGE_WIDTH, PAGE_HEIGHT, 'F');
|
| 36 |
+
|
| 37 |
+
// --- 3. DATA PREPARATION ---
|
| 38 |
+
const sortedTxs = [...transactions].sort((a, b) =>
|
| 39 |
+
new Date(a.bill_date).getTime() - new Date(b.bill_date).getTime()
|
| 40 |
+
);
|
| 41 |
+
|
| 42 |
+
let runningBalance = 0;
|
| 43 |
+
|
| 44 |
+
const tableRows = sortedTxs.flatMap(tx => {
|
| 45 |
+
const rows = [];
|
| 46 |
+
const dateStr = FORMAT_DATE(tx.bill_date);
|
| 47 |
+
|
| 48 |
+
// --- DETERMINE TYPE (AWAAK vs JAWAAK) ---
|
| 49 |
+
// AWAAK = Purchase (We Owe - Credit)
|
| 50 |
+
// JAWAAK = Sales (They Owe - Debit)
|
| 51 |
+
const typeStr = String(tx.bill_type).toUpperCase();
|
| 52 |
+
const numStr = tx.bill_number ? tx.bill_number.toUpperCase() : "";
|
| 53 |
+
|
| 54 |
+
const isAwaak = typeStr === 'AWAAK' || numStr.includes('AWAAK');
|
| 55 |
+
|
| 56 |
+
// --- A. BILL ROW ---
|
| 57 |
+
// 1. Particulars Construction
|
| 58 |
+
let itemDetails = "";
|
| 59 |
+
if (tx.items && tx.items.length > 0) {
|
| 60 |
+
tx.items.forEach(item => {
|
| 61 |
+
let wStr = "";
|
| 62 |
+
if (Array.isArray(item.poti_weights)) wStr = item.poti_weights.join(",");
|
| 63 |
+
else if (item.poti_weights) wStr = String(item.poti_weights);
|
| 64 |
+
|
| 65 |
+
const prefix = itemDetails ? "\n" : "";
|
| 66 |
+
itemDetails += `${prefix}${item.mirchi_name}`;
|
| 67 |
+
if (wStr) itemDetails += ` (${wStr})`;
|
| 68 |
+
});
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
let billParticulars = `No: ${tx.bill_number}`;
|
| 72 |
+
if (tx.is_return) billParticulars += " (RETURN)";
|
| 73 |
+
if (itemDetails) billParticulars += `\n${itemDetails}`;
|
| 74 |
+
|
| 75 |
+
let totalPoti = 0;
|
| 76 |
+
tx.items?.forEach(i => totalPoti += Number(i.poti_count) || 0);
|
| 77 |
+
|
| 78 |
+
// 2. FINANCIAL LOGIC (THE FIX)
|
| 79 |
+
let billDebit = 0;
|
| 80 |
+
let billCredit = 0;
|
| 81 |
+
|
| 82 |
+
if (isAwaak) {
|
| 83 |
+
// AWAAK (Purchase):
|
| 84 |
+
// - Normal Bill: CREDIT (Liability increases)
|
| 85 |
+
// - Return Bill: DEBIT (Liability decreases)
|
| 86 |
+
if (tx.is_return) billDebit = tx.total_amount;
|
| 87 |
+
else billCredit = tx.total_amount;
|
| 88 |
+
} else {
|
| 89 |
+
// JAWAAK (Sales):
|
| 90 |
+
// - Normal Bill: DEBIT (Asset increases - They owe us)
|
| 91 |
+
// - Return Bill: CREDIT (Asset decreases)
|
| 92 |
+
if (tx.is_return) billCredit = tx.total_amount;
|
| 93 |
+
else billDebit = tx.total_amount;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
// Running Balance = Old + Debit - Credit
|
| 97 |
+
runningBalance = runningBalance + billDebit - billCredit;
|
| 98 |
+
|
| 99 |
+
// Push Bill Row
|
| 100 |
+
rows.push({
|
| 101 |
+
date: dateStr,
|
| 102 |
+
particulars: billParticulars,
|
| 103 |
+
poti: totalPoti > 0 ? totalPoti.toString() : "-",
|
| 104 |
+
credit: billCredit > 0 ? FORMAT_CURRENCY(billCredit) : "-",
|
| 105 |
+
debit: billDebit > 0 ? FORMAT_CURRENCY(billDebit) : "-",
|
| 106 |
+
balance: `${FORMAT_CURRENCY(Math.abs(runningBalance))} ${runningBalance >= 0 ? 'Dr' : 'Cr'}`,
|
| 107 |
+
isMainRow: true
|
| 108 |
+
});
|
| 109 |
+
|
| 110 |
+
// --- B. PAYMENT ROWS ---
|
| 111 |
+
if (tx.payments && tx.payments.length > 0) {
|
| 112 |
+
const validPayments = tx.payments.filter(p => p.mode.toLowerCase() !== 'due');
|
| 113 |
+
|
| 114 |
+
validPayments.forEach(p => {
|
| 115 |
+
let payDebit = 0;
|
| 116 |
+
let payCredit = 0;
|
| 117 |
+
|
| 118 |
+
if (isAwaak) {
|
| 119 |
+
// AWAAK (Purchase) Payment:
|
| 120 |
+
// - We Pay Money: DEBIT (Liability decreases)
|
| 121 |
+
// - Refund (Return): CREDIT
|
| 122 |
+
if (tx.is_return) payCredit = p.amount;
|
| 123 |
+
else payDebit = p.amount;
|
| 124 |
+
} else {
|
| 125 |
+
// JAWAAK (Sales) Payment:
|
| 126 |
+
// - They Pay Money: CREDIT (Asset decreases - Debt paid off)
|
| 127 |
+
// - Refund (Return): DEBIT
|
| 128 |
+
if (tx.is_return) payDebit = p.amount;
|
| 129 |
+
else payCredit = p.amount;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
runningBalance = runningBalance + payDebit - payCredit;
|
| 133 |
+
|
| 134 |
+
// Description
|
| 135 |
+
const modeStr = p.mode.charAt(0).toUpperCase() + p.mode.slice(1);
|
| 136 |
+
let payDesc = ` [${modeStr}]`;
|
| 137 |
+
if (p.reference) payDesc += ` ${p.reference}`;
|
| 138 |
+
|
| 139 |
+
rows.push({
|
| 140 |
+
date: dateStr,
|
| 141 |
+
particulars: payDesc,
|
| 142 |
+
poti: "-",
|
| 143 |
+
credit: payCredit > 0 ? FORMAT_CURRENCY(payCredit) : "-",
|
| 144 |
+
debit: payDebit > 0 ? FORMAT_CURRENCY(payDebit) : "-",
|
| 145 |
+
balance: `${FORMAT_CURRENCY(Math.abs(runningBalance))} ${runningBalance >= 0 ? 'Dr' : 'Cr'}`,
|
| 146 |
+
isMainRow: false
|
| 147 |
+
});
|
| 148 |
+
});
|
| 149 |
+
}
|
| 150 |
+
return rows;
|
| 151 |
+
});
|
| 152 |
+
|
| 153 |
+
// --- 4. GENERATE TABLE ---
|
| 154 |
+
autoTable(doc, {
|
| 155 |
+
startY: 35,
|
| 156 |
+
tableWidth: CONTENT_WIDTH,
|
| 157 |
+
margin: { left: MARGIN, right: MARGIN },
|
| 158 |
+
|
| 159 |
+
head: [[
|
| 160 |
+
'Date',
|
| 161 |
+
'Particulars',
|
| 162 |
+
'Poti',
|
| 163 |
+
'Credit\n(Jama)',
|
| 164 |
+
'Debit\n(Nave)',
|
| 165 |
+
'Balance'
|
| 166 |
+
]],
|
| 167 |
+
|
| 168 |
+
body: tableRows.map(r => [r.date, r.particulars, r.poti, r.credit, r.debit, r.balance]),
|
| 169 |
+
|
| 170 |
+
theme: 'grid',
|
| 171 |
+
|
| 172 |
+
styles: {
|
| 173 |
+
fillColor: false,
|
| 174 |
+
textColor: 0,
|
| 175 |
+
lineColor: 0,
|
| 176 |
+
lineWidth: 0.1,
|
| 177 |
+
font: 'helvetica',
|
| 178 |
+
fontSize: 9,
|
| 179 |
+
valign: 'top',
|
| 180 |
+
cellPadding: 3,
|
| 181 |
+
overflow: 'linebreak'
|
| 182 |
+
},
|
| 183 |
+
|
| 184 |
+
headStyles: {
|
| 185 |
+
fillColor: false,
|
| 186 |
+
textColor: 0,
|
| 187 |
+
fontStyle: 'bold',
|
| 188 |
+
halign: 'center',
|
| 189 |
+
valign: 'middle',
|
| 190 |
+
lineWidth: 0.1,
|
| 191 |
+
},
|
| 192 |
+
|
| 193 |
+
columnStyles: {
|
| 194 |
+
0: { cellWidth: 20, halign: 'center' }, // Date
|
| 195 |
+
1: { cellWidth: 72, halign: 'left' }, // Particulars
|
| 196 |
+
2: { cellWidth: 12, halign: 'center' }, // Poti
|
| 197 |
+
3: { cellWidth: 26, halign: 'right' }, // Credit
|
| 198 |
+
4: { cellWidth: 26, halign: 'right' }, // Debit
|
| 199 |
+
5: { cellWidth: 26, halign: 'right', fontStyle: 'bold' } // Balance
|
| 200 |
+
},
|
| 201 |
+
|
| 202 |
+
didParseCell: (data) => {
|
| 203 |
+
const rowIdx = data.row.index;
|
| 204 |
+
const rowData = tableRows[rowIdx];
|
| 205 |
+
if (data.section === 'body' && data.column.index === 1 && rowData?.isMainRow) {
|
| 206 |
+
data.cell.styles.fontStyle = 'bold';
|
| 207 |
+
}
|
| 208 |
+
},
|
| 209 |
+
|
| 210 |
+
didDrawPage: (data) => {
|
| 211 |
+
// Border
|
| 212 |
+
doc.setDrawColor(...BORDER_COLOR);
|
| 213 |
+
doc.setLineWidth(0.4);
|
| 214 |
+
doc.rect(MARGIN, MARGIN, CONTENT_WIDTH, PAGE_HEIGHT - (MARGIN * 2));
|
| 215 |
+
|
| 216 |
+
// Header
|
| 217 |
+
if (data.pageNumber === 1) {
|
| 218 |
+
const startX = MARGIN + 4;
|
| 219 |
+
const startY = 25;
|
| 220 |
+
|
| 221 |
+
doc.setFontSize(14);
|
| 222 |
+
doc.setFont("helvetica", "bold");
|
| 223 |
+
doc.text("Name of A/c :", startX, startY);
|
| 224 |
+
|
| 225 |
+
const labelWidth = doc.getTextWidth("Name of A/c : ");
|
| 226 |
+
doc.text(party.name, startX + labelWidth, startY);
|
| 227 |
+
|
| 228 |
+
if (party.city || party.phone) {
|
| 229 |
+
doc.setFontSize(9);
|
| 230 |
+
doc.setFont("helvetica", "normal");
|
| 231 |
+
const subText = [party.city, party.phone].filter(Boolean).join(" - ");
|
| 232 |
+
doc.text(subText, startX, startY + 6);
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
}
|
| 236 |
+
});
|
| 237 |
+
|
| 238 |
+
const cleanName = party.name.replace(/[^a-zA-Z0-9]/g, '_');
|
| 239 |
+
doc.save(`${cleanName}_Ledger.pdf`);
|
| 240 |
};
|