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");
}