Business Loan Early Payoff Calculator

Step 1: Enter Your Loan Details

Step 2: Define Your Early Payoff Strategy

Enter 0 if you don't plan to make additional monthly payments.

Step 3: View Your Results

Amortization Schedules

Original Loan Amortization

Month Payment Date Payment Principal Interest Balance

Total Principal Paid: ${blc_formatCurrency(data.loanAmount)}

Total Interest Paid: ${blc_formatCurrency(data.originalTotalInterest)}

Total Paid: ${blc_formatCurrency(data.originalTotalPaid)}

Payoff Time: ${originalPayoffTermStr}

Payoff Date: ${data.originalPayoffDate || 'N/A'}

Accelerated Loan (with early payoff)

Intended Monthly Payment: ${blc_formatCurrency(data.actualAcceleratedMonthlyPayment)}

Total Principal Paid: ${blc_formatCurrency(data.loanAmount)}

Total Interest Paid: ${blc_formatCurrency(data.acceleratedTotalInterest)}

Total Paid: ${blc_formatCurrency(data.acceleratedTotalPaid)}

Payoff Time: ${acceleratedPayoffTermStr}

Payoff Date: ${data.acceleratedPayoffDate || 'N/A'}

Your Savings

Interest Saved: ${blc_formatCurrency(data.interestSaved)}

Time Saved: ${data.timeSavedStr}

`; blc_populateAmortizationTable('blc-original-amortization-table', data.originalSchedule, false); blc_populateAmortizationTable('blc-accelerated-amortization-table', data.acceleratedSchedule, true); // Reset amortization toggle to show original first const origAmortButton = document.getElementById('blc-show-original-amortization'); if (origAmortButton) origAmortButton.click(); } function blc_populateAmortizationTable(tableId, schedule, isAccelerated) { const tableBody = document.getElementById(tableId)?.getElementsByTagName('tbody')[0]; if (!tableBody) { console.error("BLC Error: Table body not found for ID:", tableId); return; } tableBody.innerHTML = ''; // Clear previous rows schedule.forEach(row => { const tr = tableBody.insertRow(); tr.insertCell().textContent = row.month; tr.insertCell().textContent = row.date; // Already formatted by blc_generateAmortizationSchedule tr.insertCell().textContent = blc_formatCurrency(row.payment); tr.insertCell().textContent = blc_formatCurrency(row.principal); tr.insertCell().textContent = blc_formatCurrency(row.interest); if (isAccelerated) { tr.insertCell().textContent = blc_formatCurrency(row.additional); } tr.insertCell().textContent = blc_formatCurrency(row.balance); }); } function blc_generatePDF() { // 1. Check if the main jsPDF library namespace and its constructor are available if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF generation library (jsPDF) is not loaded. Please check your internet connection or contact support.'); console.error('BLC Error: window.jspdf or window.jspdf.jsPDF is not defined.'); const errorEl = document.getElementById('blc-tab2-error'); if (errorEl) errorEl.textContent = 'Error: PDF library (jsPDF) not loaded.'; return; } const JSPDF_CONSTRUCTOR = window.jspdf.jsPDF; // Get the jsPDF constructor // 2. Check if the autoTable plugin is available. // The autoTable plugin adds itself to the jsPDF prototype. // We create a temporary instance to check if .autoTable method exists. const tempDoc = new JSPDF_CONSTRUCTOR(); if (typeof tempDoc.autoTable !== 'function') { alert('jsPDF AutoTable plugin is not loaded or not attached correctly. Please check your internet connection or contact support.'); console.error('BLC Error: autoTable function not found on jsPDF instance. Ensure jspdf.plugin.autotable.js is loaded after jspdf.js.'); const errorEl = document.getElementById('blc-tab2-error'); if (errorEl) errorEl.textContent = 'Error: PDF AutoTable plugin not loaded.'; return; } if (Object.keys(blc_loanData).length === 0) { alert('Please calculate the loan details first before downloading PDF.'); const errorEl = document.getElementById('blc-tab2-error'); if (errorEl) errorEl.textContent = 'Calculate results first to generate PDF.'; return; } const errorElPdf = document.getElementById('blc-tab2-error'); // Renamed to avoid conflict in scope if (errorElPdf) errorElPdf.textContent = ''; // Clear previous errors const doc = new JSPDF_CONSTRUCTOR(); // Create the actual document instance const cellColor = '#007bff'; const textColor = '#ffffff'; const headingColor = '#0056b3'; let yPos = 15; doc.setFontSize(18); doc.setTextColor(headingColor); doc.text("Business Loan Early Payoff Report", 105, yPos, { align: 'center' }); yPos += 10; doc.setFontSize(12); doc.setTextColor(50); // Input Summary doc.setFontSize(14); doc.setTextColor(headingColor); doc.text("Loan Inputs", 14, yPos); yPos += 6; doc.setFontSize(10); doc.setTextColor(50); const inputDataForPdf = [ ["Loan Amount:", blc_formatCurrency(blc_loanData.loanAmount)], ["Annual Interest Rate:", `${blc_loanData.annualInterestRate.toFixed(2)}%`], ["Original Loan Term:", `${blc_loanData.loanTermYears} years`], ["Loan Start Date:", blc_loanData.startDateString ? blc_formatDate(blc_loanData.startDateString) : 'N/A'], // Use blc_formatDate for consistency ["Additional Monthly Payment:", blc_formatCurrency(blc_loanData.additionalMonthlyPayment)] ]; doc.autoTable({ startY: yPos, body: inputDataForPdf, theme: 'plain', styles: { fontSize: 10, cellPadding: 1.5 }, columnStyles: { 0: { fontStyle: 'bold' } } }); yPos = doc.lastAutoTable.finalY + 10; // Results Summary Section doc.setFontSize(14); doc.setTextColor(headingColor); doc.text("Results Summary", 14, yPos); yPos += 8; const originalPayoffTermStrPdf = `${Math.floor(blc_loanData.originalPayoffMonths / 12)} years, ${blc_loanData.originalPayoffMonths % 12} months`; let acceleratedPayoffTermStrPdf = originalPayoffTermStrPdf; if(blc_loanData.additionalMonthlyPayment > 0 || blc_loanData.annualInterestRate === 0) { acceleratedPayoffTermStrPdf = `${Math.floor(blc_loanData.acceleratedPayoffMonths / 12)} years, ${blc_loanData.acceleratedPayoffMonths % 12} months`; } const summaryDataForPdf = [ [{ content: 'Original Loan Details', colSpan: 2, styles: { fontStyle: 'bold', fillColor: cellColor, textColor: textColor, halign: 'center' } }], ["Monthly Payment:", blc_formatCurrency(blc_loanData.originalMonthlyPayment)], ["Total Interest Paid:", blc_formatCurrency(blc_loanData.originalTotalInterest)], ["Total Paid:", blc_formatCurrency(blc_loanData.originalTotalPaid)], ["Payoff Time:", originalPayoffTermStrPdf], ["Payoff Date:", blc_loanData.originalPayoffDate || 'N/A'], [{ content: 'Accelerated Loan Details (with early payoff)', colSpan: 2, styles: { fontStyle: 'bold', fillColor: cellColor, textColor: textColor, halign: 'center' } }], ["Intended Monthly Payment:", blc_formatCurrency(blc_loanData.actualAcceleratedMonthlyPayment)], ["Total Interest Paid:", blc_formatCurrency(blc_loanData.acceleratedTotalInterest)], ["Total Paid:", blc_formatCurrency(blc_loanData.acceleratedTotalPaid)], ["Payoff Time:", acceleratedPayoffTermStrPdf], ["Payoff Date:", blc_loanData.acceleratedPayoffDate || 'N/A'], [{ content: 'Savings', colSpan: 2, styles: { fontStyle: 'bold', fillColor: '#28a745', textColor: textColor, halign: 'center' } }], ["Interest Saved:", blc_formatCurrency(blc_loanData.interestSaved)], ["Time Saved:", blc_loanData.timeSavedStr] ]; doc.autoTable({ startY: yPos, body: summaryDataForPdf, theme: 'grid', styles: { fontSize: 10, cellPadding: 2 }, columnStyles: { 0: { fontStyle: 'bold', cellWidth: 'auto'}, 1: {cellWidth: 'auto'} }, didParseCell: function (data) { if (data.cell.raw?.hasOwnProperty('styles')) { Object.assign(data.cell.styles, data.cell.raw.styles); } } }); yPos = doc.lastAutoTable.finalY + 10; // Original Amortization Schedule if (blc_loanData.originalSchedule && blc_loanData.originalSchedule.length > 0) { if (yPos > 220 ) { doc.addPage(); yPos = 15; } else { yPos += 5; } doc.setFontSize(14); doc.setTextColor(headingColor); doc.text("Original Amortization Schedule", 14, yPos); yPos += 8; const originalBodyForPdf = blc_loanData.originalSchedule.map(row => [ row.month, row.date, blc_formatCurrency(row.payment), blc_formatCurrency(row.principal), blc_formatCurrency(row.interest), blc_formatCurrency(row.balance) ]); doc.autoTable({ startY: yPos, head: [['Month', 'Date', 'Payment', 'Principal', 'Interest', 'Balance']], body: originalBodyForPdf, theme: 'grid', headStyles: { fillColor: cellColor, textColor: textColor, fontStyle: 'bold' }, styles: { fontSize: 8, cellPadding: 1.5 }, columnStyles: { 0: { halign: 'center' }, 1: {halign: 'left'}, 2: { halign: 'right' }, 3: { halign: 'right' }, 4: { halign: 'right' }, 5: { halign: 'right' } } }); yPos = doc.lastAutoTable.finalY + 10; } // Accelerated Amortization Schedule if (blc_loanData.acceleratedSchedule && blc_loanData.acceleratedSchedule.length > 0 && (blc_loanData.additionalMonthlyPayment > 0 || blc_loanData.annualInterestRate === 0)) { if (yPos > 220) { doc.addPage(); yPos = 15; } else { yPos += 5; } doc.setFontSize(14); doc.setTextColor(headingColor); doc.text("Accelerated Amortization Schedule", 14, yPos); yPos += 8; const acceleratedBodyForPdf = blc_loanData.acceleratedSchedule.map(row => [ row.month, row.date, blc_formatCurrency(row.payment), blc_formatCurrency(row.principal), blc_formatCurrency(row.interest), blc_formatCurrency(row.additional), blc_formatCurrency(row.balance) ]); doc.autoTable({ startY: yPos, head: [['Month', 'Date', 'Total Payment', 'Principal', 'Interest', 'Additional', 'Balance']], body: acceleratedBodyForPdf, theme: 'grid', headStyles: { fillColor: cellColor, textColor: textColor, fontStyle: 'bold' }, styles: { fontSize: 8, cellPadding: 1.5 }, columnStyles: { 0: { halign: 'center' }, 1: {halign: 'left'}, 2: { halign: 'right' }, 3: { halign: 'right' }, 4: { halign: 'right' }, 5: { halign: 'right' }, 6: { halign: 'right' } } }); } doc.save("Business_Loan_Early_Payoff_Report.pdf"); }
Scroll to Top