`;
} else {
html += ``;
}
html += ``;
if(data.summary.breakevenYearSimple) {
html += ``;
}
html += `
`;
html += `Lump-Sum Portfolio End Value (Age ${data.inputs.lifeExpectancy}): ${formatCurrency(data.summary.finalLumpSumValue)}
(Invested at ${data.inputs.lumpSumReturnRate_pct.toFixed(1)}%, withdrawing amounts equivalent to annual pension)Total Withdrawn from Invested Lump-Sum: ${formatCurrency(data.summary.totalLumpSumWithdrawn)}
Simple Breakeven Year: Year ${data.summary.breakevenYearSimple} (Age ${data.inputs.retirementAge + data.summary.breakevenYearSimple -1})
(Cumulative pension exceeds non-invested lump-sum)Year-by-Year Projection (Retirement Phase):
`; if(data.projectionTable.length > 0) { html += ``;
html += `
`;
} else {
html += `| Ret. Year | Age | Annual Pension | Cum. Pension | Lump-Sum Start | Withdrawal | Growth | Lump-Sum End |
|---|---|---|---|---|---|---|---|
| ${row.year} | ${row.age} | ${formatCurrency(row.annualPension,0,0)} | ${formatCurrency(row.cumulativePension,0,0)} | ${formatCurrency(row.lumpSumStart,0,0)} | ${formatCurrency(row.lumpSumWithdrawal,0,0)} | ${formatCurrency(row.lumpSumGrowthVal,0,0)} | ${formatCurrency(row.lumpSumEndBalance,0,0)} ${row.notes ? `(${row.notes})` : ''} |
No projection data to display.
`; } html += ``; analysisResultsDiv.innerHTML = html; } if (runAnalysisBtn) { runAnalysisBtn.addEventListener('click', runAnalysis); } // --- PDF Download --- function loadJsPdfIfNeeded(callback) { if (jsPdfLoaded) { if (callback) callback(); return; } const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js'; script.onload = () => { jsPdfLoaded = true; console.log("jsPDF loaded dynamically."); if (callback) callback(); }; script.onerror = () => { console.error("Failed to load jsPDF."); alert("Error: Could not load PDF library."); }; document.head.appendChild(script); } function downloadReportAsPdf() { if (!jsPdfLoaded) { alert("PDF library not loaded."); return; } if (!analysisDataForPdf) { alert("No analysis data to download. Please run the analysis first."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF({ unit: 'pt', format: 'a4' }); const data = analysisDataForPdf; const pageMargin = 40; const pageWidth = doc.internal.pageSize.getWidth() - 2 * pageMargin; let y = pageMargin; function addMainTitle(text) { doc.setFontSize(18); doc.setFont(undefined, 'bold'); doc.setTextColor(44, 62, 80); // Primary doc.text(text, doc.internal.pageSize.getWidth() / 2, y, { align: 'center' }); y += 35; } function addSectionTitle(text) { if (y > doc.internal.pageSize.getHeight() - 80) { doc.addPage(); y = pageMargin; } doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(52, 152, 219); // Secondary doc.text(text, pageMargin, y); y += 25; } function addLine(key, value, keyColor = [52,73,94], valueColor = [52,73,94]) { if (y > doc.internal.pageSize.getHeight() - 40) { doc.addPage(); y = pageMargin; } doc.setFontSize(10); doc.setFont(undefined, 'bold'); doc.setTextColor(keyColor[0], keyColor[1], keyColor[2]); doc.text(key, pageMargin, y); doc.setFont(undefined, 'normal'); doc.setTextColor(valueColor[0], valueColor[1], valueColor[2]); const valueText = String(value); doc.text(valueText, pageMargin + 250, y, { align: 'left', maxWidth: pageWidth - 250 - 5 }); y += 18; } function addInfo(text) { if (y > doc.internal.pageSize.getHeight() - 50) { doc.addPage(); y = pageMargin; } doc.setFontSize(8.5); doc.setFont(undefined, 'italic'); doc.setTextColor(108, 117, 125); const splitText = doc.splitTextToSize(text, pageWidth); doc.text(splitText, pageMargin, y); y += (doc.getTextDimensions(splitText).h) + 10; } function addTable(headers, tableData, columnWidths) { if (y > doc.internal.pageSize.getHeight() - 60) { doc.addPage(); y = pageMargin; } doc.setFontSize(7.5); const headerFillColor = [52, 152, 219]; const headerTextColor = [255,255,255]; const rowTextColor = [52,73,94]; doc.setFillColor(headerFillColor[0], headerFillColor[1], headerFillColor[2]); doc.setTextColor(headerTextColor[0], headerTextColor[1], headerTextColor[2]); doc.setFont(undefined, 'bold'); let currentX = pageMargin; headers.forEach((header, i) => { doc.rect(currentX, y, columnWidths[i], 20, 'F'); doc.text(header, currentX + 3, y + 14); currentX += columnWidths[i]; }); y += 20; doc.setTextColor(rowTextColor[0], rowTextColor[1], rowTextColor[2]); doc.setFont(undefined, 'normal'); tableData.forEach((rowArray) => { if (y > doc.internal.pageSize.getHeight() - 30) { doc.addPage(); y = pageMargin; currentX = pageMargin; doc.setFillColor(headerFillColor[0], headerFillColor[1], headerFillColor[2]); doc.setTextColor(headerTextColor[0], headerTextColor[1], headerTextColor[2]); doc.setFont(undefined, 'bold'); headers.forEach((header, i) => { doc.rect(currentX, y, columnWidths[i], 20, 'F'); doc.text(header, currentX + 3, y + 14); currentX += columnWidths[i]; }); y += 20; doc.setTextColor(rowTextColor[0], rowTextColor[1], rowTextColor[2]); doc.setFont(undefined, 'normal'); } currentX = pageMargin; rowArray.forEach((cell, i) => { doc.rect(currentX, y, columnWidths[i], 18); const cellText = String(cell); const textLines = doc.splitTextToSize(cellText, columnWidths[i] - 6); doc.text(textLines, currentX + 3, y + 12); currentX += columnWidths[i]; }); y += 18; }); y += 10; } addMainTitle("Pension Buyout vs. Monthly Payout Analysis"); addInfo(`Report Generated: ${new Date().toLocaleString()}`); y += 10; addSectionTitle("Input Parameters"); addLine("Current Age:", `${data.inputs.currentAge} years`); addLine("Planned Retirement Age:", `${data.inputs.retirementAge} years`); addLine("Life Expectancy (Planning Horizon):", `${data.inputs.lifeExpectancy} years`); addLine("Monthly Pension Payout (Initial):", formatCurrency(data.inputs.monthlyPension)); addLine("Annual Pension COLA:", `${data.inputs.pensionCOLA_pct.toFixed(1)}%`); addLine("Lump-Sum Buyout Amount:", formatCurrency(data.inputs.lumpSumAmount)); addLine("Expected Return on Invested Lump-Sum:", `${data.inputs.lumpSumReturnRate_pct.toFixed(1)}%`); addLine("Expected Avg. Annual Inflation:", `${data.inputs.inflationRate_pct.toFixed(1)}%`); y += 10; addSectionTitle("Analysis Summary (Projected to Age " + data.inputs.lifeExpectancy + ")"); addLine("Total Value of Monthly Pension Payouts:", formatCurrency(data.summary.totalPensionValue), [46,204,113],[46,204,113]); if (data.summary.lumpSumDepletedYear !== null && data.summary.lumpSumDepletedYear <= data.summary.yearsInRetirement) { addLine("Lump-Sum Portfolio (Invested):", `Depleted in Year ${data.summary.lumpSumDepletedYear} of retirement`, [231,76,60],[231,76,60]); } else { addLine("Lump-Sum Portfolio End Value:", formatCurrency(data.summary.finalLumpSumValue), [46,204,113],[46,204,113]); } addLine("Total Withdrawn from Invested Lump-Sum:", formatCurrency(data.summary.totalLumpSumWithdrawn)); if(data.summary.breakevenYearSimple) { addLine("Simple Breakeven (Pension vs. Non-Invested Lump-Sum):", `Year ${data.summary.breakevenYearSimple} (Age ${data.inputs.retirementAge + data.summary.breakevenYearSimple -1})`); } y += 10; if (data.projectionTable.length > 0) { addSectionTitle("Year-by-Year Projection (Retirement Phase)"); const tableH = ["Ret. Yr", "Age", "Ann. Pension", "Cum. Pension", "Lump-Sum Start", "Withdrawal", "Growth", "Lump-Sum End"]; const tableCW = [35, 35, 70, 75, 80, 70, 60, 85]; // Sum: 510 const tableFData = data.projectionTable.map(r => [ r.year, r.age, formatCurrency(r.annualPension,0,0), formatCurrency(r.cumulativePension,0,0), formatCurrency(r.lumpSumStart,0,0), formatCurrency(r.lumpSumWithdrawal,0,0), formatCurrency(r.lumpSumGrowthVal,0,0), formatCurrency(r.lumpSumEndBalance,0,0) + (r.notes ? ` (${r.notes.substring(0,10)}..)` : '') ]); addTable(tableH, tableFData, tableCW); } addInfo("This analysis is illustrative and uses fixed average assumptions. It does not account for taxes, investment fees, or market volatility. The 'withdrawal' from the lump-sum is set to match the annual pension for comparison. Consult with a financial advisor for personalized advice."); // Footer const pageCount = doc.internal.getNumberOfPages(); for (let i = 1; i <= pageCount; i++) { doc.setPage(i); doc.setFontSize(8); doc.setTextColor(150); doc.text(`Page ${i} of ${pageCount} - Pension Buyout Analyzer`, pageMargin, doc.internal.pageSize.getHeight() - 20); } doc.save('Pension_Buyout_vs_Payout_Analysis.pdf'); } if (downloadPdfBtn) { downloadPdfBtn.addEventListener('click', () => loadJsPdfIfNeeded(downloadReportAsPdf)); } // --- Initialization --- showTab(0); loadJsPdfIfNeeded(); });