Mortgage Prepayment Budgeting Tool
Your Current Mortgage Details
Your Prepayment Plan
Prepayment Analysis & Comparison
Regular Monthly Payment (Principal & Interest): $0.00
Scenario 1: No Prepayments
Calculations will appear here.
Scenario 2: With Prepayments
Calculations will appear here.
Summary of Savings
Calculations will appear here.
Report Summary
A summary of your mortgage prepayment analysis will appear here.
Extra Monthly Payment Added: $${extraMonthlyPayment.toFixed(2)}.
Without Prepayment: Remaining term ~${Math.ceil(originalScenario.monthsToPayoff/12)} years, Total Future Interest ~$${originalScenario.totalInterestPaid === Infinity ? 'Infinite' : originalScenario.totalInterestPaid.toFixed(2)}.
With Prepayment: Remaining term ~${Math.ceil(prepaymentScenario.monthsToPayoff/12)} years, Total Future Interest ~$${prepaymentScenario.totalInterestPaid === Infinity ? 'Infinite' : prepaymentScenario.totalInterestPaid.toFixed(2)}.
Total Interest Saved: ${interestSaved === Infinity ? 'Substantial (from never ending)' : (interestSaved > 0 ? `$${interestSaved.toFixed(2)}` : '$0.00')}
Time Saved on Loan: ${timeSavedText}
Full details will be in the PDF.
`; } function mpbt_generatePdf() { const loanAmount = mpbt_getFloatValue('mpbtLoanAmount'); const interestRate = mpbt_getFloatValue('mpbtInterestRate'); const loanTermYears = mpbt_getIntValue('mpbtLoanTermYears'); const paymentsMade = mpbt_getIntValue('mpbtPaymentsMade'); const extraMonthlyPayment = mpbt_getFloatValue('mpbtExtraMonthlyPayment'); const originalScenario = mpbt_calculateAmortizationDetails(loanAmount, interestRate, loanTermYears, paymentsMade, 0); const prepaymentScenario = mpbt_calculateAmortizationDetails(loanAmount, interestRate, loanTermYears, paymentsMade, extraMonthlyPayment); if (!originalScenario || !prepaymentScenario) { alert("Calculation error. Cannot generate PDF."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); let yPos = 20; const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim(); const accentColor = getComputedStyle(document.documentElement).getPropertyValue('--accent-color').trim(); const textColor = getComputedStyle(document.documentElement).getPropertyValue('--text-color').trim(); const toCurrency = (num) => num === Infinity ? "N/A (Perpetual)" : `$${num.toFixed(2)}`; const formatTerm = (months) => { if (months === Infinity || isNaN(months)) return "Never Paid Off"; const years = Math.floor(months / 12); const remMonths = months % 12; return `${years} years, ${remMonths} months`; }; doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Mortgage Prepayment Analysis", doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 15; doc.setFontSize(12); doc.setTextColor(textColor); doc.text("Loan Details:", 14, yPos); yPos += 7; doc.setFontSize(10); doc.text(`Original Loan Amount: ${toCurrency(loanAmount)}`, 16, yPos); yPos += 6; doc.text(`Annual Interest Rate: ${interestRate.toFixed(2)}%`, 16, yPos); yPos += 6; doc.text(`Original Loan Term: ${loanTermYears} years`, 16, yPos); yPos += 6; doc.text(`Payments Already Made: ${paymentsMade}`, 16, yPos); yPos += 6; doc.text(`Current Approx. Balance: ${toCurrency(originalScenario.currentBalance)}`, 16, yPos); yPos += 6; doc.text(`Regular Monthly Payment (P&I): ${toCurrency(originalScenario.regularMonthlyPayment)}`, 16, yPos); yPos += 8; doc.text("Prepayment Plan:", 14, yPos); yPos += 7; doc.setFontSize(10); doc.text(`Extra Monthly Payment: ${toCurrency(extraMonthlyPayment)}`, 16, yPos); yPos += 8; const tableBody = [ ["Scenario", "Remaining Term", "Total Future Interest", "Payoff Date (from now)"], ["No Prepayment", formatTerm(originalScenario.monthsToPayoff), toCurrency(originalScenario.totalInterestPaid), "~" + Math.ceil(originalScenario.monthsToPayoff/12) + " years"], ["With Prepayment", formatTerm(prepaymentScenario.monthsToPayoff), toCurrency(prepaymentScenario.totalInterestPaid), "~" + Math.ceil(prepaymentScenario.monthsToPayoff/12) + " years"] ]; if (yPos > 240) { doc.addPage(); yPos = 20;} doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Comparison Summary", 14, yPos); yPos +=7; doc.autoTable({ startY: yPos, head: [tableBody[0]], body: tableBody.slice(1), theme: 'grid', headStyles: { fillColor: primaryColor, textColor: '#ffffff' }, styles: { fontSize: 9, cellPadding: 2 }, didDrawPage: (d) => { yPos = d.cursor.y; } }); yPos = doc.lastAutoTable.finalY + 10; if (yPos > 250) { doc.addPage(); yPos = 20;} doc.setFontSize(12); doc.setTextColor(accentColor); doc.text("Savings Achieved:", 14, yPos); yPos += 7; doc.setFontSize(10); doc.setTextColor(textColor); let interestSavedVal = 0; let timeSavedMonthsVal = 0; let timeSavedText = "N/A"; if (originalScenario.totalInterestPaid !== Infinity && prepaymentScenario.totalInterestPaid !== Infinity) { interestSavedVal = originalScenario.totalInterestPaid - prepaymentScenario.totalInterestPaid; } else if (prepaymentScenario.totalInterestPaid !== Infinity) { interestSavedVal = Infinity; } if (originalScenario.monthsToPayoff !== Infinity && prepaymentScenario.monthsToPayoff !== Infinity) { timeSavedMonthsVal = originalScenario.monthsToPayoff - prepaymentScenario.monthsToPayoff; } else if (prepaymentScenario.monthsToPayoff !== Infinity) { timeSavedMonthsVal = Infinity; } if(timeSavedMonthsVal === Infinity) { timeSavedText = "Loan becomes payable (was perpetual)"; } else if (timeSavedMonthsVal > 0) { const tsYears = Math.floor(timeSavedMonthsVal / 12); const tsMonthsRem = timeSavedMonthsVal % 12; timeSavedText = `${tsYears} years, ${tsMonthsRem} months`; } else { timeSavedText = "No time saved or payment too low"; } doc.text(`Total Interest Saved: ${interestSavedVal === Infinity ? "Substantial (loan now payable)" : toCurrency(interestSavedVal)}`, 16, yPos); yPos += 6; doc.text(`Time Saved on Loan: ${timeSavedText}`, 16, yPos); yPos += 6; doc.save('mortgage_prepayment_analysis.pdf'); } // Initialize document.addEventListener('DOMContentLoaded', () => { mpbt_showTab(0); // Sample data could be set via input values in HTML or here for testing });