Online Secure Vendor & Supplier Invoice Management Tool

Vendor & Supplier Invoice Management

A secure, browser-based tool to track and manage your invoices.

Financial Overview

Total Overdue

$0.00

Total Outstanding

$0.00

Paid (Last 30 Days)

Invoice Status Distribution

${vendor.name}

${vendor.contact} - ${vendor.email}

`).join(''); // Update vendor dropdown in invoice form invoiceVendorInput.innerHTML = vendors.map(v => ``).join(''); } // --- INVOICE LOGIC --- // function toggleInvoiceForm(show, invoice = null) { invoiceFormContainer.classList.toggle('hidden', !show); if (show) { invoiceFormTitle.textContent = invoice ? 'Edit Invoice' : 'Add New Invoice'; invoiceIdInput.value = invoice ? invoice.id : ''; invoiceVendorInput.value = invoice ? invoice.vendorId : (vendors[0]?.id || ''); invoiceNumberInput.value = invoice ? invoice.number : ''; invoiceAmountInput.value = invoice ? invoice.amount : ''; invoiceDueDateInput.value = invoice ? invoice.dueDate : ''; invoiceStatusInput.value = invoice ? invoice.status : 'Draft'; } } function handleSaveInvoice() { const id = invoiceIdInput.value; const invoiceData = { id: id ? parseInt(id) : Date.now(), vendorId: parseInt(invoiceVendorInput.value), number: invoiceNumberInput.value.trim(), amount: parseFloat(invoiceAmountInput.value), dueDate: invoiceDueDateInput.value, status: invoiceStatusInput.value }; if (!invoiceData.vendorId || !invoiceData.number || isNaN(invoiceData.amount) || !invoiceData.dueDate) { showNotification('Please fill all invoice fields correctly.', 'warning'); return; } if (id) { // Update const index = invoices.findIndex(i => i.id === invoiceData.id); if (index > -1) invoices[index] = invoiceData; } else { // Create invoices.push(invoiceData); } saveDataToStorage(); renderInvoices(); updateDashboard(); toggleInvoiceForm(false); showNotification('Invoice saved successfully!', 'success'); } function handleInvoiceAction(e) { const button = e.target.closest('button[data-action]'); if (!button) return; const id = parseInt(button.dataset.id); const action = button.dataset.action; if (action === 'edit') { const invoice = invoices.find(i => i.id === id); if (invoice) toggleInvoiceForm(true, invoice); } else if (action === 'delete') { if (confirm('Are you sure you want to delete this invoice?')) { invoices = invoices.filter(i => i.id !== id); saveDataToStorage(); renderInvoices(); updateDashboard(); } } } function renderInvoices() { invoicesListEl.innerHTML = invoices.map(invoice => { const vendor = vendors.find(v => v.id === invoice.vendorId); const isOverdue = new Date(invoice.dueDate) < new Date() && invoice.status !== 'Paid'; const statusColors = { Paid: 'bg-green-100 text-green-800', Sent: 'bg-blue-100 text-blue-800', Draft: 'bg-gray-100 text-gray-800', Overdue: 'bg-red-100 text-red-800' }; const statusText = isOverdue ? 'Overdue' : invoice.status; const statusColor = isOverdue ? statusColors.Overdue : statusColors[invoice.status]; return ` ${vendor ? vendor.name : 'Unknown Vendor'} ${invoice.number} $${invoice.amount.toFixed(2)} ${invoice.dueDate} ${statusText} `; }).join(''); } // --- DASHBOARD --- // function updateDashboard() { const today = new Date(); const thirtyDaysAgo = new Date(); thirtyDaysAgo.setDate(today.getDate() - 30); let totalOverdue = 0; let totalOutstanding = 0; let paidRecent = 0; let statusCounts = { Draft: 0, Sent: 0, Paid: 0, Overdue: 0 }; invoices.forEach(inv => { const isOverdue = new Date(inv.dueDate) < today && inv.status !== 'Paid'; if (isOverdue) { totalOverdue += inv.amount; statusCounts.Overdue++; } else { statusCounts[inv.status]++; } if (inv.status !== 'Paid') { totalOutstanding += inv.amount; } if (inv.status === 'Paid') { // Assuming a paidDate property would exist in a real app paidRecent += inv.amount; // Simplified for this example } }); totalOverdueStat.textContent = `$${totalOverdue.toFixed(2)}`; totalOutstandingStat.textContent = `$${totalOutstanding.toFixed(2)}`; paidRecentStat.textContent = `$${paidRecent.toFixed(2)}`; renderStatusChart(statusCounts); } function renderStatusChart(counts) { const ctx = document.getElementById('statusChart'); if (!ctx) return; const data = { labels: ['Paid', 'Sent', 'Overdue', 'Draft'], datasets: [{ data: [counts.Paid, counts.Sent, counts.Overdue, counts.Draft], backgroundColor: ['#10B981', '#3B82F6', '#EF4444', '#6B7280'], hoverOffset: 4 }] }; if (statusChart) statusChart.destroy(); statusChart = new Chart(ctx, { type: 'doughnut', data: data, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom' } } } }); } // --- PDF GENERATION --- // function generatePDF() { const { jsPDF } = window.jspdf; const pdf = new jsPDF({ unit: 'pt', format: 'a4' }); let y = 40; const margin = 40; const pdfWidth = pdf.internal.pageSize.getWidth(); pdf.setFontSize(20); pdf.setFont('helvetica', 'bold'); pdf.text('Financial Summary Report', pdfWidth / 2, y, { align: 'center' }); y += 20; pdf.setFontSize(10); pdf.setFont('helvetica', 'normal'); pdf.text(new Date().toLocaleDateString(), pdfWidth / 2, y, { align: 'center' }); y += 40; pdf.setFontSize(12); pdf.text(`Total Overdue: ${totalOverdueStat.textContent}`, margin, y); y += 20; pdf.text(`Total Outstanding: ${totalOutstandingStat.textContent}`, margin, y); y += 20; pdf.text(`Paid (Last 30 Days): ${paidRecentStat.textContent}`, margin, y); y += 40; const headers = [['Vendor', 'Invoice #', 'Amount', 'Due Date', 'Status']]; const body = invoices.filter(i => i.status !== 'Paid').map(i => { const vendor = vendors.find(v => v.id === i.vendorId); const isOverdue = new Date(i.dueDate) < new Date() && i.status !== 'Paid'; return [vendor ? vendor.name : 'N/A', i.number, `$${i.amount.toFixed(2)}`, i.dueDate, isOverdue ? 'Overdue' : i.status]; }); pdf.autoTable({ startY: y, head: headers, body: body, theme: 'grid', headStyles: { fillColor: [17, 24, 39] } }); pdf.save('Financial-Report.pdf'); } // --- TAB NAVIGATION --- // function setActiveTab(index) { tabs.forEach((tab, i) => tab.classList.toggle('active', i === index)); tabPanels.forEach((panel, i) => panel.classList.toggle('hidden', i !== index)); if (index === 0) updateDashboard(); // Refresh dashboard on view } // --- KICK IT OFF --- // initializeApp(); });
Scroll to Top