Personal Loan Repayment Budgeting Tool

Loan Details

Format: YYYY-MM-DD. If blank, calculations use today.

Accelerated Repayment (Optional)

Enter 0 if no lump sum payment.

Repayment Analysis

Amortization Schedule

Calculate a plan to see the schedule.

Loan Payoff Time: ${Math.floor(planData.payoffTimeMonths / 12)} yrs, ${planData.payoffTimeMonths % 12} mths (${planData.payoffTimeMonths} mths)

`; summaryHTML += `

Total Interest Paid: $${planData.totalInterest.toFixed(2)}

`; summaryHTML += `

Total Amount Paid: $${planData.totalAmount.toFixed(2)}

`; summaryHTML += `

Estimated Payoff Date: ${planData.payoffDate}

`; if (standardPlanForComparison && planData.interestSaved !== undefined) { summaryHTML += `

Savings Compared to Standard Plan:

`; summaryHTML += `

Interest Saved: $${planData.interestSaved.toFixed(2)}

`; const timeSavedY = Math.floor(planData.timeSavedMonths / 12); const timeSavedM = planData.timeSavedMonths % 12; summaryHTML += `

Time Saved: ${timeSavedY} yrs, ${timeSavedM} mths (${planData.timeSavedMonths} mths)

`; } summaryHTML += `
`; if (elementId === 'standardPlanResults') { // Main container for potentially two summaries let comparisonHTML = summaryHTML; // Start with standard if (document.getElementById('acceleratedPlanResults').style.display === 'block' && standardPlanForComparison === null) { // This means we're calling for accelerated, so standard is already there. // The structure is for standardPlanResults to hold standard, acceleratedPlanResults to hold accelerated } container.innerHTML = comparisonHTML; } else { // This is for accelerated plan specifically container.innerHTML = summaryHTML; } // If standardPlanResults is being updated, and there's an accelerated plan, it should be in its own div if (elementId === 'standardPlanResults' && loanAnalysisData.acceleratedPlan && standardPlanForComparison === null) { // Standard plan is displayed in standardPlanResults. // Accelerated plan will be (re)displayed by its own call to displayPlanSummary. } else if (elementId === 'acceleratedPlanResults') { //This ensures the comparison section properly wraps both if accelerated plan exists document.getElementById('standardPlanResults').innerHTML = loanAnalysisData.standardPlan ? displayPlanSummaryHTML(loanAnalysisData.standardPlan, "Standard Repayment Plan") : ''; container.innerHTML = displayPlanSummaryHTML(planData, title, loanAnalysisData.standardPlan); // Wrap both in the comparison section div const finalLayout = `
${document.getElementById('standardPlanResults').innerHTML}${container.innerHTML}
`; document.getElementById('resultsContainer').querySelector('h3').insertAdjacentHTML('afterend', finalLayout); // Clear the individual containers as they are now part of comparison-section document.getElementById('standardPlanResults').innerHTML = ''; document.getElementById('acceleratedPlanResults').innerHTML = ''; } else if (elementId === 'standardPlanResults' && !loanAnalysisData.acceleratedPlan) { // Only standard plan container.innerHTML = `
${summaryHTML}
`; } } // Helper function to return HTML string for plan summary, to manage layout better function displayPlanSummaryHTML(planData, title, standardPlanForComparison = null) { let summaryHTML = `
${title}
`; const baseEMI = loanAnalysisData.standardPlan ? loanAnalysisData.standardPlan.monthlyEMI : planData.monthlyEMI; const currentExtraPayment = (planData.effectiveMonthlyPayment && baseEMI) ? planData.effectiveMonthlyPayment - baseEMI : 0; summaryHTML += `

Monthly Payment: $${(planData.effectiveMonthlyPayment || planData.monthlyEMI).toFixed(2)}

`; if(title.includes("Accelerated") && currentExtraPayment > 0) { summaryHTML += `

(Std EMI: $${baseEMI.toFixed(2)} + Extra: $${currentExtraPayment.toFixed(2)})

`; } if(title.includes("Accelerated") && planData.lumpSumAmount > 0) { summaryHTML += `

(Incl. Lump Sum of $${planData.lumpSumAmount.toFixed(2)} in month ${planData.lumpSumMonth})

`; } summaryHTML += `

Loan Payoff Time: ${Math.floor(planData.payoffTimeMonths / 12)} yrs, ${planData.payoffTimeMonths % 12} mths (${planData.payoffTimeMonths} mths)

`; summaryHTML += `

Total Interest Paid: $${planData.totalInterest.toFixed(2)}

`; summaryHTML += `

Total Amount Paid: $${planData.totalAmount.toFixed(2)}

`; summaryHTML += `

Estimated Payoff Date: ${planData.payoffDate}

`; if (standardPlanForComparison && planData.interestSaved !== undefined) { summaryHTML += `
`; summaryHTML += `

Savings Achieved:

`; summaryHTML += `

Interest Saved: $${planData.interestSaved.toFixed(2)}

`; const timeSavedY = Math.floor(planData.timeSavedMonths / 12); const timeSavedM = planData.timeSavedMonths % 12; summaryHTML += `

Time Saved: ${timeSavedY} yr${timeSavedY !== 1 ? 's' : ''}, ${timeSavedM} mth${timeSavedM !== 1 ? 's' : ''} (${planData.timeSavedMonths} mths)

`; } summaryHTML += `
`; return summaryHTML; } function displayAmortizationTable(schedule) { const container = document.getElementById('amortizationTableContainer'); if (!schedule || schedule.length === 0) { container.innerHTML = "

No schedule data available.

"; return; } let tableHTML = ``; schedule.forEach(row => { tableHTML += ``; }); tableHTML += `
Month Beginning Balance Payment Interest Principal Lump Sum Ending Balance
${row.month} $${row.beginningBalance.toFixed(2)} $${row.payment.toFixed(2)} $${row.interest.toFixed(2)} $${row.principal.toFixed(2)} $${row.lumpSum.toFixed(2)} $${row.endingBalance.toFixed(2)}
`; container.innerHTML = tableHTML; } function downloadLoanPdf() { if (!loanAnalysisData.standardPlan) { alert("Please calculate a plan first."); return; } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF generation library (jsPDF) is not loaded.'); return; } const jsPDFConstructor = window.jspdf.jsPDF; const doc = new jsPDFConstructor(); if (typeof doc.autoTable !== 'function') { alert('jsPDF AutoTable plugin not loaded.'); return; } const primaryColor = '#007bff'; textColor = '#212529', tableHeaderColor = '#e9ecef'; let yPos = 22; doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Personal Loan Repayment Plan", 14, yPos); yPos += 8; doc.setFontSize(10); doc.setTextColor(textColor); doc.text(`Report Date: ${new Date().toLocaleDateString()}`, 14, yPos); yPos += 10; // Loan Inputs doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Loan Inputs", 14, yPos); yPos += 6; const inputsBody = [ ['Loan Amount:', `$${loanAnalysisData.standardPlan.principal.toFixed(2)}`], ['Annual Interest Rate:', `${loanAnalysisData.standardPlan.annualRate.toFixed(2)}%`], ['Loan Term:', `${loanAnalysisData.standardPlan.termYears} years (${loanAnalysisData.standardPlan.termYears * 12} months)`], ['Loan Start Date:', loanAnalysisData.standardPlan.startDateStr || 'Not specified'] ]; if(loanAnalysisData.acceleratedPlan){ inputsBody.push(['Extra Monthly Payment:', `$${(document.getElementById('extraMonthlyPayment').valueAsNumber || 0).toFixed(2)}`]); if((document.getElementById('lumpSumAmount').valueAsNumber || 0) > 0) { inputsBody.push(['Lump Sum Payment:', `$${(document.getElementById('lumpSumAmount').valueAsNumber).toFixed(2)} (in month ${(document.getElementById('lumpSumMonth').valueAsNumber)})`]); } } doc.autoTable({ startY: yPos, body: inputsBody, theme: 'plain', styles: {fontSize:9}, columnStyles: {0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 10; // Plan Summaries function addPlanSummaryToPdf(plan, title) { doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text(title, 14, yPos); yPos +=6; const baseEMI_pdf = loanAnalysisData.standardPlan ? loanAnalysisData.standardPlan.monthlyEMI : plan.monthlyEMI; const extraPay_pdf = (plan.effectiveMonthlyPayment && baseEMI_pdf) ? plan.effectiveMonthlyPayment - baseEMI_pdf : 0; let planBody = [ ['Monthly Payment:', `$${(plan.effectiveMonthlyPayment || plan.monthlyEMI).toFixed(2)}`], ]; if(title.includes("Accelerated") && extraPay_pdf > 0) { planBody.push(['Breakdown:', `(Std EMI: $${baseEMI_pdf.toFixed(2)} + Extra: $${extraPay_pdf.toFixed(2)})`]); } if(title.includes("Accelerated") && plan.lumpSumAmount > 0) { planBody.push(['Lump Sum:', `$${plan.lumpSumAmount.toFixed(2)} (Month ${plan.lumpSumMonth})`]); } planBody.push(...[ ['Payoff Time:', `${Math.floor(plan.payoffTimeMonths / 12)} yrs, ${plan.payoffTimeMonths % 12} mths (${plan.payoffTimeMonths} mths)`], ['Total Interest Paid:', `$${plan.totalInterest.toFixed(2)}`], ['Total Amount Paid:', `$${plan.totalAmount.toFixed(2)}`], ['Est. Payoff Date:', plan.payoffDate] ]); if(plan.interestSaved !== undefined) { planBody.push(['--- Savings ---', '']); planBody.push(['Interest Saved:', `$${plan.interestSaved.toFixed(2)}`]); planBody.push(['Time Saved:', `${Math.floor(plan.timeSavedMonths / 12)} yrs, ${plan.timeSavedMonths % 12} mths`]); } doc.autoTable({startY: yPos, body: planBody, theme:'plain', styles:{fontSize:9}, columnStyles: {0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 10; } addPlanSummaryToPdf(loanAnalysisData.standardPlan, "Standard Repayment Plan"); if(loanAnalysisData.acceleratedPlan){ if (yPos > 250) { doc.addPage(); yPos = 20; } addPlanSummaryToPdf(loanAnalysisData.acceleratedPlan, "Accelerated Repayment Plan"); } // Amortization Schedule const scheduleToUse = loanAnalysisData.acceleratedPlan ? loanAnalysisData.acceleratedPlan.schedule : loanAnalysisData.standardPlan.schedule; const scheduleTitle = loanAnalysisData.acceleratedPlan ? "Amortization Schedule (Accelerated Plan)" : "Amortization Schedule (Standard Plan)"; if (yPos > 240) { doc.addPage(); yPos = 20; } // Check space before starting table doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text(scheduleTitle, 14, yPos); yPos += 6; const scheduleBody = scheduleToUse.map(row => [ row.month, `$${row.beginningBalance.toFixed(2)}`, `$${row.payment.toFixed(2)}`, `$${row.interest.toFixed(2)}`, `$${row.principal.toFixed(2)}`, `$${row.lumpSum.toFixed(2)}`, `$${row.endingBalance.toFixed(2)}` ]); doc.autoTable({ startY: yPos, head: [['Month', 'Beginning Bal.', 'Payment', 'Interest', 'Principal', 'Lump Sum', 'Ending Bal.']], body: scheduleBody, theme: 'grid', headStyles: { fillColor: tableHeaderColor, textColor: textColor, fontStyle: 'bold', fontSize:8 }, styles: { fontSize: 7, cellPadding: 1.2, halign: 'right' }, columnStyles: { 0: {halign: 'center'} } }); doc.save("Loan_Repayment_Plan.pdf"); } // Initial call to set up tab navigation button states updateLoanNavButtons();
Scroll to Top