Finance & Accounting Tools Dashboard

Finance & Accounting Tools

Invoice Generator

Create professional invoices with logo upload, client details, and automatic VAT/tax calculations.

Profit & Loss Calculator

Calculate net profit/loss with revenue and expense inputs. View results in interactive charts.

Tax & VAT Calculator

Calculate taxes and VAT with percentage breakdown and export options.

Cash Flow Planner

Plan monthly cash flow with inflow/outflow tracking and visual graphs.

Expense Tracker

Track daily/monthly expenses with categories and receipt image uploads.

Investment ROI Calculator

Calculate ROI percentage, payback period, and growth projections with charts.

Supplier Payment Tracker

Track supplier bills, due dates, and payment status with reminder alerts.

`; previewWindow.document.write(previewHTML); previewWindow.document.close(); } function saveInvoiceDraft() { const invoiceData = { companyName: document.getElementById('company-name').value, companyReg: document.getElementById('company-reg').value, companyAddress: document.getElementById('company-address').value, companyContact: document.getElementById('company-contact').value, invoiceNumber: document.getElementById('invoice-number').value, invoiceDate: document.getElementById('invoice-date').value, clientName: document.getElementById('client-name').value, clientReg: document.getElementById('client-reg').value, clientAddress: document.getElementById('client-address').value, clientContact: document.getElementById('client-contact').value, items: Array.from(document.querySelectorAll('.invoice-item')).map(item => ({ description: item.querySelector('.item-description').value, quantity: item.querySelector('.item-quantity').value, price: item.querySelector('.item-price').value })), vatRate: document.getElementById('vat-rate').value, taxRate: document.getElementById('tax-rate').value, discountRate: document.getElementById('discount-rate').value, bankName: document.getElementById('bank-name').value, accountNumber: document.getElementById('account-number').value, swiftCode: document.getElementById('swift-code').value, paymentMethods: document.getElementById('payment-methods').value, notes: document.getElementById('invoice-notes').value, timestamp: new Date().toISOString() }; localStorage.setItem(`invoice_draft_${invoiceData.invoiceNumber}`, JSON.stringify(invoiceData)); alert(`Invoice draft saved successfully! Invoice #${invoiceData.invoiceNumber}`); } function sendInvoiceEmail() { const clientEmail = prompt('Enter client email address:'); if (clientEmail) { const subject = `Invoice ${document.getElementById('invoice-number').value} from ${document.getElementById('company-name').value}`; const body = `Dear ${document.getElementById('client-name').value},\n\nPlease find attached your invoice.\n\nInvoice Details:\n- Invoice Number: ${document.getElementById('invoice-number').value}\n- Amount: ${document.getElementById('invoice-total').textContent}\n- Due Date: ${document.getElementById('due-date-invoice').value}\n\nThank you for your business.\n\nBest regards,\n${document.getElementById('company-name').value}`; const mailtoLink = `mailto:${clientEmail}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`; window.open(mailtoLink); } } function clearInvoiceForm() { if (confirm('Are you sure you want to clear all invoice data? This action cannot be undone.')) { document.getElementById('invoice-form').reset(); removeLogo(); // Reset invoice items to just one const itemsContainer = document.getElementById('invoice-items'); itemsContainer.innerHTML = `
`; // Reset calculations calculateInvoice(); // Reset dates document.getElementById('invoice-date').value = new Date().toISOString().split('T')[0]; const dueDate = new Date(); dueDate.setDate(dueDate.getDate() + 30); document.getElementById('due-date-invoice').value = dueDate.toISOString().split('T')[0]; // Generate new professional invoice number const today = new Date(); const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, '0'); const timestamp = Date.now().toString().slice(-4); document.getElementById('invoice-number').value = `INV-${year}${month}-${timestamp}`; } }// Profit & Loss Functions function calculatePL() { const revenue = parseFloat(document.getElementById('total-revenue').value) || 0; const expenses = parseFloat(document.getElementById('total-expenses').value) || 0; const netResult = revenue - expenses;document.getElementById('pl-revenue-value').textContent = formatCurrency(revenue); document.getElementById('pl-expenses-value').textContent = formatCurrency(expenses); document.getElementById('pl-net-result').textContent = formatCurrency(netResult); document.getElementById('pl-net-result').style.color = netResult >= 0 ? '#28a745' : '#dc3545';document.getElementById('pl-results').style.display = 'block';// Create chart const ctx = document.getElementById('pl-chart').getContext('2d'); new Chart(ctx, { type: 'bar', data: { labels: ['Revenue', 'Expenses', 'Net Result'], datasets: [{ label: 'Amount', data: [revenue, expenses, netResult], backgroundColor: ['#28a745', '#dc3545', netResult >= 0 ? '#28a745' : '#dc3545'] }] }, options: { responsive: true, maintainAspectRatio: false } }); }function exportPLReport() { const { jsPDF } = window.jspdf; const doc = new jsPDF();doc.setFontSize(20); doc.text('Profit & Loss Report', 20, 30); doc.setFontSize(12); doc.text(`Revenue: ${document.getElementById('pl-revenue-value').textContent}`, 20, 50); doc.text(`Expenses: ${document.getElementById('pl-expenses-value').textContent}`, 20, 60); doc.text(`Net Result: ${document.getElementById('pl-net-result').textContent}`, 20, 70);doc.save('profit-loss-report.pdf'); }// Tax & VAT Functions function calculateTaxVAT() { const baseAmount = parseFloat(document.getElementById('base-amount').value) || 0; const taxPercentage = parseFloat(document.getElementById('tax-percentage').value) || 0; const vatPercentage = parseFloat(document.getElementById('vat-percentage').value) || 0;const taxAmount = baseAmount * (taxPercentage / 100); const vatAmount = baseAmount * (vatPercentage / 100); const totalAmount = baseAmount + taxAmount + vatAmount;document.getElementById('tax-base-value').textContent = formatCurrency(baseAmount); document.getElementById('tax-calculated-value').textContent = formatCurrency(taxAmount); document.getElementById('vat-calculated-value').textContent = formatCurrency(vatAmount); document.getElementById('tax-total-value').textContent = formatCurrency(totalAmount);document.getElementById('tax-results').style.display = 'block'; }function exportTaxReport() { const { jsPDF } = window.jspdf; const doc = new jsPDF();doc.setFontSize(20); doc.text('Tax & VAT Report', 20, 30); doc.setFontSize(12); doc.text(`Base Amount: ${document.getElementById('tax-base-value').textContent}`, 20, 50); doc.text(`Tax Amount: ${document.getElementById('tax-calculated-value').textContent}`, 20, 60); doc.text(`VAT Amount: ${document.getElementById('vat-calculated-value').textContent}`, 20, 70); doc.text(`Total: ${document.getElementById('tax-total-value').textContent}`, 20, 80);doc.save('tax-vat-report.pdf'); }// Cash Flow Functions function addCashFlowEntry() { const month = document.getElementById('cashflow-month').value; const openingBalance = parseFloat(document.getElementById('opening-balance').value) || 0; const inflow = parseFloat(document.getElementById('cash-inflow').value) || 0; const outflow = parseFloat(document.getElementById('cash-outflow').value) || 0;if (!month || inflow === 0 || outflow === 0) { alert('Please fill all fields'); return; }const netFlow = inflow - outflow; const closingBalance = openingBalance + netFlow;cashFlowEntries.push({ month, openingBalance, inflow, outflow, netFlow, closingBalance });updateCashFlowTable(); document.getElementById('cashflow-form').reset(); }function updateCashFlowTable() { const tbody = document.getElementById('cashflow-tbody'); tbody.innerHTML = '';cashFlowEntries.forEach((entry, index) => { const row = tbody.insertRow(); row.innerHTML = `${entry.month}${formatCurrency(entry.inflow)}${formatCurrency(entry.outflow)}${formatCurrency(entry.netFlow)}${formatCurrency(entry.closingBalance)} `; });document.getElementById('cashflow-table-container').style.display = 'block'; }function calculateCashFlow() { if (cashFlowEntries.length === 0) { alert('Please add at least one cash flow entry'); return; }// Create chart const ctx = document.getElementById('cashflow-chart').getContext('2d'); new Chart(ctx, { type: 'line', data: { labels: cashFlowEntries.map(entry => entry.month), datasets: [{ label: 'Cash Inflow', data: cashFlowEntries.map(entry => entry.inflow), borderColor: '#28a745', tension: 0.1 }, { label: 'Cash Outflow', data: cashFlowEntries.map(entry => entry.outflow), borderColor: '#dc3545', tension: 0.1 }] }, options: { responsive: true, maintainAspectRatio: false } });document.getElementById('cashflow-chart-container').style.display = 'block'; }function exportCashFlowReport() { const { jsPDF } = window.jspdf; const doc = new jsPDF();doc.setFontSize(20); doc.text('Cash Flow Report', 20, 30); let yPosition = 50; cashFlowEntries.forEach((entry, index) => { doc.setFontSize(12); doc.text(`${entry.month}: Inflow ${formatCurrency(entry.inflow)} - Outflow ${formatCurrency(entry.outflow)} = Net ${formatCurrency(entry.netFlow)}`, 20, yPosition); yPosition += 10; });doc.save('cashflow-report.pdf'); }// Expense Functions function handleReceiptUpload(event) { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = function(e) { const preview = document.getElementById('receipt-preview'); preview.innerHTML = ``; }; reader.readAsDataURL(file); } }function addExpense() { const date = document.getElementById('expense-date').value; const category = document.getElementById('expense-category').value; const description = document.getElementById('expense-description').value; const amount = parseFloat(document.getElementById('expense-amount').value) || 0;if (!date || !category || !description || amount === 0) { alert('Please fill all fields'); return; }expenses.push({ date, category, description, amount, id: Date.now() });updateExpenseTable(); updateExpenseSummary(); document.getElementById('expense-form').reset(); document.getElementById('receipt-preview').innerHTML = ''; }function updateExpenseTable() { const tbody = document.getElementById('expense-tbody'); tbody.innerHTML = '';expenses.forEach((expense, index) => { const row = tbody.insertRow(); row.innerHTML = `${expense.date}${expense.category}${expense.description}${formatCurrency(expense.amount)} `; });document.getElementById('expense-table-container').style.display = 'block'; }function updateExpenseSummary() { const total = expenses.reduce((sum, expense) => sum + expense.amount, 0); document.getElementById('total-expenses-value').textContent = formatCurrency(total); document.getElementById('expense-summary').style.display = 'block'; }function removeExpense(id) { expenses = expenses.filter(expense => expense.id !== id); updateExpenseTable(); updateExpenseSummary(); }function exportExpenseReport() { const { jsPDF } = window.jspdf; const doc = new jsPDF();doc.setFontSize(20); doc.text('Expense Report', 20, 30); let yPosition = 50; expenses.forEach((expense, index) => { doc.setFontSize(10); doc.text(`${expense.date} - ${expense.category} - ${expense.description} - ${formatCurrency(expense.amount)}`, 20, yPosition); yPosition += 8; });const total = expenses.reduce((sum, expense) => sum + expense.amount, 0); doc.setFontSize(12); doc.text(`Total Expenses: ${formatCurrency(total)}`, 20, yPosition + 10);doc.save('expense-report.pdf'); }// ROI Functions function calculateROI() { const initialInvestment = parseFloat(document.getElementById('initial-investment').value) || 0; const finalValue = parseFloat(document.getElementById('final-value').value) || 0; const period = parseFloat(document.getElementById('investment-period').value) || 0;if (initialInvestment === 0 || finalValue === 0 || period === 0) { alert('Please fill all required fields'); return; }const totalGain = finalValue - initialInvestment; const roiPercentage = (totalGain / initialInvestment) * 100; const paybackPeriod = initialInvestment / (totalGain / period);document.getElementById('roi-percentage-value').textContent = `${roiPercentage.toFixed(2)}%`; document.getElementById('total-gain-value').textContent = formatCurrency(totalGain); document.getElementById('payback-period-value').textContent = `${paybackPeriod.toFixed(1)} years`;document.getElementById('roi-results').style.display = 'block';// Create chart const ctx = document.getElementById('roi-chart').getContext('2d'); new Chart(ctx, { type: 'doughnut', data: { labels: ['Initial Investment', 'Gain'], datasets: [{ data: [initialInvestment, totalGain], backgroundColor: ['#667eea', '#28a745'] }] }, options: { responsive: true, maintainAspectRatio: false } }); }function exportROIReport() { const { jsPDF } = window.jspdf; const doc = new jsPDF();doc.setFontSize(20); doc.text('ROI Analysis Report', 20, 30); doc.setFontSize(12); doc.text(`Initial Investment: ${formatCurrency(document.getElementById('initial-investment').value)}`, 20, 50); doc.text(`Final Value: ${formatCurrency(document.getElementById('final-value').value)}`, 20, 60); doc.text(`ROI Percentage: ${document.getElementById('roi-percentage-value').textContent}`, 20, 70); doc.text(`Total Gain: ${document.getElementById('total-gain-value').textContent}`, 20, 80); doc.text(`Payback Period: ${document.getElementById('payback-period-value').textContent}`, 20, 90);doc.save('roi-report.pdf'); }// Supplier Functions function addSupplierBill() { const supplierName = document.getElementById('supplier-name').value; const billNumber = document.getElementById('bill-number').value; const billAmount = parseFloat(document.getElementById('bill-amount').value) || 0; const dueDate = document.getElementById('due-date').value; const paymentStatus = document.getElementById('payment-status').value;if (!supplierName || !billNumber || billAmount === 0 || !dueDate) { alert('Please fill all fields'); return; }supplierBills.push({ supplierName, billNumber, billAmount, dueDate, paymentStatus, id: Date.now() });updateSupplierTable(); updateSupplierSummary(); document.getElementById('supplier-form').reset(); }function updateSupplierTable() { const tbody = document.getElementById('supplier-tbody'); tbody.innerHTML = '';supplierBills.forEach((bill, index) => { const row = tbody.insertRow(); const statusClass = `status-${bill.paymentStatus}`; row.innerHTML = `${bill.supplierName}${bill.billNumber}${formatCurrency(bill.billAmount)}${bill.dueDate}${bill.paymentStatus.toUpperCase()} `; });document.getElementById('supplier-table-container').style.display = 'block'; }function updateSupplierSummary() { const totalBills = supplierBills.reduce((sum, bill) => sum + bill.billAmount, 0); const paidAmount = supplierBills.filter(bill => bill.paymentStatus === 'paid').reduce((sum, bill) => sum + bill.billAmount, 0); const pendingAmount = totalBills - paidAmount;document.getElementById('total-bills-value').textContent = formatCurrency(totalBills); document.getElementById('paid-amount-value').textContent = formatCurrency(paidAmount); document.getElementById('pending-amount-value').textContent = formatCurrency(pendingAmount); document.getElementById('supplier-summary').style.display = 'block'; }function togglePaymentStatus(id) { const bill = supplierBills.find(bill => bill.id === id); if (bill) { const statuses = ['unpaid', 'paid', 'overdue']; const currentIndex = statuses.indexOf(bill.paymentStatus); bill.paymentStatus = statuses[(currentIndex + 1) % statuses.length]; updateSupplierTable(); updateSupplierSummary(); } }function removeSupplierBill(id) { supplierBills = supplierBills.filter(bill => bill.id !== id); updateSupplierTable(); updateSupplierSummary(); }function exportSupplierReport() { const { jsPDF } = window.jspdf; const doc = new jsPDF();doc.setFontSize(20); doc.text('Supplier Payment Report', 20, 30); let yPosition = 50; supplierBills.forEach((bill, index) => { doc.setFontSize(10); doc.text(`${bill.supplierName} - ${bill.billNumber} - ${formatCurrency(bill.billAmount)} - ${bill.dueDate} - ${bill.paymentStatus.toUpperCase()}`, 20, yPosition); yPosition += 8; });const totalBills = supplierBills.reduce((sum, bill) => sum + bill.billAmount, 0); const paidAmount = supplierBills.filter(bill => bill.paymentStatus === 'paid').reduce((sum, bill) => sum + bill.billAmount, 0); doc.setFontSize(12); doc.text(`Total Bills: ${formatCurrency(totalBills)}`, 20, yPosition + 10); doc.text(`Paid Amount: ${formatCurrency(paidAmount)}`, 20, yPosition + 20); doc.text(`Pending: ${formatCurrency(totalBills - paidAmount)}`, 20, yPosition + 30);doc.save('supplier-report.pdf'); }// Event Listeners document.getElementById('currency-selector').addEventListener('change', function() { setCurrency(this.value); });// Auto-calculate invoice items document.addEventListener('input', function(e) { if (e.target.classList.contains('item-quantity') || e.target.classList.contains('item-price') || e.target.id === 'discount-rate' || e.target.id === 'vat-rate' || e.target.id === 'tax-rate') { calculateInvoice(); } }); // International features initialization function initializeInternationalFeatures() { // Add international indicators to relevant fields const internationalFields = [ 'company-address', 'client-address', 'swift-code', 'payment-methods', 'invoice-currency' ]; internationalFields.forEach(fieldId => { const field = document.getElementById(fieldId); if (field) { field.parentElement.classList.add('international-field'); } }); // Currency change handler document.getElementById('currency-selector').addEventListener('change', function() { setCurrency(this.value); // Update invoice currency if not explicitly set const invoiceCurrency = document.getElementById('invoice-currency'); if (invoiceCurrency && !invoiceCurrency.value) { invoiceCurrency.value = this.value; } calculateInvoice(); }); }// Close modals when clicking outside document.addEventListener('click', function(e) { if (e.target.classList.contains('modal')) { e.target.classList.remove('active'); document.body.style.overflow = 'auto'; } });// Enhanced translations for new features const enhancedTranslations = { en: { ...translations.en, 'upload-logo-text': 'Upload Company Logo', 'upload-subtext': 'Drag & drop or click to browse • PNG, JPG, SVG • Max 5MB', 'logo-placeholder': 'No logo uploaded', 'calculate-invoice-btn': 'Calculate Invoice', 'export-pdf-btn': 'Export as PDF', 'preview-invoice-btn': 'Preview Invoice', 'clear-form-btn': 'Clear Form', 'invoice-summary-title': 'Invoice Summary' }, bn: { ...translations.bn, 'upload-logo-text': 'কোম্পানির লোগো আপলোড করুন', 'upload-subtext': 'ড্র্যাগ অ্যান্ড ড্রপ অথবা ব্রাউজ করতে ক্লিক করুন', 'logo-placeholder': 'কোনো লোগো আপলোড হয়নি', 'calculate-invoice-btn': 'ইনভয়েস গণনা করুন', 'export-pdf-btn': 'PDF এ এক্সপোর্ট করুন', 'preview-invoice-btn': 'ইনভয়েস প্রিভিউ', 'clear-form-btn': 'ফর্ম সাফ করুন', 'invoice-summary-title': 'ইনভয়েস সারাংশ' } };// Initialize App document.addEventListener('DOMContentLoaded', function() { // Load saved preferences const savedLanguage = localStorage.getItem('language') || 'en'; const savedCurrency = localStorage.getItem('currency') || 'BDT'; const savedTheme = localStorage.getItem('theme') || 'light';setLanguage(savedLanguage); setCurrency(savedCurrency); if (savedTheme === 'dark') { toggleTheme(); }// Set current date for invoice document.getElementById('invoice-date').value = new Date().toISOString().split('T')[0]; document.getElementById('expense-date').value = new Date().toISOString().split('T')[0]; document.getElementById('due-date').value = new Date().toISOString().split('T')[0]; document.getElementById('cashflow-month').value = new Date().toISOString().slice(0, 7);// Auto-generate professional invoice number const today = new Date(); const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, '0'); const timestamp = Date.now().toString().slice(-4); document.getElementById('invoice-number').value = `INV-${year}${month}-${timestamp}`; // Set due date to 30 days from today const dueDate = new Date(); dueDate.setDate(dueDate.getDate() + 30); document.getElementById('due-date-invoice').value = dueDate.toISOString().split('T')[0]; // Initialize drag and drop for all upload areas document.querySelectorAll('.upload-area').forEach(area => { area.addEventListener('dragover', handleDragOver); area.addEventListener('dragleave', handleDragLeave); area.addEventListener('drop', handleDrop); }); // Initialize international features initializeInternationalFeatures(); // Add professional badges to key features const professionalFeatures = document.querySelectorAll('[id*="international"], [id*="currency"], [id*="tax"], [id*="vat"]'); professionalFeatures.forEach(feature => { if (feature.tagName === 'LABEL') { feature.innerHTML += 'Pro'; } }); });