Installment Payment Plan Calculator

Installment Payment Plan Calculator

Calculate payments and generate a detailed amortization schedule.

Fill out the form and click calculate.

`; document.getElementById('calculator-form').addEventListener('submit', handleCalculation); }; const handleCalculation = (e) => { e.preventDefault(); // 1. Gather Inputs const purchaseAmount = parseFloat(document.getElementById('purchase-amount').value); const downPayment = parseFloat(document.getElementById('down-payment').value); const annualRate = parseFloat(document.getElementById('interest-rate').value); let loanTerm = parseInt(document.getElementById('loan-term').value); const termUnit = document.getElementById('term-unit').value; const startDate = new Date(document.getElementById('start-date').value); if (isNaN(purchaseAmount) || isNaN(annualRate) || isNaN(loanTerm) || !startDate) { alert('Please fill in all fields with valid values.'); return; } // Store inputs for PDF inputs = { purchaseAmount, downPayment, annualRate, loanTerm, termUnit, startDate }; // 2. Calculate Principal let basePrincipal = purchaseAmount - downPayment; let totalFees = 0; appData.fees.forEach(fee => { if (fee.enabled) { if (fee.type === 'fixed') { totalFees += fee.value; } else if (fee.type === 'percent') { totalFees += basePrincipal * (fee.value / 100); } } }); const principal = basePrincipal + totalFees; // 3. Calculate Payment const monthlyRate = (annualRate / 100) / 12; const numberOfMonths = termUnit === 'years' ? loanTerm * 12 : loanTerm; if(monthlyRate === 0) { // Simple interest-free calculation monthlyPayment = principal / numberOfMonths; } else { monthlyPayment = principal * (monthlyRate * Math.pow(1 + monthlyRate, numberOfMonths)) / (Math.pow(1 + monthlyRate, numberOfMonths) - 1); } if (!isFinite(monthlyPayment)) { alert("Could not calculate payment. Please check your inputs."); return; } // 4. Generate Amortization Schedule let balance = principal; let totalInterest = 0; const schedule = []; for (let i = 1; i <= numberOfMonths; i++) { const interestPaid = balance * monthlyRate; const principalPaid = monthlyPayment - interestPaid; balance -= principalPaid; totalInterest += interestPaid; let paymentDate = new Date(startDate); paymentDate.setMonth(startDate.getMonth() + i - 1); schedule.push({ paymentNumber: i, paymentDate: formatDate(paymentDate), paymentAmount: monthlyPayment, principalPaid, interestPaid, remainingBalance: Math.abs(balance) < 0.01 ? 0 : balance, // handle floating point inaccuracies }); } const payoffDate = new Date(startDate); payoffDate.setMonth(startDate.getMonth() + numberOfMonths - 1); calculationResult = { monthlyPayment, totalPrincipal: principal, totalInterest, totalCost: principal + totalInterest, payoffDate: formatDate(payoffDate), schedule, totalFees }; renderResults(); }; const renderResults = () => { const resultsContainer = document.getElementById('results-container'); if (!calculationResult) return; resultsContainer.innerHTML = `

Payment Summary

Monthly Payment

${formatCurrency(calculationResult.monthlyPayment)}

Total Interest Paid

${formatCurrency(calculationResult.totalInterest)}

Final Payoff Date

${calculationResult.payoffDate}

Amortization Schedule

${calculationResult.schedule.map(row => ` `).join('')}
# Date Principal Interest Balance
${row.paymentNumber} ${row.paymentDate} ${formatCurrency(row.principalPaid)} ${formatCurrency(row.interestPaid)} ${formatCurrency(row.remainingBalance)}
`; document.getElementById('download-pdf-btn').addEventListener('click', generatePdf); }; const renderConfig = () => { const configContent = document.getElementById('content-config'); if (!configContent) return; const feesHtml = appData.fees.map((fee, index) => `
`).join(''); configContent.innerHTML = `

Configure Additional Fees

${feesHtml}
`; document.getElementById('fee-config-form').addEventListener('submit', handleConfigUpdate); }; const handleConfigUpdate = (e) => { e.preventDefault(); const newFees = []; document.querySelectorAll('.fee-row').forEach(row => { newFees.push({ name: row.querySelector('[data-field="name"]').value, type: row.querySelector('[data-field="type"]').value, value: parseFloat(row.querySelector('[data-field="value"]').value), enabled: row.querySelector('[data-field="enabled"]').checked }); }); appData.fees = newFees; alert('Fee configuration saved! Your next calculation will include these changes.'); }; const generatePdf = () => { if (!calculationResult) return; loadingOverlay.style.display = 'flex'; const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); // --- Add Content to PDF --- let y = 40; // Title pdf.setFontSize(18); pdf.setFont('helvetica', 'bold'); pdf.text('Installment Payment Plan Report', pdf.internal.pageSize.getWidth() / 2, y, { align: 'center' }); y += 30; // Summary section pdf.setFontSize(10); pdf.setFont('helvetica', 'normal'); pdf.text(`Generated on: ${new Date().toLocaleDateString()}`, 40, y); y += 30; pdf.setFontSize(12); pdf.setFont('helvetica', 'bold'); pdf.text('Loan Summary', 40, y); y += 20; pdf.setFontSize(10); pdf.setFont('helvetica', 'normal'); const summaryData = [ ['Purchase Amount:', formatCurrency(inputs.purchaseAmount)], ['Down Payment:', formatCurrency(inputs.downPayment)], ['Additional Fees:', formatCurrency(calculationResult.totalFees)], ['Total Principal:', formatCurrency(calculationResult.totalPrincipal)], ['Annual Interest Rate:', `${inputs.annualRate.toFixed(2)}%`], ['Loan Term:', `${inputs.loanTerm} ${inputs.termUnit}`], ['Monthly Payment:', formatCurrency(calculationResult.monthlyPayment)], ['Total Interest:', formatCurrency(calculationResult.totalInterest)], ['Payoff Date:', calculationResult.payoffDate] ]; summaryData.forEach(row => { pdf.setFont('helvetica', 'bold'); pdf.text(row[0], 50, y); pdf.setFont('helvetica', 'normal'); pdf.text(row[1], 200, y); y += 15; }); y += 20; // Amortization Table pdf.setFontSize(12); pdf.setFont('helvetica', 'bold'); pdf.text('Amortization Schedule', 40, y); y += 20; pdf.autoTable({ startY: y, head: [['#', 'Date', 'Principal', 'Interest', 'Balance']], body: calculationResult.schedule.map(row => [ row.paymentNumber, row.paymentDate, formatCurrency(row.principalPaid), formatCurrency(row.interestPaid), formatCurrency(row.remainingBalance) ]), theme: 'grid', headStyles: { fillColor: [22, 163, 74] }, // Green header styles: { fontSize: 8 }, }); pdf.save(`Payment-Plan-Report.pdf`); loadingOverlay.style.display = 'none'; }; // --- TAB NAVIGATION & INITIALIZATION --- const switchTab = (tabIndex) => { activeTabIndex = tabIndex; document.querySelectorAll('.tab-btn').forEach((btn, i) => btn.classList.toggle('active', i === tabIndex)); document.querySelectorAll('.tab-content').forEach((content, i) => content.classList.toggle('hidden', i !== tabIndex)); updateNavButtons(); }; const updateNavButtons = () => { prevTabBtn.disabled = activeTabIndex === 0; nextTabBtn.disabled = activeTabIndex === tabIdentifiers.length - 1; }; const initializeUI = () => { const tabs = [ { name: 'Payment Calculator', id: 'calculator' }, { name: 'Fee Configuration', id: 'config' } ]; tabIdentifiers = tabs.map(t => t.id); tabsContainer.innerHTML = tabs.map(tab => ``).join(''); mainContent.innerHTML = tabs.map(tab => `
`).join(''); tabs.forEach((tab, index) => { document.getElementById(`tab-${tab.id}`).addEventListener('click', () => switchTab(index)); }); renderCalculator(); renderConfig(); switchTab(0); lucide.createIcons(); }; initializeUI(); // Load jsPDF autoTable plugin const autoTableScript = document.createElement('script'); autoTableScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.23/jspdf.plugin.autotable.min.js'; document.head.appendChild(autoTableScript); prevTabBtn.addEventListener('click', () => { if (activeTabIndex > 0) switchTab(activeTabIndex - 1); }); nextTabBtn.addEventListener('click', () => { if (activeTabIndex < tabIdentifiers.length - 1) switchTab(activeTabIndex + 1); }); });
Scroll to Top