Finance & Accounting Tools Dashboard
`;
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';
}
});
});