form16 annexure2
function downloadForm16PDF(taxRegime = 'OLD') {
// 1. Safety Checks - Ensure jsPDF library is loaded
if (typeof window.jspdf === 'undefined') {
alert("jsPDF library is missing. Please ensure it is loaded.");
return;
}
const selectedRegime = (taxRegime || 'OLD').toUpperCase();
try {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'pt', 'a4');
// --- CONFIG ---
const PG_W = 595.28;
const PG_H = 841.89;
const LM = 25; // Left Margin
const RM = 570; // Right Margin
const CW = RM - LM; // Content Width
let y = 30; // Vertical Cursor
const ROW_H_M = 18; // Minimum Row Height
const SECTION_SPACING = 6; // extra spacing between sections
// --- HELPERS ---
const font = (style, size) => { doc.setFont("helvetica", style); doc.setFontSize(size); };
const safeNum = v => {
if (v === null || v === undefined || v === "") return 0;
const n = Number(String(v).replace(/,/g, ''));
return isNaN(n) ? 0 : Math.round(n);
};
const fmt = (n) => {
const v = safeNum(n);
return v === 0 ? "0" : v.toLocaleString('en-IN');
};
const txt = (str, x, yy, options = {}) => {
if (str === null || str === undefined) return;
doc.text(String(str), x, yy, options);
};
const right = (str, x, yy) => {
if (str === null || str === undefined) return;
doc.text(String(str), x, yy, { align: "right" });
};
const center = (str, yy) => {
if (str === null || str === undefined) return;
doc.text(String(str), PG_W / 2, yy, { align: "center" });
};
// --- LOAD APP DATA (window.latestStatement) ---
const S = window.latestStatement || {};
const _meta = S.meta || {};
const _totals = S.totals || {};
const _inputs = S.inputs || {};
const _adv = Array.isArray(S.advTax) ? S.advTax.map(v => safeNum(v)) : null;
// --- METADATA (fallbacks kept minimal) ---
const METADATA = {
nameEmp: _meta.employer || _meta.workplace || "" ,
nameDesig: _meta.employee || _meta.name || "",
panDed: _meta.panDed || _meta.panDeductor || "PANNOTREQD",
tanDed: _meta.tanNo || _meta.tan || _meta.tanDeductor || "",
panEmp: _meta.panno || _meta.panEmp || _meta.pan || "",
cit: _meta.cit || _meta.citTDS || "The Commissioner of Income Tax (TDS)\nRoom No. 411, Income Tax Towers, 10-2-3 A.C. Guard.",
fy: _meta.fy || "2025-26",
ay: _meta.ay || "2026-27",
periodFrom: _meta.periodFrom || "01/04/2025",
periodTo: _meta.periodTo || "31/03/2026",
footer: _meta.footer || "Designed By: K.SANYASI NAIDU, SGT, VISAKHAPATNAM",
date: _meta.date || _meta.generatedDate || "31/03/2026"
};
// --- DATA MAPPING: pick keys that your app uses (with fallbacks)
const mapped = {
gross: safeNum(_totals.totalGross || _totals.gross || _totals.totalPay || _inputs.gross || 0),
hraExemption: safeNum(_totals.hraExemption || _totals.hraEx || _inputs.hraExemption),
pt: safeNum(_totals.totalPtax || _totals.pt || _inputs.pt),
stdDed: safeNum(_totals.stdDeduction || _inputs.stdDeduction || _totals.stdDed || 50000),
s80c_gross: safeNum(_totals.sec80C_Allowed || _totals.S80C_TotalGross || _inputs.S80C_TotalGross || _totals.s80c),
s80c_ded: safeNum(_totals.sec80C_Allowed || _totals.S80C_Deductible || _inputs.S80C_Deductible || _totals.s80c),
s13_ewf_gross: safeNum(_totals.S13_EWF_Gross || _inputs.S13_EWF_Gross || _totals.EWF),
s13_80d_gross: safeNum(_totals.S13_80D_Gross || _inputs.S13_80D_Gross || _totals.S13_80D),
s13_ewf_ded: safeNum(_totals.S13_EWF_Deductible || _inputs.S13_EWF_Deductible || _totals.EWF_Ded),
s13_80d_ded: safeNum(_totals.S13_80D_Deductible || _inputs.S13_80D_Deductible || _totals.S13_80D_Ded),
oldTaxOnIncome: safeNum(_totals.oldTax || _totals.taxOnIncomeOld || _totals.taxOnIncome || 0),
newTaxOnIncome: safeNum(_totals.newTax || _totals.taxOnIncomeNew || _totals.taxOnIncome || 0),
totalTDS: safeNum(_totals.totalTDS || _totals.totalAdvTax || _totals.totalTaxDeducted || 0),
totalPaid: safeNum(_totals.totalPay || _totals.gross || _inputs.gross || 0)
};
// --- Regime rules: enforce zeroing where necessary ---
let DATA = null;
if (selectedRegime === 'NEW') {
DATA = {
slabLabel: "NEW IT SLAB",
gross: mapped.gross,
hraExemption: 0,
pt: 0,
standardDeduction: mapped.stdDed || 75000,
S80C_TotalGross: 0,
S80C_Deductible: 0,
S13_EWF_Gross: 0,
S13_80D_Gross: 0,
S13_EWF_Deductible: 0,
S13_80D_Deductible: 0,
taxOnIncome: mapped.newTaxOnIncome,
rebate: safeNum(_totals.rebate || 0),
taxPayableFinal: safeNum(_totals.totalTaxNew || _totals.totalTax || 0),
qtrData: [],
totalTDS: mapped.totalTDS,
totalPaid: mapped.totalPaid
};
} else {
DATA = {
slabLabel: "OLD IT SLAB",
gross: mapped.gross,
hraExemption: mapped.hraExemption,
pt: mapped.pt,
standardDeduction: mapped.stdDed || 50000,
S80C_TotalGross: mapped.s80c_gross,
S80C_Deductible: mapped.s80c_ded,
S13_EWF_Gross: mapped.s13_ewf_gross,
S13_80D_Gross: mapped.s13_80d_gross,
S13_EWF_Deductible: mapped.s13_ewf_ded,
S13_80D_Deductible: mapped.s13_80d_ded,
taxOnIncome: mapped.oldTaxOnIncome,
rebate: safeNum(_totals.rebate || 0),
taxPayableFinal: safeNum(_totals.totalTax || _totals.oldTotalTax || 0),
qtrData: [],
totalTDS: mapped.totalTDS,
totalPaid: mapped.totalPaid
};
}
// --- Build quarter data from advTax if present else fallback split evenly ---
if (_adv && _adv.length >= 12) {
const q0 = _adv.slice(0, 3).reduce((a, b) => a + b, 0);
const q1 = _adv.slice(3, 6).reduce((a, b) => a + b, 0);
const q2 = _adv.slice(6, 9).reduce((a, b) => a + b, 0);
const q3 = _adv.slice(9, 12).reduce((a, b) => a + b, 0);
const paidEach = Math.round(DATA.totalPaid / 4) || 0;
DATA.qtrData = [
{ paid: paidEach, deducted: q0, deposited: q0 },
{ paid: paidEach, deducted: q1, deposited: q1 },
{ paid: paidEach, deducted: q2, deposited: q2 },
{ paid: paidEach, deducted: q3, deposited: q3 }
];
} else {
const paidEach = Math.round(DATA.totalPaid / 4) || 0;
const tds = DATA.totalTDS || 0;
const per = Math.floor(tds / 4);
DATA.qtrData = [
{ paid: paidEach, deducted: per, deposited: per },
{ paid: paidEach, deducted: per, deposited: per },
{ paid: paidEach, deducted: per, deposited: per },
{ paid: paidEach, deducted: tds - per * 3, deposited: tds - per * 3 }
];
}
// --- DERIVED CALCULATIONS (STANDARD FORM 16 LOGIC) ---
const grossTotal = DATA.gross || 0;
const balance = grossTotal - (DATA.hraExemption || 0); // S.No 3
const totalDeductionsU16 = (DATA.standardDeduction || 0) + (DATA.pt || 0); // S.No 5 (Std. Ded + PT)
const incSal = balance - totalDeductionsU16; // S.No 6
const gti = incSal; // S.No 8 (Assuming S.No 7 = 0)
const S11_TotalSavings = DATA.S80C_Deductible || 0; // S.No 11 (Only 80C/CCE)
const taxableIncome_S12 = gti - S11_TotalSavings; // S.No 12
const S13_OtherTotalGross = (DATA.S13_EWF_Gross || 0) + (DATA.S13_80D_Gross || 0);
const aggregateDeductibleS13 = (DATA.S13_EWF_Deductible || 0) + (DATA.S13_80D_Deductible || 0);
const S14_TotalDeductions = S11_TotalSavings + aggregateDeductibleS13; // S.No 14
const totalIncome = gti - S14_TotalDeductions; // S.No 15
const taxOnIncome = DATA.taxOnIncome || 0;
const rebate = DATA.rebate || 0;
const taxAfterRebate = Math.max(0, taxOnIncome - rebate);
const cess = Math.round(taxAfterRebate * 0.04);
const taxPayableRounded = Math.round(taxAfterRebate + cess);
const taxPayableFinal = DATA.taxPayableFinal || taxPayableRounded;
const taxPayableResult = taxPayableFinal - (DATA.totalTDS || 0);
const verifiedAmount = taxPayableFinal;
const annexureA_Total = taxPayableFinal;
// --- DRAWING HELPERS (Refined for continuity) ---
const cx1 = RM - 180;
const cx2 = RM - 95;
// helper for Part-B Salary rows (S.No 1-8)
const bRow = (sl, desc, v1, v2, v3, h = ROW_H_M, boldRow = false) => {
const wrapped = doc.splitTextToSize(String(desc || ""), cx1 - LM - 35);
const lines = Math.max(1, wrapped.length);
const height = Math.max(h, lines * 12 + 6);
doc.rect(LM, y, CW, height); // Draw horizontal lines
font(boldRow ? "bold" : "normal", 8);
const textY = y + (height / 2) + 3;
if (sl) txt(sl, LM + 6, textY, { baseline: 'middle' });
doc.text(wrapped, LM + 30, textY, { baseline: 'middle' });
if (v1 !== null && v1 !== undefined) {
txt("Rs:", cx1 - 18, textY, { baseline: 'middle' });
right(fmt(v1), cx1 - 6, textY, { baseline: 'middle' });
}
if (v2 !== null && v2 !== undefined) {
txt("Rs:", cx2 - 18, textY, { baseline: 'middle' });
right(fmt(v2), cx2 - 6, textY, { baseline: 'middle' });
}
if (v3 !== null && v3 !== undefined) {
txt("Rs:", RM - 18, textY, { baseline: 'middle' });
right(fmt(v3), RM - 6, textY, { baseline: 'middle' });
}
y += height;
return height;
};
const xGross = LM + 330;
const xQual = LM + 425;
const xDed = RM - 90;
// helper for Part-B Chapter VI-A rows (S.No 10-13)
const viaRow = (sl, l, vG, vQ, vD, h = 15, boldRow = false, rs = false) => {
const wrapped = doc.splitTextToSize(String(l || ""), xGross - LM - 35);
const lines = Math.max(1, wrapped.length);
const height = Math.max(h, lines * 12 + 6);
doc.rect(LM, y, CW, height); // Draw horizontal lines
font(boldRow ? "bold" : "normal", 8);
const textY = y + (height / 2) + 3;
if (sl) txt(sl, LM + 6, textY, { baseline: 'middle' });
doc.text(wrapped, LM + 30, textY, { baseline: 'middle' });
if (rs && vG !== null && vG !== undefined) { txt("Rs:", xGross - 18, textY, { baseline: 'middle' }); right(fmt(vG), xGross - 6, textY, { baseline: 'middle' }); }
if (vQ !== null && vQ !== undefined) { txt("Rs:", xQual - 18, textY, { baseline: 'middle' }); right(fmt(vQ), xQual - 6, textY, { baseline: 'middle' }); }
if (vD !== null && vD !== undefined) { txt("Rs:", RM - 18, textY, { baseline: 'middle' }); right(fmt(vD), RM - 6, textY, { baseline: 'middle' }); }
y += height;
return height;
};
// --- PAGE 1 DRAWING START ---
// PART A Headers & Grids (Unchanged - already look good)
doc.setLineWidth(0.6);
doc.rect(LM - 5, 20, CW + 10, 30); font("bold", 12); center("FORM NO.16", y + 12); y += 20;
doc.rect(LM - 5, y, CW + 10, 16); font("normal", 10); center(`(${DATA.slabLabel}) [See rule 31(1)(a)]`, y + 10); y += 16;
doc.rect(LM - 5, y, CW + 10, 16); font("bold", 12); center("PART-A", y + 10); y += 16;
doc.rect(LM - 5, y, CW + 10, 16); font("normal", 10); center("Certificate under section 203 of the Income-tax Act, 1961 for Tax deducted at source on Salary", y + 12); y += 20;
const nameGridH = 50;
const nameGridMidX = LM + (CW / 2);
doc.setLineWidth(0.5);
doc.rect(LM - 5, y, CW + 10, nameGridH);
doc.line(nameGridMidX, y, nameGridMidX, y + nameGridH);
font("normal", 8);
txt("Name and address of the Employer", LM + 6, y + 14);
txt("Name and designation of the employee", nameGridMidX + 6, y + 14);
font("bold", 9);
doc.text(doc.splitTextToSize(METADATA.nameEmp, (CW / 2) - 12), LM + 6, y + 30);
doc.text(doc.splitTextToSize(METADATA.nameDesig, (CW / 2) - 12), nameGridMidX + 6, y + 30);
y += nameGridH + 4;
const panGridH = 40;
const panGridCol1 = LM + 105;
const panGridCol3 = LM + 400;
doc.rect(LM - 5, y, CW + 10, panGridH);
doc.line(panGridCol1, y, panGridCol1, y + panGridH);
doc.line(panGridCol3, y, panGridCol3, y + panGridH);
doc.line(LM - 5, y + 24, RM + 5, y + 24);
font("normal", 8);
txt("PAN no. of the Deductor", LM + 6, y + 12);
txt("TAN No. of the Deductor", panGridCol1 + 6, y + 12);
txt("PAN NO. of the Employee", panGridCol3 + 6, y + 12);
font("bold", 9);
txt(METADATA.panDed || _meta.panDed || "PANNOTREQD", LM + 6, y + 36);
txt(METADATA.tanDed, panGridCol1 + 6, y + 36);
txt(METADATA.panEmp, panGridCol3 + 6, y + 36);
y += panGridH + 4;
const citGridH = 50;
doc.rect(LM - 5, y, CW + 10, citGridH);
doc.line(nameGridMidX, y, nameGridMidX, y + citGridH);
doc.line(nameGridMidX, y + 30, RM + 5, y + 30);
font("normal", 8);
txt("CIT (TDS)", LM + 6, y + 12);
doc.text(doc.splitTextToSize(METADATA.cit, (CW / 2) - 12), LM + 6, y + 26);
txt("FINANCE YEAR", nameGridMidX + 6, y + 12);
txt("Period", nameGridMidX + 110, y + 12);
font("bold", 9);
txt(METADATA.fy, nameGridMidX + 6, y + 26);
font("normal", 8);
txt("Assessment Year", nameGridMidX + 6, y + 38);
font("bold", 9);
txt(METADATA.ay, nameGridMidX + 6, y + 50);
txt(METADATA.periodFrom, nameGridMidX + 110, y + 50);
txt(METADATA.periodTo, nameGridMidX + 190, y + 50);
y += citGridH + 6;
font("normal", 8);
txt("Summary of tax deducted at source", LM + 6, y + 12);
y += 14;
const qtrTblCols = [LM, LM + 50, LM + 180, LM + 320, LM + 450, RM];
const qtrRowH = 18;
doc.rect(LM, y, CW, qtrRowH);
qtrTblCols.forEach((x, i) => { if (i > 0) doc.line(x, y, x, y + qtrRowH + (4 * qtrRowH)); });
font("bold", 7);
txt("Quarter", qtrTblCols[0] + 4, y + 12);
txt("Receipt Numbers of", qtrTblCols[1] + 4, y + 12);
txt("Amount paid / Credited", qtrTblCols[2] + 4, y + 12);
txt("Amount of tax deducted", qtrTblCols[3] + 4, y + 12);
txt("Amount of tax deposited /", qtrTblCols[4] + 4, y + 12);
y += qtrRowH;
font("normal", 8);
txt("remitted in Central Govt.", qtrTblCols[4] + 4, y + 2);
y += 6;
DATA.qtrData.forEach((qtr, i) => {
doc.rect(LM, y, CW, qtrRowH);
font("normal", 8);
txt(`Q${i + 1}`, qtrTblCols[0] + 6, y + 12);
txt("-", qtrTblCols[1] + 6, y + 12);
right(fmt(qtr.paid), qtrTblCols[3] - 6, y + 12);
right(fmt(qtr.deducted), qtrTblCols[4] - 6, y + 12);
right(fmt(qtr.deposited), RM - 6, y + 12);
y += qtrRowH;
});
doc.rect(LM, y, CW, qtrRowH);
font("bold", 8);
txt("Total", qtrTblCols[0] + 6, y + 12);
right(fmt(DATA.totalPaid), qtrTblCols[3] - 6, y + 12);
right(fmt(DATA.totalTDS), qtrTblCols[4] - 6, y + 12);
right(fmt(DATA.totalTDS), RM - 6, y + 12);
y += qtrRowH + SECTION_SPACING;
// --- PART B: SALARY DETAILS (S.No 1 to 8) ---
font("bold", 11);
txt("PART-B (Refer Note 1)", LM + 6, y + 10);
y += 12;
font("normal", 8);
txt("Details of Salary paid and any other income and tax deducted", LM + 6, y + 8);
y += 14;
// Start Y for the salary block
const salaryBlockY = y;
// S.No 1 (Gross Salary)
doc.rect(LM, y, CW, ROW_H_M);
font("bold", 8);
txt("1", LM + 6, y + 10);
txt("Gross Salary", LM + 30, y + 10);
y += ROW_H_M;
let rowCount = 0; // to track height for vertical lines
// Rows 1(a), (b), (c), TOTAL
rowCount += bRow(null, "(a) Salary as per provisions contained in section 17(1)", grossTotal, null, null, ROW_H_M, false);
rowCount += bRow(null, "(b) Value of perquisites under section 17(2)", 0, null, null, ROW_H_M, false);
rowCount += bRow(null, "(c) Profits in lieu of salary under section 17(3)", 0, null, null, ROW_H_M, false);
rowCount += bRow(null, "TOTAL (a+b+c)", null, grossTotal, grossTotal, ROW_H_M, true);
// S.No 2: Exemptions u/s 10
doc.rect(LM, y, CW, ROW_H_M);
font("bold", 8);
txt("2", LM + 6, y + 10);
txt("Less: Exempted Allowance u/s 10:", LM + 30, y + 10);
y += ROW_H_M;
rowCount += bRow("A)", "House Rent Allowance vis 10 (2A)13(A) (Exempted only in Old Tax)", DATA.hraExemption || 0, DATA.hraExemption || 0, null, ROW_H_M, false);
rowCount += bRow("B)", "Intrest On Housing Loan ADVANCE U/S 24 (B)", 0, 0, null, ROW_H_M, false);
// S.No 3: Balance (1-2)
rowCount += bRow("3", "Balance (1-2)", null, null, balance, ROW_H_M, true);
// S.No 4: Deductions U/s 16
doc.rect(LM, y, CW, ROW_H_M);
font("bold", 8);
txt("4", LM + 6, y + 10);
txt("Deductions U/s 16:", LM + 30, y + 10);
y += ROW_H_M;
rowCount += bRow(null, "(a) Standard Deduction U/s 16(ia) (Common in New/Old Tax)", DATA.standardDeduction || 0, null, null, ROW_H_M, false);
rowCount += bRow(null, "(b) Professional Tax U/s 16(iii) (Only in Old Tax)", DATA.pt || 0, null, null, ROW_H_M, false);
rowCount += bRow(null, "(c) Entertainment Allowance U/s 16(ii)", 0, null, null, ROW_H_M, false);
// S.No 5 to 8
rowCount += bRow("5", "Aggregate of 4(a) to (c)", null, totalDeductionsU16, null, ROW_H_M, true);
rowCount += bRow("6", "Income chargeable under the head 'salaries' (3-5)", null, null, incSal, ROW_H_M, true);
rowCount += bRow("7", "Add: Any other income reported by the employee", 0, null, null, ROW_H_M, false);
rowCount += bRow("8", "Gross total income (6+7)", null, null, gti, ROW_H_M, true);
// --- CONSOLIDATED VERTICAL LINES for Salary Block (S.No 1 to 8) ---
doc.line(LM + 25, salaryBlockY, LM + 25, y); // SL No Column
doc.line(cx1, salaryBlockY, cx1, y); // Rs Column 1
doc.line(cx2, salaryBlockY, cx2, y); // Rs Column 2
y += SECTION_SPACING;
// --- CHAPTER VI-A (9..12) ---
font("bold", 10);
txt("9", LM + 6, y + 12);
txt("Deductions under Chapter VIA", LM + 32, y + 12);
y += 16;
const chapterVIA_Y = y; // Start Y for Chapter VI-A Block
// S.No 10 Header
doc.rect(LM, y, CW, 16);
doc.line(xGross, y, xGross, y + 16);
doc.line(xQual, y, xQual, y + 16);
doc.line(xDed, y, xDed, y + 16);
font("bold", 8);
txt("10", LM + 6, y + 12);
txt("Savings U/s 80CCE (80C, 80CCC and 80CCD (i))", LM + 32, y + 12);
txt("Gross Amount", xGross + 4, y + 12);
txt("Qualifying amount", xQual + 4, y + 12);
txt("Deductible Amount Rs.", xDed + 4, y + 12);
y += 16;
viaRow("A)", "Section 80 C (Only in Old Tax)", null, null, null, 15, true);
viaRow("a)", "PPF/LIC/Tuition Fee/Home Loan Principle", DATA.S80C_TotalGross || 0, S11_TotalSavings, S11_TotalSavings, 15, false, true);
// S.No 11: Total Savings
doc.rect(LM, y, CW, ROW_H_M);
doc.line(xGross, y, xGross, y + ROW_H_M);
doc.line(xQual, y, xQual, y + ROW_H_M);
doc.line(xDed, y, xDed, y + ROW_H_M);
font("bold", 9);
txt("11", LM + 6, y + 12);
txt("Total Deductible Savings (A+B+C+D)", LM + 32, y + 12);
txt("Rs:", xGross - 18, y + 12);
right(fmt(S11_TotalSavings), xGross - 6, y + 12);
txt("Rs:", xQual - 18, y + 12);
right(fmt(S11_TotalSavings), xQual - 6, y + 12);
txt("Rs:", RM - 18, y + 12);
right(fmt(S11_TotalSavings), RM - 6, y + 12);
y += ROW_H_M + 4;
// S.No 12: Taxable Income
doc.rect(LM, y, CW, ROW_H_M);
doc.line(xDed, y, xDed, y + ROW_H_M);
font("bold", 9);
txt("12", LM + 6, y + 12);
txt("Taxable income (8 - 11)", LM + 32, y + 12);
txt("Rs:", RM - 18, y + 12);
right(fmt(taxableIncome_S12), RM - 6, y + 12);
y += ROW_H_M + 8;
// --- CONSOLIDATED VERTICAL LINES for Chapter VI-A (S.No 10-12 block) ---
doc.line(LM + 25, chapterVIA_Y, LM + 25, y - (ROW_H_M + 8) + (ROW_H_M + 4)); // SL No for 10-11
// Note: Lines for 10/11 columns are already drawn inside the fixed height boxes above.
// -------------------- PAGE 2 --------------------
doc.addPage();
y = 30;
// --- 13: Other Sections ---
font("bold", 9);
txt("13", LM + 6, y + 12);
txt("Other Sections (80CCG, 80D, 80DDB, 80E, 80G etc) under Chapter VI-A (Only in Old Tax)", LM + 32, y + 12);
y += 16;
const otherSection_Y = y; // Start Y for Other Deductions Block
const xG_O = LM + 330;
const xQ_O = LM + 425;
const xD_O = RM - 90;
// S.No 13 Header
doc.rect(LM, y, CW, 16);
doc.line(xG_O, y, xG_O, y + 16);
doc.line(xQ_O, y, xQ_O, y + 16);
doc.line(xD_O, y, xD_O, y + 16);
font("bold", 8);
txt("Gross Amount", xG_O + 6, y + 12);
txt("Qualify amount", xQ_O + 6, y + 12);
txt("Deductible Amount Rs.", xD_O + 6, y + 12);
y += 16;
// helper for S.No 13 rows
const oRow = (sl, l, vG, vQ, h = 15) => {
const wrapped = doc.splitTextToSize(String(l || ""), xG_O - LM - 35);
const lines = Math.max(1, wrapped.length);
const height = Math.max(h, lines * 12 + 6);
doc.rect(LM, y, CW, height); // Draw horizontal lines
font("normal", 8);
const textY = y + (height / 2) + 3;
if (sl) txt(sl, LM + 6, textY, { baseline: 'middle' });
doc.text(wrapped, LM + 30, textY, { baseline: 'middle' });
if (vG !== null && vG !== undefined) { txt("Rs:", xG_O - 18, textY, { baseline: 'middle' }); right(fmt(vG), xG_O - 6, textY, { baseline: 'middle' }); }
if (vQ !== null && vQ !== undefined) { txt("Rs:", xQ_O - 18, textY, { baseline: 'middle' }); right(fmt(vQ), xQ_O - 6, textY, { baseline: 'middle' }); }
y += height;
return height;
};
oRow("a)", "E.W.F, & S.W.F, Kerala flood, Titli relief fund", DATA.S13_EWF_Gross || 0, DATA.S13_EWF_Deductible || 0);
oRow("b)", "80D-Medical Insurance Premium-Self, Spouse & Children", DATA.S13_80D_Gross || 0, DATA.S13_80D_Deductible || 0);
oRow("c)", "80E-Interest on Educational Loan", 0, 0);
oRow("d)", "80G-Donation to certain funds", 0, 0);
oRow("e)", "Others", 0, 0);
// TOTAL (13)
doc.rect(LM, y, CW, ROW_H_M);
doc.line(xG_O, y, xG_O, y + ROW_H_M);
doc.line(xQ_O, y, xQ_O, y + ROW_H_M);
doc.line(xD_O, y, xD_O, y + ROW_H_M);
font("bold", 8);
txt("TOTAL (a+b+c+d+e)", LM + 32, y + 12);
txt("Rs:", xG_O - 18, y + 12);
right(fmt(S13_OtherTotalGross), xG_O - 6, y + 12);
txt("Rs:", xQ_O - 18, y + 12);
right(fmt(aggregateDeductibleS13), xQ_O - 6, y + 12);
y += ROW_H_M + 6;
// --- CONSOLIDATED VERTICAL LINES for Other Deductions Block (S.No 13) ---
doc.line(LM + 25, otherSection_Y, LM + 25, y - 6); // SL No Column (Runs down to S.No 14)
doc.line(xG_O, otherSection_Y + 16, xG_O, y - 6); // Gross Column
doc.line(xQ_O, otherSection_Y + 16, xQ_O, y - 6); // Qualify Column
doc.line(xD_O, otherSection_Y + 16, xD_O, y - 6); // Deductible Column
// 14 Aggregate
doc.rect(LM, y, CW, ROW_H_M);
doc.line(xD_O, y, xD_O, y + ROW_H_M);
font("bold", 9);
txt("14", LM + 6, y + 12);
txt("Aggregate of deductible amount under Chap. VIA (11+13)", LM + 32, y + 12);
txt("Rs:", RM - 18, y + 12);
right(fmt(S14_TotalDeductions), RM - 6, y + 12);
y += ROW_H_M + 8;
// The SL No 13/14 column line is now officially done at y.
// --- TAX CALCULATION (15..22) ---
const taxBlock_Y = y; // Start Y for Tax Calculation Block
const taxRow = (sl, d, v, boldRow = false) => {
const height = ROW_H_M;
doc.rect(LM, y, CW, height);
font(boldRow ? "bold" : "normal", 8);
const textY = y + 12;
if (sl) txt(sl, LM + 6, textY);
doc.text(doc.splitTextToSize(d, RM - 120 - LM), LM + 28, textY);
if (v !== null && v !== undefined) { txt("Rs:", RM - 30, textY); right(fmt(v), RM - 6, textY); }
y += height;
return height;
};
taxRow("15", "Total Income (8 - 14)", totalIncome, true);
taxRow("16", "Tax on total income", taxOnIncome, false);
taxRow("17", "Rebate U/S 87A (Old Tax: <=5Lakh, New Tax: <=7Lakh)", DATA.rebate || 0, false);
taxRow("18", "Surcharge", 0, false);
taxRow("19", `Education & health cess @4% on (Tax after Rebate x 4%)`, cess, false);
taxRow("20", "Tax payable (After Rebate & Cess, Rounded off)", taxPayableRounded, true);
taxRow("21", "Less Relief U/s 89(1) (attach details)", 0, false);
taxRow("22", `${DATA.slabLabel} Total Tax Payable (Rounded off)`, taxPayableFinal, true);
// --- CONSOLIDATED VERTICAL LINE for Tax Calculation Block (S.No 15-22) ---
doc.line(RM - 110, taxBlock_Y, RM - 110, y);
y += 6;
// --- 23 & 24 ---
const xTDS = RM - 110;
const xTDS_Rs = RM - 6;
doc.rect(LM, y, CW, ROW_H_M);
font("normal", 8);
txt("23", LM + 6, y + 12);
txt("Less:(a) Tax deducted at source U/s 192(1)", LM + 28, y + 12);
doc.line(xTDS, y, xTDS, y + ROW_H_M);
txt("Rs:", xTDS - 18, y + 12);
right(fmt(DATA.totalTDS || 0), xTDS - 6, y + 12);
txt("Rs:", xTDS_Rs - 18, y + 12);
right(fmt(DATA.totalTDS || 0), xTDS_Rs, y + 12);
y += ROW_H_M + 6;
doc.rect(LM, y, CW, ROW_H_M);
doc.line(xTDS, y, xTDS, y + ROW_H_M);
font("normal", 8);
txt(" (b)", LM + 28, y + 12);
doc.text("Tax paid by the employer on behalf of the employee U/s 192 (1A) on perquisited U/s 17 (2)", LM + 48, y + 12);
y += ROW_H_M + 6;
doc.rect(LM, y, CW, ROW_H_M);
doc.line(xTDS, y, xTDS, y + ROW_H_M);
font("bold", 9);
txt("24", LM + 6, y + 12);
txt("TAX PAYABLE / REFUNDABLE (22-23)", LM + 28, y + 12);
txt("Rs:", xTDS_Rs - 18, y + 12);
right(fmt(taxPayableResult), xTDS_Rs, y + 12);
y += ROW_H_M + 8;
// --- VERIFICATION ---
font("bold", 11);
txt("Verification", LM + 6, y + 12);
y += 16;
font("normal", 9);
const empShort = (METADATA.nameDesig || "").split('\n')[0] || METADATA.nameDesig;
const empCapacity = (METADATA.nameDesig || "").split('\n')[1] || "";
const verifText = `I Sri/Smt.: ${empShort.replace(/^Sri\.\s*/i, '')}, Son/Daughter of Sri/smt. working in the capacity of ${empCapacity.trim() || ''}, do hereby certify that the sum of Rs: ${fmt(verifiedAmount)} /- has been deducted and deposited to the credit of the Central Government as per ${DATA.slabLabel}.`;
doc.text(doc.splitTextToSize(verifText, CW), LM + 6, y);
y += 30;
// Signature boxes
doc.rect(LM, y, CW / 2 - 6, 50);
doc.rect(LM + CW / 2 + 6, y, CW / 2 - 6, 50);
font("normal", 9);
txt("Place:-", LM + 10, y + 14);
txt(METADATA.city || "PADMANABHAM", LM + 80, y + 14);
txt("Date:-", LM + 10, y + 30);
txt(METADATA.date || METADATA.periodTo || "31/03/2026", LM + 80, y + 30);
txt("Designation:", LM + 10, y + 46);
doc.text(doc.splitTextToSize(METADATA.nameEmp.split('\n')[1] || METADATA.nameDesig, 180), LM + 90, y + 46);
right("Signature of person responsible for deduction of tax", RM - 6, y + 26);
right(`Full Name: ${METADATA.nameEmp.split('\n')[0] || METADATA.nameEmp}`, RM - 6, y + 46);
y += 64;
// --- ANNEXURE A (Book Entry) ---
font("bold", 10);
center("ANNEXURE A (Book Entry)", y);
y += 14;
const ac = [LM, LM + 40, LM + 170, LM + 270, LM + 400, RM];
const aRowH = 14;
doc.rect(LM, y, CW, aRowH);
ac.forEach((x, i) => { if (i > 0) doc.line(x, y, x, y + aRowH + (10 * aRowH)); });
font("bold", 7);
txt("Sl.No", ac[0] + 6, y + 10);
doc.text("Tax Deposited in respect\non of the employee (Rs.)", ac[1] + 6, y + 6);
doc.text("Receipt Numbers of Form No 24G", ac[2] + 6, y + 10);
doc.text("DDO Sequence Number in the\nBook Adjustment Mini Statement", ac[3] + 6, y + 6);
doc.text("Date on which tax deposited\n(dd/mm/yy)", ac[4] + 6, y + 6);
y += aRowH;
for (let i = 1; i <= 12; i++) {
doc.rect(LM, y, CW, aRowH);
font("normal", 8);
txt(`${i}.`, ac[0] + 6, y + 10);
if (i === 12) {
right(fmt(DATA.taxPayableFinal || 0), ac[2] - 6, y + 10);
txt("0", ac[3] + 6, y + 10);
txt("0", ac[4] + 6, y + 10);
txt(METADATA.periodTo || "31/03/2026", ac[4] + 60, y + 10);
} else {
right("0", ac[2] - 6, y + 10);
txt("-", ac[3] + 6, y + 10);
txt("-", ac[4] + 6, y + 10);
txt("-", ac[4] + 60, y + 10);
}
y += aRowH;
}
doc.rect(LM, y, CW, aRowH);
font("bold", 8);
txt("Total", ac[0] + 6, y + 10);
right(fmt(annexureA_Total), ac[2] - 6, y + 10);
y += aRowH + 10;
// --- ANNEXURE B (Challan) ---
font("bold", 10);
center("ANNEXURE B (Challan)", y);
y += 14;
const bc = [LM, LM + 40, LM + 170, LM + 270, LM + 390, RM];
const bRowH = 14;
doc.rect(LM, y, CW, bRowH);
bc.forEach((x, i) => { if (i > 0) doc.line(x, y, x, y + bRowH + (4 * bRowH)); });
font("bold", 7);
txt("Sl.No", bc[0] + 6, y + 10);
doc.text("Challan Serial No", bc[1] + 6, y + 10);
doc.text("BSR Code of Bank Branch", bc[2] + 6, y + 10);
doc.text("Date of Deposit\n(dd/mm/yy)", bc[3] + 6, y + 6);
doc.text("Amount of Tax Deposited (Rs.)", bc[4] + 6, y + 10);
y += bRowH;
DATA.qtrData.forEach((row, i) => {
doc.rect(LM, y, CW, bRowH);
font("normal", 8);
txt(`${i + 1}.`, bc[0] + 6, y + 10);
txt(`${i + 1}`, bc[1] + 6, y + 10);
txt("0000000", bc[2] + 6, y + 10);
const yr = (METADATA.periodTo || "31/03/2026").split('/').pop() || "2026";
txt(`31/03/${yr}`, bc[3] + 6, y + 10);
right(fmt(row.deducted || 0), RM - 6, y + 10);
y += bRowH;
});
doc.rect(LM, y, CW, bRowH);
font("bold", 8);
txt("Total", bc[0] + 6, y + 10);
right(fmt(DATA.totalTDS || 0), RM - 6, y + 10);
y += bRowH + 10;
// Footer
font("normal", 8);
center(METADATA.footer, y);
y += 8;
// Final outer borders (thin)
const pages = doc.internal.getNumberOfPages();
for (let i = 1; i <= pages; i++) {
doc.setPage(i);
doc.setLineWidth(0.6);
doc.rect(LM - 5, 20, CW + 10, PG_H - 40);
doc.setLineWidth(0.4);
doc.rect(LM - 2, 23, CW + 4, PG_H - 46);
}
const empLabelRaw = (_meta.name || METADATA.nameDesig || "Employee").toString();
const empLabel = empLabelRaw.replace(/\s+/g, '_').replace(/[^\w\-_.]/g, '');
doc.save(`Form16_${selectedRegime}_${empLabel || 'Employee'}.pdf`);
} catch (e) {
console.error(e);
alert(`Error generating PDF: ${e && e.message ? e.message : e}. Check console.`);
}
}
0 Comments:
Post a Comment