Personal Finance Audit & Health Check Tool

Personal Finance Audit & Health Check

Monthly Income & Key Expenses

Income

$
$

Key Monthly Financial Commitments

$
$
$
$ (Housing, utilities, food, basic transport, insurance, min. debt payments)

Your Assets

Liquid Assets

$
$

Investments

$
$

Real Estate

$
$

Other Significant Assets

$
$
Total Assets: $0.00

Your Liabilities

Short-Term Debt

$
$

Long-Term Debt

$
$
$
$
$
Total Liabilities: $0.00

Financial Health Check Report

Please fill in your financial details on the previous tabs, then click "View / Refresh Health Check".

Your financial indicators are generally within healthy ranges based on common guidelines. Keep up the good work!

"; } pfhc_healthCheckDataForPdf = { inputs: { grossMonthlyIncome, netMonthlyIncome, monthlySavings, totalMonthlyDebtPayments, monthlyHousingCost, monthlyEssentialExpenses, totalAssets, totalLiabilities, emergencyFundBalance, liquidAssets }, netWorth, ratios: displayedRatios, // Contains label, value, unit, statusText, interpretation qualitativeSummary: summaryEl.innerHTML, // Capture the generated HTML for summary suggestions // Array of suggestion strings }; // No recursive openTab call } catch (error) { console.error("Error generating health check:", error); alert("Error generating health check: " + error.message); pfhc_healthCheckDataForPdf = null; } } function pfhc_downloadPDF() { if (!pfhc_healthCheckDataForPdf) { alert("Please generate the health check report first."); return; } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF library (jsPDF) not loaded.'); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); if (typeof doc.autoTable !== 'function') { alert('PDF Table plugin (jsPDF-AutoTable) not loaded.'); return; } const data = pfhc_healthCheckDataForPdf; const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--pfhc-primary-color').trim(); const accentGood = getComputedStyle(document.documentElement).getPropertyValue('--pfhc-accent-good').trim(); const accentFair = getComputedStyle(document.documentElement).getPropertyValue('--pfhc-accent-fair').trim(); const accentAttention = getComputedStyle(document.documentElement).getPropertyValue('--pfhc-accent-attention').trim(); let yPos = 20; doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Personal Finance Health Check Report", 105, yPos, { align: 'center' }); yPos += 15; doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Financial Snapshot:", 14, yPos); yPos += 7; const snapshotData = [ ["Gross Monthly Income:", pfhc_formatCurrency(data.inputs.grossMonthlyIncome)], ["Net Monthly Income:", pfhc_formatCurrency(data.inputs.netMonthlyIncome)], ["Monthly Savings:", pfhc_formatCurrency(data.inputs.monthlySavings)], ["Monthly Debt Payments:", pfhc_formatCurrency(data.inputs.totalMonthlyDebtPayments)], ["Monthly Housing Cost:", pfhc_formatCurrency(data.inputs.monthlyHousingCost)], ["Monthly Essential Expenses:", pfhc_formatCurrency(data.inputs.monthlyEssentialExpenses)], ["Total Assets:", pfhc_formatCurrency(data.inputs.totalAssets)], ["Total Liabilities:", pfhc_formatCurrency(data.inputs.totalLiabilities)], [{content:"Calculated Net Worth:", styles:{fontStyle:'bold'}}, {content:pfhc_formatCurrency(data.netWorth), styles:{fontStyle:'bold'}}], ]; doc.autoTable({ startY: yPos, body: snapshotData, theme: 'plain', styles: { fontSize: 9 }, columnStyles: {0:{fontStyle:'bold', cellWidth:70}}}); yPos = doc.lastAutoTable.finalY + 10; if (yPos > 250) { doc.addPage(); yPos = 20;} doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Key Financial Ratios & Indicators:", 14, yPos); yPos += 7; const ratioHeaders = ["Indicator", "Value", "Status", "General Guideline"]; const ratioBody = data.ratios.map(r => { let valueStr = (isNaN(r.value) || r.value === Infinity) ? 'N/A' : `${r.value.toFixed(1)}${r.unit}`; return [r.label, valueStr, r.statusText, r.interpretation]; }); doc.autoTable({ startY: yPos, head: [ratioHeaders], body: ratioBody, theme: 'grid', headStyles: { fillColor: primaryColor, textColor: [255,255,255], fontStyle: 'bold' }, styles: { fontSize: 8, cellPadding: 1.5, overflow: 'linebreak' }, columnStyles: {1:{halign:'right'}, 2:{halign:'center'}}, didDrawCell: function(hookData) { // Color status cell if (hookData.column.index === 2 && hookData.cell.section === 'body') { const status = hookData.cell.raw; if (status === 'Good') hookData.cell.styles.fillColor = accentGood; else if (status === 'Fair') hookData.cell.styles.fillColor = accentFair; else if (status === 'Needs Attention') hookData.cell.styles.fillColor = accentAttention; if (status === 'Good' || status === 'Needs Attention' || status ==='Fair') hookData.cell.styles.textColor = [255,255,255]; } } }); yPos = doc.lastAutoTable.finalY + 10; if (yPos > 250) { doc.addPage(); yPos = 20;} doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Overall Summary & Suggestions:", 14, yPos); yPos +=7; doc.setFontSize(9); doc.setTextColor(50); // Process qualitative summary - remove HTML tags for PDF let summaryTextForPdf = data.qualitativeSummary.replace(/<[^>]*>?/gm, ''); summaryTextForPdf = summaryTextForPdf.replace(/Key Observations:/g, "\nKey Observations:\n"); // Add line breaks const splitSummary = doc.splitTextToSize(summaryTextForPdf, 180); doc.text(splitSummary, 14, yPos); yPos += (splitSummary.length * 4) + 5; if (data.suggestions.length > 0) { if (yPos > 260) { doc.addPage(); yPos = 20;} doc.setFontSize(10); doc.setTextColor(primaryColor); doc.text("Suggestions for Areas to Review:", 14, yPos); yPos += 6; doc.setFontSize(9); doc.setTextColor(50); data.suggestions.forEach(sug => { const splitSuggestion = doc.splitTextToSize(`• ${sug}`, 180); if (yPos > 270 && (yPos + splitSuggestion.length * 4 > 290) ) {doc.addPage(); yPos = 20;} doc.text(splitSuggestion, 16, yPos); yPos += (splitSuggestion.length * 4) + 2; }); } else if (data.ratios.every(r => r.statusText === 'Good')) { if (yPos > 270) {doc.addPage(); yPos = 20;} doc.text("All indicators are generally within healthy ranges. Keep up the great work!", 14, yPos); } // Footer const pageHeight = doc.internal.pageSize.height || doc.internal.pageSize.getHeight(); doc.setFontSize(8); doc.setTextColor(150); doc.text(`Generated on: ${new Date().toLocaleDateString('en-US', {year:'numeric', month:'short', day:'numeric'})}`, 14, pageHeight - 10); doc.text(`Personal Finance Health Check`, doc.internal.pageSize.width - 14, pageHeight - 10, { align: 'right' }); doc.save("Financial_Health_Check_Report.pdf"); } // Initialize document.addEventListener('DOMContentLoaded', () => { if (pfhc_tabs.length > 0 && pfhc_tabs[0]) pfhc_openTab(null, pfhc_tabs[0].id); pfhc_updateNavButtons(); // Add listeners to asset and liability inputs to update totals dynamically const assetLiabilityInputs = document.querySelectorAll('#pfhc-tab2 input[type="number"], #pfhc-tab3 input[type="number"]'); assetLiabilityInputs.forEach(input => { input.addEventListener('input', () => { if (pfhc_currentTab === 1) pfhc_calculateTotalAssets(); // Tab 2 is index 1 if (pfhc_currentTab === 2) pfhc_calculateTotalLiabilities(); // Tab 3 is index 2 // If on report tab and an input changes, refresh report if (pfhc_currentTab === 3) pfhc_generateHealthCheck(); }); }); // Add listeners for Tab 1 inputs for the same reason const tab1Inputs = document.querySelectorAll('#pfhc-tab1 input[type="number"]'); tab1Inputs.forEach(input => { input.addEventListener('input', () => { if (pfhc_currentTab === 3) pfhc_generateHealthCheck(); }); }); const primaryColorVal = getComputedStyle(document.documentElement).getPropertyValue('--pfhc-primary-color').trim(); if (primaryColorVal.startsWith('#')) { const r = parseInt(primaryColorVal.slice(1, 3), 16); const g = parseInt(primaryColorVal.slice(3, 5), 16); const b = parseInt(primaryColorVal.slice(5, 7), 16); document.documentElement.style.setProperty('--pfhc-primary-color-rgb', `${r},${g},${b}`); } // Initial calculation for display pfhc_calculateTotalAssets(); pfhc_calculateTotalLiabilities(); });
Scroll to Top