`;
// Revenue Section
html += `
Revenue
`; data.revenues.forEach(item => { if (item.description || item.amount > 0) html += `${item.description}${formatCurrency(item.amount || 0)}
`;
});
html += `Total Revenue${formatCurrency(totalRevenue)}
`;
// Expenses Section
html += `Expenses
`; data.expenses.forEach(item => { if (item.description || item.amount > 0) html += `${item.description}${formatCurrency(item.amount || 0)}
`;
});
html += `Total Expenses${formatCurrency(totalExpenses)}
`;
// Net Profit
html += `
Net Profit${formatCurrency(netProfit)}
`;
preview.innerHTML = html;
}
function updateData(e) {
const id = parseInt(e.target.parentElement.dataset.id);
const type = e.target.dataset.type;
const isAmount = e.target.classList.contains('amount-input');
const value = isAmount ? parseFloat(e.target.value) : e.target.value;
const key = isAmount ? 'amount' : 'description';
const item = data[type].find(i => i.id === id);
if (item) {
item[key] = value;
}
renderPreview();
}
function handleGeneralInput(e) {
data[e.target.id.replace(/-/g, '')] = e.target.value;
renderPreview();
}
// --- Event Listeners ---
document.getElementById('add-revenue-btn').addEventListener('click', () => {
data.revenues.push({ id: Date.now(), description: '', amount: 0 });
renderInputs();
});
document.getElementById('add-expense-btn').addEventListener('click', () => {
data.expenses.push({ id: Date.now(), description: '', amount: 0 });
renderInputs();
});
['revenue-items', 'expense-items'].forEach(id => {
document.getElementById(id).addEventListener('input', updateData);
document.getElementById(id).addEventListener('click', (e) => {
if (e.target.classList.contains('remove-btn')) {
const id = parseInt(e.target.parentElement.dataset.id);
const type = e.target.parentElement.querySelector('input').dataset.type;
data[type] = data[type].filter(item => item.id !== id);
renderInputs();
renderPreview();
}
});
});
document.getElementById('company-name').addEventListener('input', handleGeneralInput);
document.getElementById('statement-period').addEventListener('input', handleGeneralInput);
document.getElementById('download-pdf-btn').addEventListener('click', () => {
const { jsPDF } = window.jspdf;
const pdf = new jsPDF();
const totalRevenue = data.revenues.reduce((sum, item) => sum + (item.amount || 0), 0);
const totalExpenses = data.expenses.reduce((sum, item) => sum + (item.amount || 0), 0);
const netProfit = totalRevenue - totalExpenses;
pdf.setFontSize(18).setFont('helvetica', 'bold').text(data.companyName, 105, 20, { align: 'center' });
pdf.setFontSize(14).setFont('helvetica', 'normal').text('Profit & Loss Statement', 105, 28, { align: 'center' });
pdf.setFontSize(10).text(data.statementPeriod, 105, 35, { align: 'center' });
pdf.autoTable({
startY: 45,
head: [['Revenue', 'Amount']],
body: data.revenues.map(i => [i.description, formatCurrency(i.amount || 0)]),
foot: [['Total Revenue', formatCurrency(totalRevenue)]],
theme: 'striped',
headStyles: { fillColor: '#047857' },
footStyles: { fontStyle: 'bold' }
});
pdf.autoTable({
startY: pdf.autoTable.previous.finalY + 10,
head: [['Expenses', 'Amount']],
body: data.expenses.map(i => [i.description, formatCurrency(i.amount || 0)]),
foot: [['Total Expenses', formatCurrency(totalExpenses)]],
theme: 'striped',
headStyles: { fillColor: '#b91c1c' },
footStyles: { fontStyle: 'bold' }
});
pdf.setFontSize(12).setFont('helvetica', 'bold');
pdf.text('Net Profit:', 15, pdf.autoTable.previous.finalY + 15);
pdf.text(formatCurrency(netProfit), 200, pdf.autoTable.previous.finalY + 15, { align: 'right' });
pdf.save(`${data.companyName}_PnL.pdf`);
});
// --- Initial Load ---
renderInputs();
renderPreview();
});
