<!DOCTYPE html> <html lang="en" data-theme="light"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CNPERP - General & Subsidiary Ledgers</title> <!-- Bootstrap 5 CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- Bootstrap Icons --> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet"> <!-- Chart.js --> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <!-- Modern Styles --> <link href="css/modern-styles.css" rel="stylesheet"> <!-- Google Fonts --> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> <style> /* Scrollable dropdown styles */ .dropdown-menu.scrollable-dropdown { max-height: 400px; overflow-y: auto; width: 350px; } .dropdown-menu.scrollable-dropdown .dropdown-header { background-color: #f8f9fa; border-bottom: 1px solid #dee2e6; font-weight: 600; position: sticky; top: 0; z-index: 1020; } .dropdown-menu.scrollable-dropdown .dropdown-item { white-space: nowrap; } .dropdown-menu.scrollable-dropdown .dropdown-item i { width: 16px; text-align: center; } /* Dark theme for scrollable dropdown */ body[data-theme="dark"] .dropdown-menu.scrollable-dropdown { background-color: #343a40; border-color: #495057; } body[data-theme="dark"] .dropdown-menu.scrollable-dropdown .dropdown-header { background-color: #495057; border-bottom-color: #6c757d; color: #ffffff; } body[data-theme="dark"] .dropdown-menu.scrollable-dropdown .dropdown-item { color: #ffffff; } body[data-theme="dark"] .dropdown-menu.scrollable-dropdown .dropdown-item:hover { background-color: #495057; color: #ffffff; } </style> </head> <body> <!-- Navigation Bar Container --> <div id="navbar-container"></div> <!-- Spacer to prevent content from being hidden under fixed navbar --> <div style="height: 70px;"></div> <!-- Main Content --> <div class="container-fluid mt-4"> <!-- Header --> <div class="row mb-4"> <div class="col-12"> <div class="d-flex justify-content-between align-items-center"> <div> <h1 class="h3 mb-0"> <i class="bi bi-journal-text text-primary"></i> General & Subsidiary Ledgers </h1> <p class="text-muted mb-0">Comprehensive ledger views and transaction analysis</p> </div> <div class="d-flex gap-2"> <button class="btn btn-outline-primary" onclick="openLedgerFilters()"> <i class="bi bi-funnel"></i> Advanced Filters </button> <button class="btn btn-primary" onclick="generateLedgerReport()"> <i class="bi bi-file-earmark-text"></i> Generate Report </button> </div> </div> </div> </div> <!-- Ledger Type Selection --> <div class="row mb-4"> <div class="col-md-3"> <div class="card border-primary" style="cursor: pointer;" onclick="showGeneralLedger()"> <div class="card-body text-center"> <i class="bi bi-journal-text fs-1 text-primary mb-3"></i> <h5>General Ledger</h5> <p class="text-muted">Complete account ledgers</p> <span class="badge bg-primary">All Accounts</span> </div> </div> </div> <div class="col-md-3"> <div class="card border-success" style="cursor: pointer;" onclick="showCustomerLedger()"> <div class="card-body text-center"> <i class="bi bi-people fs-1 text-success mb-3"></i> <h5>Customer Ledger</h5> <p class="text-muted">Accounts receivable details</p> <span class="badge bg-success">Debtors</span> </div> </div> </div> <div class="col-md-3"> <div class="card border-warning" style="cursor: pointer;" onclick="showSupplierLedger()"> <div class="card-body text-center"> <i class="bi bi-building fs-1 text-warning mb-3"></i> <h5>Supplier Ledger</h5> <p class="text-muted">Accounts payable details</p> <span class="badge bg-warning text-dark">Creditors</span> </div> </div> </div> <div class="col-md-3"> <div class="card border-info" style="cursor: pointer;" onclick="showInventoryLedger()"> <div class="card-body text-center"> <i class="bi bi-box-seam fs-1 text-info mb-3"></i> <h5>Inventory Ledger</h5> <p class="text-muted">Stock movement tracking</p> <span class="badge bg-info">Stock</span> </div> </div> </div> </div> <!-- Advanced Filters (Collapsible) --> <div class="card mb-4" id="advancedFilters" style="display: none;"> <div class="card-header bg-light"> <h6 class="mb-0"> <i class="bi bi-funnel me-2"></i>Advanced Ledger Filters </h6> </div> <div class="card-body"> <div class="row"> <div class="col-md-3"> <label class="form-label">Account</label> <select class="form-select" id="accountFilter"> <option value="">All Accounts</option> </select> </div> <div class="col-md-2"> <label class="form-label">From Date</label> <input type="date" class="form-control" id="fromDate"> </div> <div class="col-md-2"> <label class="form-label">To Date</label> <input type="date" class="form-control" id="toDate"> </div> <div class="col-md-2"> <label class="form-label">Transaction Type</label> <select class="form-select" id="transactionTypeFilter"> <option value="">All Types</option> <option value="sales">Sales</option> <option value="purchases">Purchases</option> <option value="payments">Payments</option> <option value="adjustments">Adjustments</option> <option value="transfers">Transfers</option> </select> </div> <div class="col-md-2"> <label class="form-label">Amount Range</label> <input type="number" class="form-control" id="minAmount" placeholder="Min Amount" step="0.01"> </div> <div class="col-md-1"> <label class="form-label">&nbsp;</label> <button class="btn btn-primary w-100" onclick="applyLedgerFilters()"> <i class="bi bi-search"></i> </button> </div> </div> </div> </div> <!-- Ledger Tabs --> <ul class="nav nav-tabs mb-4" id="ledgerTabs" role="tablist"> <li class="nav-item" role="presentation"> <button class="nav-link active" id="general-ledger-tab" data-bs-toggle="tab" data-bs-target="#general-ledger-pane" type="button" role="tab"> <i class="bi bi-journal-text me-2"></i>General Ledger </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="customer-ledger-tab" data-bs-toggle="tab" data-bs-target="#customer-ledger-pane" type="button" role="tab"> <i class="bi bi-people me-2"></i>Customer Ledger </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="supplier-ledger-tab" data-bs-toggle="tab" data-bs-target="#supplier-ledger-pane" type="button" role="tab"> <i class="bi bi-building me-2"></i>Supplier Ledger </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="inventory-ledger-tab" data-bs-toggle="tab" data-bs-target="#inventory-ledger-pane" type="button" role="tab"> <i class="bi bi-box-seam me-2"></i>Inventory Ledger </button> </li> </ul> <!-- Tab Content --> <div class="tab-content" id="ledgerTabsContent"> <!-- General Ledger --> <div class="tab-pane fade show active" id="general-ledger-pane" role="tabpanel"> <div class="row"> <!-- Account List --> <div class="col-md-4"> <div class="card"> <div class="card-header bg-primary text-white"> <h6 class="mb-0"> <i class="bi bi-list me-2"></i>Chart of Accounts </h6> </div> <div class="card-body p-0"> <div class="list-group list-group-flush" id="accountsList"> <div class="list-group-item text-center"> <div class="spinner-border text-primary" role="status"> <span class="visually-hidden">Loading...</span> </div> </div> </div> </div> </div> </div> <!-- Ledger Details --> <div class="col-md-8"> <div class="card"> <div class="card-header bg-light"> <div class="d-flex justify-content-between align-items-center"> <h6 class="mb-0" id="selectedAccountName">Select an account to view ledger</h6> <div class="d-flex gap-2"> <button class="btn btn-outline-primary btn-sm" onclick="exportLedger()" id="exportLedgerBtn" disabled> <i class="bi bi-download"></i> Export </button> <button class="btn btn-outline-secondary btn-sm" onclick="printLedger()" id="printLedgerBtn" disabled> <i class="bi bi-printer"></i> Print </button> </div> </div> </div> <div class="card-body"> <!-- Account Summary --> <div class="row mb-3" id="accountSummary" style="display: none;"> <div class="col-md-3"> <div class="text-center p-2 bg-light rounded"> <small class="text-muted">Opening Balance</small> <div class="fw-bold" id="openingBalance">P 0.00</div> </div> </div> <div class="col-md-3"> <div class="text-center p-2 bg-light rounded"> <small class="text-muted">Total Debits</small> <div class="fw-bold text-danger" id="totalDebits">P 0.00</div> </div> </div> <div class="col-md-3"> <div class="text-center p-2 bg-light rounded"> <small class="text-muted">Total Credits</small> <div class="fw-bold text-success" id="totalCredits">P 0.00</div> </div> </div> <div class="col-md-3"> <div class="text-center p-2 bg-primary text-white rounded"> <small>Closing Balance</small> <div class="fw-bold" id="closingBalance">P 0.00</div> </div> </div> </div> <!-- Transactions Table --> <div class="table-responsive"> <table class="table table-striped table-hover"> <thead class="table-dark"> <tr> <th>Date</th> <th>Reference</th> <th>Description</th> <th class="text-end">Debit</th> <th class="text-end">Credit</th> <th class="text-end">Balance</th> <th>Actions</th> </tr> </thead> <tbody id="transactionsTableBody"> <tr> <td colspan="7" class="text-center text-muted"> <i class="bi bi-info-circle me-2"></i>Select an account to view transactions </td> </tr> </tbody> </table> </div> </div> </div> </div> </div> </div> <!-- Filters --> <div class="filter-section"> <div class="row"> <div class="col-md-2"> <label class="form-label">Account Type</label> <select class="form-select" id="accountTypeFilter"> <option value="">All Types</option> <option value="asset">Assets</option> <option value="liability">Liabilities</option> <option value="equity">Equity</option> <option value="revenue">Revenue</option> <option value="expense">Expenses</option> </select> </div> <div class="col-md-2"> <label class="form-label">Account</label> <select class="form-select" id="accountFilter"> <option value="">All Accounts</option> <option value="1000">1000 - Assets</option> <option value="2000">2000 - Liabilities</option> <option value="3000">3000 - Equity</option> <option value="4000">4000 - Revenue</option> <option value="5000">5000 - Expenses</option> </select> </div> <div class="col-md-2"> <label class="form-label">From Date</label> <input type="date" class="form-control" id="fromDateFilter"> </div> <div class="col-md-2"> <label class="form-label">To Date</label> <input type="date" class="form-control" id="toDateFilter"> </div> <div class="col-md-2"> <label class="form-label">Search</label> <input type="text" class="form-control" id="searchFilter" placeholder="Search transactions..."> </div> <div class="col-md-2"> <label class="form-label">&nbsp;</label> <div class="d-flex gap-2"> <button class="btn-modern btn-outline" onclick="clearFilters()"> <i class="bi bi-arrow-clockwise"></i> Clear </button> <button class="btn-modern btn-outline" onclick="exportLedger()"> <i class="bi bi-download"></i> Export </button> </div> </div> </div> </div> <!-- Ledger Tabs --> <div class="modern-card"> <div class="card-header"> <ul class="nav nav-tabs card-header-tabs" id="ledgerTabs" role="tablist"> <li class="nav-item" role="presentation"> <button class="nav-link active" id="general-tab" data-bs-toggle="tab" data-bs-target="#general" type="button" role="tab"> <i class="bi bi-journal-text"></i> General Ledger </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="subsidiary-tab" data-bs-toggle="tab" data-bs-target="#subsidiary" type="button" role="tab"> <i class="bi bi-journal-arrow-down"></i> Subsidiary Ledgers </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="trial-balance-tab" data-bs-toggle="tab" data-bs-target="#trial-balance" type="button" role="tab"> <i class="bi bi-calculator"></i> Trial Balance </button> </li> </ul> </div> <div class="card-body"> <div class="tab-content" id="ledgerTabsContent"> <!-- General Ledger Tab --> <div class="tab-pane fade show active" id="general" role="tabpanel"> <div class="table-responsive"> <table class="table-modern"> <thead> <tr> <th>Date</th> <th>Account</th> <th>Description</th> <th>Reference</th> <th>Debit</th> <th>Credit</th> <th>Balance</th> <th>Actions</th> </tr> </thead> <tbody id="generalLedgerTable"> <!-- General ledger entries will be dynamically generated here --> </tbody> </table> </div> </div> <!-- Subsidiary Ledgers Tab --> <div class="tab-pane fade" id="subsidiary" role="tabpanel"> <div class="row mb-3"> <div class="col-md-4"> <label class="form-label">Select Subsidiary Ledger</label> <select class="form-select" id="subsidiaryLedgerSelect"> <option value="">Choose ledger...</option> <option value="accounts-receivable">Accounts Receivable</option> <option value="accounts-payable">Accounts Payable</option> <option value="inventory">Inventory</option> <option value="cash">Cash</option> <option value="bank">Bank</option> </select> </div> </div> <div class="table-responsive"> <table class="table-modern"> <thead> <tr> <th>Date</th> <th>Customer/Supplier</th> <th>Description</th> <th>Reference</th> <th>Debit</th> <th>Credit</th> <th>Balance</th> <th>Actions</th> </tr> </thead> <tbody id="subsidiaryLedgerTable"> <!-- Subsidiary ledger entries will be dynamically generated here --> </tbody> </table> </div> </div> <!-- Trial Balance Tab --> <div class="tab-pane fade" id="trial-balance" role="tabpanel"> <div class="row mb-3"> <div class="col-md-4"> <label class="form-label">As of Date</label> <input type="date" class="form-control" id="trialBalanceDate" value="2024-01-31"> </div> <div class="col-md-4"> <label class="form-label">&nbsp;</label> <button class="btn-modern btn-primary" onclick="generateTrialBalance()"> <i class="bi bi-calculator"></i> Generate Trial Balance </button> </div> </div> <div class="table-responsive"> <table class="table-modern"> <thead> <tr> <th>Account Code</th> <th>Account Name</th> <th>Type</th> <th>Debit Balance</th> <th>Credit Balance</th> <th>Net Balance</th> </tr> </thead> <tbody id="trialBalanceTable"> <!-- Trial balance entries will be dynamically generated here --> </tbody> </table> </div> </div> </div> </div> </div> </div> <!-- Bootstrap JS --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> <!-- Navbar Scripts --> <script src="js/navbar.js"></script> <script src="js/navbar-loader.js"></script> <!-- Modern Interactions --> <script src="js/modern-interactions.js"></script> <script> // Global data storage let ledgerEntries = []; let subsidiaryLedgers = {}; let trialBalanceData = []; let financialSummary = {}; let loading = false; // Currency settings let currentCurrency = 'BWP'; let currencySymbol = 'P'; let currencyCode = 'BWP'; // API endpoints const API_BASE = '/api/v1'; const ACCOUNTING_ENDPOINT = `${API_BASE}/accounting`; const LEDGER_ENDPOINT = `${ACCOUNTING_ENDPOINT}/ledger`; const SUBSIDIARY_ENDPOINT = `${ACCOUNTING_ENDPOINT}/ledger/subsidiary`; const TRIAL_BALANCE_ENDPOINT = `${ACCOUNTING_ENDPOINT}/trial-balance`; const FINANCIAL_SUMMARY_ENDPOINT = `${ACCOUNTING_ENDPOINT}/financial-summary`; const SETTINGS_ENDPOINT = `${API_BASE}/settings/currency`; // Load settings and currency async function loadSettings() { try { const response = await fetch(SETTINGS_ENDPOINT); if (response.ok) { const settings = await response.json(); currentCurrency = settings.data.currency || 'BWP'; currencySymbol = settings.data.currency_symbol || 'P'; currencyCode = settings.data.currency || 'BWP'; } } catch (error) { console.error('Error loading settings:', error); } } // Format currency amount function formatCurrency(amount) { return `${currencySymbol}${parseFloat(amount).toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`; } // Fetch general ledger entries async function fetchGeneralLedger() { try { loading = true; showLoadingState(); const params = new URLSearchParams(); const accountTypeFilter = document.getElementById('accountTypeFilter').value; const accountFilter = document.getElementById('accountFilter').value; const fromDateFilter = document.getElementById('fromDateFilter').value; const toDateFilter = document.getElementById('toDateFilter').value; const searchFilter = document.getElementById('searchFilter').value; if (accountTypeFilter) params.append('account_type', accountTypeFilter); if (accountFilter) params.append('account_code', accountFilter); if (fromDateFilter) params.append('from_date', fromDateFilter); if (toDateFilter) params.append('to_date', toDateFilter); if (searchFilter) params.append('search', searchFilter); const response = await fetch(`${LEDGER_ENDPOINT}?${params}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); ledgerEntries = data; renderGeneralLedger(); if (window.modernUI) { window.modernUI.showNotification('Ledger data loaded successfully', 'success'); } } catch (error) { console.error('Error fetching ledger entries:', error); if (window.modernUI) { window.modernUI.showNotification('Failed to load ledger data', 'error'); } // Load data from database loadData(); } finally { loading = false; hideLoadingState(); } } // Fetch subsidiary ledger async function fetchSubsidiaryLedger(ledgerType) { try { const response = await fetch(`${SUBSIDIARY_ENDPOINT}/${ledgerType}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); subsidiaryLedgers[ledgerType] = data; renderSubsidiaryLedger(ledgerType); } catch (error) { console.error('Error fetching subsidiary ledger:', error); // Show empty state subsidiaryLedgers[ledgerType] = []; renderSubsidiaryLedger(ledgerType); } } // Fetch trial balance async function fetchTrialBalance(asOfDate = null) { try { const params = new URLSearchParams(); if (asOfDate) params.append('as_of_date', asOfDate); const response = await fetch(`${TRIAL_BALANCE_ENDPOINT}?${params}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); trialBalanceData = data; renderTrialBalance(); } catch (error) { console.error('Error fetching trial balance:', error); // Show empty state trialBalanceData = []; renderTrialBalance(); } } // Fetch financial summary async function fetchFinancialSummary() { try { const response = await fetch(FINANCIAL_SUMMARY_ENDPOINT); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); financialSummary = data; updateFinancialSummary(); } catch (error) { console.error('Error fetching financial summary:', error); // Show empty state financialSummary = {}; updateFinancialSummary(); } } // Show loading state function showLoadingState() { const table = document.getElementById('generalLedgerTable'); if (table) { table.innerHTML = ` <tr> <td colspan="8" class="text-center"> <div class="spinner-border text-primary" role="status"> <span class="visually-hidden">Loading...</span> </div> <p class="mt-2">Loading ledger data...</p> </td> </tr> `; } } // Hide loading state function hideLoadingState() { // Loading state will be replaced by render functions } // Load data from database function loadData() { renderGeneralLedger(); } // Render general ledger function renderGeneralLedger(entriesToRender = ledgerEntries) { const tbody = document.getElementById('generalLedgerTable'); if (!tbody) return; tbody.innerHTML = ''; if (entriesToRender.length === 0) { tbody.innerHTML = ` <tr> <td colspan="8" class="text-center"> <div class="modern-card"> <div class="card-body"> <i class="bi bi-journal-text fs-1 text-muted"></i> <h5 class="mt-3">No ledger entries found</h5> <p class="text-muted">No entries match your current filters.</p> <button class="btn-modern btn-primary" onclick="clearFilters()"> <i class="bi bi-arrow-clockwise"></i> Clear Filters </button> </div> </div> </td> </tr> `; return; } entriesToRender.forEach(entry => { const row = document.createElement('tr'); row.innerHTML = ` <td>${formatDate(entry.date)}</td> <td> <div> <strong>${entry.account_code}</strong><br> <small class="text-muted">${entry.account_name}</small> </div> </td> <td>${entry.description}</td> <td>${entry.reference}</td> <td class="text-end">${entry.debit > 0 ? `P ${entry.debit.toLocaleString()}` : ''}</td> <td class="text-end">${entry.credit > 0 ? `P ${entry.credit.toLocaleString()}` : ''}</td> <td class="text-end fw-bold ${entry.balance >= 0 ? 'text-success' : 'text-danger'}"> P ${Math.abs(entry.balance).toLocaleString()} </td> <td> <button class="btn-modern btn-outline btn-sm" onclick="viewEntry('${entry.id}')"> <i class="bi bi-eye"></i> </button> <button class="btn-modern btn-outline btn-sm" onclick="editEntry('${entry.id}')"> <i class="bi bi-pencil"></i> </button> </td> `; tbody.appendChild(row); }); } // Render subsidiary ledger function renderSubsidiaryLedger(ledgerType) { const tbody = document.getElementById('subsidiaryLedgerTable'); if (!tbody) return; tbody.innerHTML = ''; const entries = subsidiaryLedgers[ledgerType] || []; if (entries.length === 0) { tbody.innerHTML = ` <tr> <td colspan="8" class="text-center"> <div class="modern-card"> <div class="card-body"> <i class="bi bi-journal-arrow-down fs-1 text-muted"></i> <h5 class="mt-3">No subsidiary ledger entries found</h5> <p class="text-muted">No entries for this ledger type.</p> </div> </div> </td> </tr> `; return; } entries.forEach(entry => { const row = document.createElement('tr'); const customerSupplier = ledgerType === 'accounts-receivable' ? entry.customer : entry.supplier; row.innerHTML = ` <td>${formatDate(entry.date)}</td> <td>${customerSupplier || 'N/A'}</td> <td>${entry.description}</td> <td>${entry.reference}</td> <td class="text-end">${entry.debit > 0 ? `P ${entry.debit.toLocaleString()}` : ''}</td> <td class="text-end">${entry.credit > 0 ? `P ${entry.credit.toLocaleString()}` : ''}</td> <td class="text-end fw-bold ${entry.balance >= 0 ? 'text-success' : 'text-danger'}"> P ${Math.abs(entry.balance).toLocaleString()} </td> <td> <button class="btn-modern btn-outline btn-sm" onclick="viewEntry('${entry.id}')"> <i class="bi bi-eye"></i> </button> </td> `; tbody.appendChild(row); }); } // Render trial balance function renderTrialBalance(dataToRender = trialBalanceData) { const tbody = document.getElementById('trialBalanceTable'); if (!tbody) return; tbody.innerHTML = ''; if (dataToRender.length === 0) { tbody.innerHTML = ` <tr> <td colspan="6" class="text-center"> <div class="modern-card"> <div class="card-body"> <i class="bi bi-calculator fs-1 text-muted"></i> <h5 class="mt-3">No trial balance data found</h5> <p class="text-muted">No accounting data available for the selected date.</p> </div> </div> </td> </tr> `; return; } dataToRender.forEach(entry => { const row = document.createElement('tr'); row.innerHTML = ` <td><strong>${entry.account_code}</strong></td> <td>${entry.account_name}</td> <td> <span class="badge-modern badge-${getAccountTypeColor(entry.type)}"> ${entry.type} </span> </td> <td class="text-end">${entry.debit_balance > 0 ? `P ${entry.debit_balance.toLocaleString()}` : ''}</td> <td class="text-end">${entry.credit_balance > 0 ? `P ${entry.credit_balance.toLocaleString()}` : ''}</td> <td class="text-end fw-bold ${entry.net_balance >= 0 ? 'text-success' : 'text-danger'}"> P ${Math.abs(entry.net_balance).toLocaleString()} </td> `; tbody.appendChild(row); }); } // Update financial summary function updateFinancialSummary() { if (financialSummary) { document.getElementById('totalAssets').textContent = `P ${financialSummary.total_assets?.toLocaleString() || '0'}`; document.getElementById('totalLiabilities').textContent = `P ${financialSummary.total_liabilities?.toLocaleString() || '0'}`; document.getElementById('totalEquity').textContent = `P ${financialSummary.total_equity?.toLocaleString() || '0'}`; document.getElementById('netIncome').textContent = `P ${financialSummary.net_income?.toLocaleString() || '0'}`; } } // Get account type color function getAccountTypeColor(type) { const colors = { 'asset': 'primary', 'liability': 'warning', 'equity': 'info', 'revenue': 'success', 'expense': 'danger' }; return colors[type] || 'secondary'; } // Format date function formatDate(dateString) { const date = new Date(dateString); return date.toLocaleDateString(); } // Filter ledger entries function filterLedgerEntries() { fetchGeneralLedger(); } // Clear filters function clearFilters() { document.getElementById('accountTypeFilter').value = ''; document.getElementById('accountFilter').value = ''; document.getElementById('fromDateFilter').value = ''; document.getElementById('toDateFilter').value = ''; document.getElementById('searchFilter').value = ''; fetchGeneralLedger(); } // Generate trial balance async function generateTrialBalance() { const date = document.getElementById('trialBalanceDate').value; if (!date) { if (window.modernUI) { window.modernUI.showNotification('Please select a date for the trial balance', 'warning'); } else { alert('Please select a date for the trial balance'); } return; } await fetchTrialBalance(date); if (window.modernUI) { window.modernUI.showNotification('Trial balance generated successfully', 'success'); } } // View entry function viewEntry(id) { // Find the entry const entry = ledgerEntries.find(e => e.id === id) || Object.values(subsidiaryLedgers).flat().find(e => e.id === id); if (!entry) { if (window.modernUI) { window.modernUI.showNotification('Entry not found', 'error'); } else { alert('Entry not found'); } return; } // Create and show a detailed modal const modalHtml = ` <div class="modal fade" id="entryDetailsModal" tabindex="-1"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title"> <i class="bi bi-journal-text"></i> Ledger Entry Details </h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <div class="row"> <div class="col-md-6"> <h6 class="text-primary">Entry Information</h6> <table class="table table-borderless"> <tr><td><strong>Date:</strong></td><td>${formatDate(entry.date)}</td></tr> <tr><td><strong>Account Code:</strong></td><td>${entry.account_code || 'N/A'}</td></tr> <tr><td><strong>Account Name:</strong></td><td>${entry.account_name || 'N/A'}</td></tr> <tr><td><strong>Reference:</strong></td><td>${entry.reference || 'N/A'}</td></tr> <tr><td><strong>Type:</strong></td><td> <span class="badge-modern badge-${getAccountTypeColor(entry.type)}"> ${entry.type || 'N/A'} </span> </td></tr> </table> </div> <div class="col-md-6"> <h6 class="text-primary">Amounts</h6> <table class="table table-borderless"> <tr><td><strong>Debit:</strong></td><td>${entry.debit > 0 ? `P ${entry.debit.toLocaleString()}` : 'P 0.00'}</td></tr> <tr><td><strong>Credit:</strong></td><td>${entry.credit > 0 ? `P ${entry.credit.toLocaleString()}` : 'P 0.00'}</td></tr> <tr><td><strong>Balance:</strong></td><td class="fw-bold ${entry.balance >= 0 ? 'text-success' : 'text-danger'}"> P ${Math.abs(entry.balance).toLocaleString()} </td></tr> </table> </div> </div> <div class="row mt-3"> <div class="col-12"> <h6 class="text-primary">Description</h6> <p class="mb-0">${entry.description || 'No description available'}</p> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn-modern btn-outline" data-bs-dismiss="modal">Close</button> <button type="button" class="btn-modern btn-primary" onclick="editEntry('${entry.id}')" data-bs-dismiss="modal"> <i class="bi bi-pencil"></i> Edit Entry </button> </div> </div> </div> </div> `; // Remove existing modal if any const existingModal = document.getElementById('entryDetailsModal'); if (existingModal) { existingModal.remove(); } // Add modal to body and show it document.body.insertAdjacentHTML('beforeend', modalHtml); const modal = new bootstrap.Modal(document.getElementById('entryDetailsModal')); modal.show(); // Clean up modal after it's hidden document.getElementById('entryDetailsModal').addEventListener('hidden.bs.modal', function() { this.remove(); }); } // Edit entry function editEntry(id) { if (window.modernUI) { window.modernUI.showNotification('Edit functionality will be implemented in the next phase', 'info'); } else { alert('Edit functionality will be implemented in the next phase'); } } // Generate ledger report function generateLedgerReport() { if (window.modernUI) { window.modernUI.showNotification('Report generation will be implemented in the next phase', 'info'); } else { alert('Report generation will be implemented in the next phase'); } } // Export ledger function exportLedger() { // Create CSV content const headers = ['Date', 'Account Code', 'Account Name', 'Description', 'Reference', 'Debit', 'Credit', 'Balance']; const csvContent = [ headers.join(','), ...ledgerEntries.map(entry => [ formatDate(entry.date), entry.account_code, entry.account_name, entry.description, entry.reference, entry.debit, entry.credit, entry.balance ].join(',')) ].join('\n'); // Create and download file const blob = new Blob([csvContent], { type: 'text/csv' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `ledger_export_${new Date().toISOString().split('T')[0]}.csv`; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); if (window.modernUI) { window.modernUI.showNotification('Ledger exported successfully', 'success'); } } // Handle subsidiary ledger selection document.getElementById('subsidiaryLedgerSelect').addEventListener('change', function() { const selectedLedger = this.value; if (selectedLedger) { fetchSubsidiaryLedger(selectedLedger); } else { document.getElementById('subsidiaryLedgerTable').innerHTML = ''; } }); // Add event listeners document.getElementById('accountTypeFilter').addEventListener('change', filterLedgerEntries); document.getElementById('accountFilter').addEventListener('change', filterLedgerEntries); document.getElementById('fromDateFilter').addEventListener('change', filterLedgerEntries); document.getElementById('toDateFilter').addEventListener('change', filterLedgerEntries); document.getElementById('searchFilter').addEventListener('input', filterLedgerEntries); // Initialize data loading async function initializeData() { try { await loadSettings(); await Promise.all([ fetchGeneralLedger(), fetchTrialBalance(), fetchFinancialSummary() ]); } catch (error) { console.error('Error initializing data:', error); // Load data from database loadData(); renderTrialBalance(); updateFinancialSummary(); } } // Initialize when page loads document.addEventListener('DOMContentLoaded', function() { initializeData(); }); </script> </body> </html>