Business Loan Repayment Budget Planner

General Settings

Loan Details

No loans added yet. Click "Add Loan" to begin.

Repayment Summary & Projections

Complete loan data in Tab 2 to see the summary and projections.

No loans added. Please add loan details in Tab 2.

'; downloadPdfButton.disabled = true; return; } let combinedYearlyTotals = {}; // year: { payments, principal, interest } loansData.forEach(loan => { html += `

${loan.name}

`; const monthlyPayment = calculateMonthlyPayment(loan.principal, loan.annualRate, loan.termMonths); html += `

Calculated Monthly Payment (P&I): ${currency}${monthlyPayment.toFixed(2)}

`; const amortNoExtra = calculateAmortization(loan.principal, loan.annualRate, loan.termMonths, monthlyPayment, 0); html += `

Original Total Interest: ${currency}${amortNoExtra.totalInterestPaid.toFixed(2)} | Original Payoff: ${Math.ceil(amortNoExtra.monthsToPayOff / 12)} yrs ${Math.ceil(amortNoExtra.monthsToPayOff % 12)} mos

`; if (loan.extraMonthlyPayment > 0) { const amortWithExtra = calculateAmortization(loan.principal, loan.annualRate, loan.termMonths, monthlyPayment, loan.extraMonthlyPayment); html += `

Total Interest (with ${currency}${loan.extraMonthlyPayment.toFixed(2)} extra/mo): ${currency}${amortWithExtra.totalInterestPaid.toFixed(2)}

`; html += `

Est. Payoff (with extra): ${Math.floor(amortWithExtra.monthsToPayOff / 12)} yrs ${amortWithExtra.monthsToPayOff % 12} mos (Savings: ${amortNoExtra.monthsToPayOff - amortWithExtra.monthsToPayOff} mos)

`; } // Display yearly breakdown const displayAmort = loan.extraMonthlyPayment > 0 ? calculateAmortization(loan.principal, loan.annualRate, loan.termMonths, monthlyPayment, loan.extraMonthlyPayment) : amortNoExtra; let budgetHorizonYears = budgetHorizonOption === "0" ? Math.ceil(displayAmort.monthsToPayOff / 12) : parseInt(budgetHorizonOption); budgetHorizonYears = Math.min(budgetHorizonYears, 30); // Cap display for sanity html += ''; displayAmort.yearlyBreakdown.slice(0, budgetHorizonYears).forEach(yearData => { html += ``; // Aggregate for combined summary if (!combinedYearlyTotals[yearData.year]) { combinedYearlyTotals[yearData.year] = { payments: 0, principal: 0, interest: 0 }; } combinedYearlyTotals[yearData.year].payments += yearData.payments; combinedYearlyTotals[yearData.year].principal += yearData.principal; combinedYearlyTotals[yearData.year].interest += yearData.interest; }); html += `
YearTotal PaymentsPrincipal PaidInterest PaidEnding Balance
${yearData.year} ${currency}${yearData.payments.toFixed(2)} ${currency}${yearData.principal.toFixed(2)} ${currency}${yearData.interest.toFixed(2)} ${currency}${yearData.endBalance.toFixed(2)}
`; }); if (loansData.length > 1) { html += `

Combined Loan Projections

`; html += ``; let grandTotalPayments = 0, grandTotalPrincipal = 0, grandTotalInterest = 0; let maxYearCombined = 0; Object.keys(combinedYearlyTotals).forEach(yr => maxYearCombined = Math.max(maxYearCombined, parseInt(yr))); let budgetHorizonYearsCombined = budgetHorizonOption === "0" ? maxYearCombined : parseInt(budgetHorizonOption); budgetHorizonYearsCombined = Math.min(budgetHorizonYearsCombined, 30); for(let y = 1; y <= budgetHorizonYearsCombined; y++) { const yearData = combinedYearlyTotals[y] || { payments: 0, principal: 0, interest: 0 }; html += ``; grandTotalPayments += yearData.payments; grandTotalPrincipal += yearData.principal; grandTotalInterest += yearData.interest; } html += ``; html += `
YearTotal Combined PaymentsTotal Principal PaidTotal Interest Paid
${y} ${currency}${yearData.payments.toFixed(2)} ${currency}${yearData.principal.toFixed(2)} ${currency}${yearData.interest.toFixed(2)}
TOTALS ${currency}${grandTotalPayments.toFixed(2)} ${currency}${grandTotalPrincipal.toFixed(2)} ${currency}${grandTotalInterest.toFixed(2)}
`; } summaryOutput.innerHTML = html; downloadPdfButton.disabled = loansData.length === 0; } // PDF Download downloadPdfButton.addEventListener('click', function () { if (typeof jspdf === 'undefined' || typeof jspdf.jsPDF === 'undefined') { alert('Error: jsPDF library is not loaded.'); return; } const { jsPDF } = jspdf; const doc = new jsPDF('p'); const currency = currencySymbolInput.value || '$'; const budgetHorizonOption = document.getElementById('blrb-budget-horizon').value; const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--blrb-primary-color').trim(); const secondaryColor = getComputedStyle(document.documentElement).getPropertyValue('--blrb-secondary-color').trim(); const textColor = getComputedStyle(document.documentElement).getPropertyValue('--blrb-text-color').trim(); const buttonTextColor = getComputedStyle(document.documentElement).getPropertyValue('--blrb-button-text-color').trim(); doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text('Business Loan Repayment Plan', doc.internal.pageSize.getWidth() / 2, 20, { align: 'center' }); doc.setFontSize(12); doc.setTextColor(textColor); doc.text(`Business Name: ${document.getElementById('blrb-business-name').value || 'N/A'}`, 14, 30); doc.text(`Currency: ${currency}`, 14, 37); let budgetHorizonText = budgetHorizonOption === "0" ? "Full Loan Term (Max 30 Yrs Displayed)" : `${budgetHorizonOption} Years`; doc.text(`Budget Horizon: ${budgetHorizonText}`, 14, 44); let lastY = 55; const loansDataForPdf = []; // Collect all data before iterating for PDF document.querySelectorAll('.blrb-loan-item').forEach(item => { const termValue = getNum(item.querySelector('.blrb-loan-term-value').value); const termUnit = item.querySelector('.blrb-loan-term-unit').value; loansDataForPdf.push({ name: item.querySelector('.blrb-loan-name').value || `Loan ${item.dataset.loanId}`, principal: getNum(item.querySelector('.blrb-loan-principal').value), annualRate: getNum(item.querySelector('.blrb-loan-rate').value), termMonths: termUnit === 'Years' ? termValue * 12 : termValue, extraMonthlyPayment: getNum(item.querySelector('.blrb-loan-extra-payment').value) }); }); let combinedYearlyTotalsPdf = {}; loansDataForPdf.forEach(loan => { if (lastY > 250) { doc.addPage(); lastY = 20; } doc.setFontSize(14); doc.setTextColor(primaryColor); doc.text(loan.name, 14, lastY); lastY += 6; doc.setFontSize(10); doc.setTextColor(textColor); doc.text(`Principal: ${currency}${loan.principal.toFixed(2)}, Rate: ${loan.annualRate.toFixed(2)}%, Term: ${loan.termMonths} months`, 14, lastY); lastY += 5; if (loan.extraMonthlyPayment > 0) { doc.text(`Extra Monthly Payment: ${currency}${loan.extraMonthlyPayment.toFixed(2)}`, 14, lastY); lastY += 5; } const monthlyPayment = calculateMonthlyPayment(loan.principal, loan.annualRate, loan.termMonths); doc.text(`Calculated Monthly Payment (P&I): ${currency}${monthlyPayment.toFixed(2)}`, 14, lastY); lastY += 5; const amortNoExtra = calculateAmortization(loan.principal, loan.annualRate, loan.termMonths, monthlyPayment, 0); doc.text(`Original Total Interest: ${currency}${amortNoExtra.totalInterestPaid.toFixed(2)} | Original Payoff: ${Math.ceil(amortNoExtra.monthsToPayOff / 12)} yrs ${Math.ceil(amortNoExtra.monthsToPayOff % 12)} mos`, 14, lastY); lastY +=5; if (loan.extraMonthlyPayment > 0) { const amortWithExtra = calculateAmortization(loan.principal, loan.annualRate, loan.termMonths, monthlyPayment, loan.extraMonthlyPayment); doc.text(`Total Interest (with extra): ${currency}${amortWithExtra.totalInterestPaid.toFixed(2)} | Est. Payoff (with extra): ${Math.floor(amortWithExtra.monthsToPayOff / 12)} yrs ${amortWithExtra.monthsToPayOff % 12} mos`, 14, lastY); lastY += 7; } else { lastY +=2; // little less space if no extra payment info } const displayAmort = loan.extraMonthlyPayment > 0 ? calculateAmortization(loan.principal, loan.annualRate, loan.termMonths, monthlyPayment, loan.extraMonthlyPayment) : amortNoExtra; let budgetHorizonYears = budgetHorizonOption === "0" ? Math.ceil(displayAmort.monthsToPayOff / 12) : parseInt(budgetHorizonOption); budgetHorizonYears = Math.min(budgetHorizonYears, 30); const head = [['Year', 'Total Payments', 'Principal Paid', 'Interest Paid', 'Ending Balance']]; const body = []; displayAmort.yearlyBreakdown.slice(0, budgetHorizonYears).forEach(yearData => { body.push([ yearData.year.toString(), `${currency}${yearData.payments.toFixed(2)}`, `${currency}${yearData.principal.toFixed(2)}`, `${currency}${yearData.interest.toFixed(2)}`, `${currency}${yearData.endBalance.toFixed(2)}` ]); // Aggregate for combined summary if (!combinedYearlyTotalsPdf[yearData.year]) { combinedYearlyTotalsPdf[yearData.year] = { payments: 0, principal: 0, interest: 0 }; } combinedYearlyTotalsPdf[yearData.year].payments += yearData.payments; combinedYearlyTotalsPdf[yearData.year].principal += yearData.principal; combinedYearlyTotalsPdf[yearData.year].interest += yearData.interest; }); doc.autoTable({ startY: lastY, head: head, body: body, theme: 'grid', headStyles: {fillColor: secondaryColor, textColor: buttonTextColor, fontSize:9}, styles:{fontSize:8, cellPadding:1.5}, columnStyles: {0:{halign:'center'},1:{halign:'right'},2:{halign:'right'},3:{halign:'right'},4:{halign:'right'}}}); lastY = doc.lastAutoTable.finalY + 10; }); if (loansDataForPdf.length > 1) { if (lastY > 250) { doc.addPage(); lastY = 20; } doc.setFontSize(14); doc.setTextColor(primaryColor); doc.text('Combined Loan Projections', 14, lastY); lastY += 7; const combinedHead = [['Year', 'Total Combined Payments', 'Total Principal Paid', 'Total Interest Paid']]; const combinedBody = []; let grandTotalPaymentsPdf = 0, grandTotalPrincipalPdf = 0, grandTotalInterestPdf = 0; let maxYearCombinedPdf = 0; Object.keys(combinedYearlyTotalsPdf).forEach(yr => maxYearCombinedPdf = Math.max(maxYearCombinedPdf, parseInt(yr))); let budgetHorizonYearsCombinedPdf = budgetHorizonOption === "0" ? maxYearCombinedPdf : parseInt(budgetHorizonOption); budgetHorizonYearsCombinedPdf = Math.min(budgetHorizonYearsCombinedPdf, 30); for(let y = 1; y <= budgetHorizonYearsCombinedPdf; y++) { const yearData = combinedYearlyTotalsPdf[y] || { payments: 0, principal: 0, interest: 0 }; combinedBody.push([ y.toString(), `${currency}${yearData.payments.toFixed(2)}`, `${currency}${yearData.principal.toFixed(2)}`, `${currency}${yearData.interest.toFixed(2)}` ]); grandTotalPaymentsPdf += yearData.payments; grandTotalPrincipalPdf += yearData.principal; grandTotalInterestPdf += yearData.interest; } combinedBody.push([ // Grand Total Row {content: 'TOTALS', styles: {fontStyle: 'bold', fillColor: primaryColor, textColor: buttonTextColor, halign: 'center'}}, {content: `${currency}${grandTotalPaymentsPdf.toFixed(2)}`, styles: {fontStyle: 'bold', fillColor: primaryColor, textColor: buttonTextColor, halign: 'right'}}, {content: `${currency}${grandTotalPrincipalPdf.toFixed(2)}`, styles: {fontStyle: 'bold', fillColor: primaryColor, textColor: buttonTextColor, halign: 'right'}}, {content: `${currency}${grandTotalInterestPdf.toFixed(2)}`, styles: {fontStyle: 'bold', fillColor: primaryColor, textColor: buttonTextColor, halign: 'right'}} ]); doc.autoTable({ startY: lastY, head: combinedHead, body: combinedBody, theme: 'grid', headStyles: {fillColor: secondaryColor, textColor: buttonTextColor, fontSize:9}, styles:{fontSize:8, cellPadding:1.5}, columnStyles: {0:{halign:'center'},1:{halign:'right'},2:{halign:'right'},3:{halign:'right'}}}); } doc.save(`Business_Loan_Repayment_Plan_${document.getElementById('blrb-business-name').value.replace(/\s+/g, '_') || 'Report'}.pdf`); }); checkEmptyState('#blrb-loans-container', 'blrb-no-items-text'); showTab(0); updateAllCurrencyPrefixes(); });
Scroll to Top