JezK
Edit File: expenses.php
<?php require_once __DIR__ . '/../config/auth.php'; require_role('accountant', 'admin'); $pdo = db(); $lab_id = current_user()['lab_id']; if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { if (!verify_csrf_token($_POST['csrf_token'] ?? '')) die('Invalid CSRF'); if ($_POST['action'] === 'add_expense') { $category = sanitize_input($_POST['category']); $amount = (float)$_POST['amount']; $desc = sanitize_input($_POST['description']); $date = sanitize_input($_POST['date']); $stmt = $pdo->prepare("INSERT INTO expenses (lab_id, category, amount, date, description) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$lab_id, $category, $amount, $date, $desc]); $new_id = $pdo->lastInsertId(); log_audit('Add Expense', 'expenses', $new_id, null, ['category' => $category, 'amount' => $amount]); $cfg_high_expense = (float)get_setting('anomaly_high_expense', 5000); if ($amount > $cfg_high_expense) { $e_id = $pdo->lastInsertId(); $msg = "Accountant recorded an unusually high expense of " . format_currency($amount) . " for category: " . current([$category]); create_anomaly_alert($lab_id, 'high_expense', 'medium', $msg, ['expense_id' => $e_id, 'amount' => $amount]); } header("Location: expenses.php"); exit; } } $expenses = $pdo->prepare("SELECT * FROM expenses WHERE lab_id = ? ORDER BY date DESC, id DESC"); $expenses->execute([$lab_id]); $expenses = $expenses->fetchAll(); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Expenses - X-Ray Lab</title> <link rel="stylesheet" href="../assets/css/style.css"> <script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script> </head> <body> <div class="app-layout"> <?php include '../layouts/sidebar_accountant.php'; ?> <header class="topbar"><div class="topbar-title">Daily Expenses & Net Balance</div></header> <main class="main-content"> <?php // Module M: Net Balance Calculation $today_collection = $pdo->prepare("SELECT COALESCE(SUM(i.amount),0) FROM installments i JOIN billings b ON i.billing_id=b.id JOIN patients p ON b.patient_id=p.id WHERE p.lab_id=? AND DATE(i.paid_on)=CURDATE() AND i.status='verified'"); $today_collection->execute([$lab_id]); $today_collection = (float)$today_collection->fetchColumn(); $today_expenses = $pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM expenses WHERE lab_id=? AND date=CURDATE()"); $today_expenses->execute([$lab_id]); $today_expenses = (float)$today_expenses->fetchColumn(); $today_net = $today_collection - $today_expenses; $month_collection = $pdo->prepare("SELECT COALESCE(SUM(i.amount),0) FROM installments i JOIN billings b ON i.billing_id=b.id JOIN patients p ON b.patient_id=p.id WHERE p.lab_id=? AND MONTH(i.paid_on)=MONTH(CURDATE()) AND YEAR(i.paid_on)=YEAR(CURDATE()) AND i.status='verified'"); $month_collection->execute([$lab_id]); $month_collection = (float)$month_collection->fetchColumn(); $month_expenses = $pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM expenses WHERE lab_id=? AND MONTH(date)=MONTH(CURDATE()) AND YEAR(date)=YEAR(CURDATE())"); $month_expenses->execute([$lab_id]); $month_expenses = (float)$month_expenses->fetchColumn(); $month_net = $month_collection - $month_expenses; ?> <!-- Net Balance Stats --> <div class="stats-grid-wrap" style="margin-bottom:24px;"> <div class="stats-grid" style="grid-template-columns:repeat(auto-fit, minmax(180px, 1fr));"> <div class="stat-card"> <div class="stat-icon" style="background:#f0fdf4;color:#22c55e;padding:15px;border-radius:12px;"><i data-lucide="trending-up"></i></div> <div class="stat-info"> <div class="stat-value"><?= format_currency($today_collection) ?></div> <div class="stat-label">Today's Collection</div> </div> </div> <div class="stat-card"> <div class="stat-icon" style="background:#fef2f2;color:#ef4444;padding:15px;border-radius:12px;"><i data-lucide="trending-down"></i></div> <div class="stat-info"> <div class="stat-value"><?= format_currency($today_expenses) ?></div> <div class="stat-label">Today's Expenses</div> </div> </div> <div class="stat-card" style="border-left:3px solid <?= $today_net >= 0 ? '#22c55e' : '#ef4444' ?>;"> <div class="stat-icon" style="background:<?= $today_net >= 0 ? '#f0fdf4' : '#fef2f2' ?>;color:<?= $today_net >= 0 ? '#22c55e' : '#ef4444' ?>;padding:15px;border-radius:12px;"><i data-lucide="wallet"></i></div> <div class="stat-info"> <div class="stat-value" style="color:<?= $today_net >= 0 ? '#22c55e' : '#ef4444' ?>;"><?= format_currency($today_net) ?></div> <div class="stat-label">Today's Net Balance</div> </div> </div> <div class="stat-card"> <div class="stat-icon" style="background:#eff6ff;color:#3b82f6;padding:15px;border-radius:12px;"><i data-lucide="calendar-range"></i></div> <div class="stat-info"> <div class="stat-value"><?= format_currency($month_collection) ?></div> <div class="stat-label">Month Collection</div> </div> </div> <div class="stat-card"> <div class="stat-icon" style="background:#fff7ed;color:#f97316;padding:15px;border-radius:12px;"><i data-lucide="receipt"></i></div> <div class="stat-info"> <div class="stat-value"><?= format_currency($month_expenses) ?></div> <div class="stat-label">Month Expenses</div> </div> </div> <div class="stat-card" style="border-left:3px solid <?= $month_net >= 0 ? '#22c55e' : '#ef4444' ?>;"> <div class="stat-icon" style="background:<?= $month_net >= 0 ? '#f0fdf4' : '#fef2f2' ?>;color:<?= $month_net >= 0 ? '#22c55e' : '#ef4444' ?>;padding:15px;border-radius:12px;"><i data-lucide="landmark"></i></div> <div class="stat-info"> <div class="stat-value" style="color:<?= $month_net >= 0 ? '#22c55e' : '#ef4444' ?>;"><?= format_currency($month_net) ?></div> <div class="stat-label">Month Net Balance</div> </div> </div> </div> </div> <div class="card"> <div class="card-header" style="display:flex; justify-content:space-between;"> <div class="card-title">Expense Tracker</div> <button onclick="document.getElementById('addModal').style.display='block'" class="btn" style="background:#ef4444;color:#fff;padding:8px 16px;border-radius:6px;border:none;cursor:pointer;">+ Record Expense</button> </div> <div class="table-wrap"> <table class="data-table"> <thead> <tr> <th>Date</th> <th>Category</th> <th>Description</th> <th>Amount</th> </tr> </thead> <tbody> <?php foreach($expenses as $e): ?> <tr> <td><?= date('d M Y', strtotime($e['date'])) ?></td> <td><strong><?= htmlspecialchars($e['category']) ?></strong></td> <td><?= htmlspecialchars($e['description']) ?></td> <td><span style="color:#ef4444;font-weight:600;">- <?= format_currency($e['amount']) ?></span></td> </tr> <?php endforeach; ?> <?php if(empty($expenses)): ?> <tr><td colspan="4" style="text-align:center;color:#64748b;">No expenses recorded yet.</td></tr> <?php endif; ?> </tbody> </table> </div> </div> </main> </div> <!-- Add Expense Modal --> <div id="addModal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:1000; align-items:center; justify-content:center;"> <div style="background:#fff; padding:30px; border-radius:12px; width:400px; max-width:90%; position:absolute; top:50%; left:50%; transform:translate(-50%, -50%);"> <h3 style="margin-top:0;color:#ef4444">Record Expense</h3> <form method="POST"> <input type="hidden" name="csrf_token" value="<?= generate_csrf_token() ?>"> <input type="hidden" name="action" value="add_expense"> <div style="display:flex; gap:10px; margin-bottom:15px;"> <div style="flex:1;"> <label style="display:block;margin-bottom:5px;">Date</label> <input type="date" name="date" required value="<?= date('Y-m-d') ?>" style="width:100%;padding:10px;border:1px solid #ccc;border-radius:6px;box-sizing:border-box;"> </div> <div style="flex:1;"> <label style="display:block;margin-bottom:5px;">Category</label> <select name="category" required style="width:100%;padding:10px;border:1px solid #ccc;border-radius:6px;box-sizing:border-box;"> <option value="Rent">Rent</option> <option value="Salary">Staff Salary</option> <option value="Consumables">Consumables / Materials</option> <option value="Electricity">Electricity</option> <option value="Maintenance">Maintenance</option> <option value="Other">Other</option> </select> </div> </div> <div style="margin-bottom:15px;"> <label style="display:block;margin-bottom:5px;">Amount (₹)</label> <input type="number" step="0.01" name="amount" required style="width:100%;padding:10px;border:1px solid #ccc;border-radius:6px;box-sizing:border-box;"> </div> <div style="margin-bottom:20px;"> <label style="display:block;margin-bottom:5px;">Description / Notes</label> <textarea name="description" rows="2" style="width:100%;padding:10px;border:1px solid #ccc;border-radius:6px;box-sizing:border-box;"></textarea> </div> <div style="display:flex; justify-content:flex-end; gap:10px;"> <button type="button" onclick="document.getElementById('addModal').style.display='none'" style="padding:10px 15px; border:none; background:#f1f5f9; color:#475569; border-radius:6px; cursor:pointer;">Cancel</button> <button type="submit" style="padding:10px 15px; border:none; background:#ef4444; color:#fff; border-radius:6px; cursor:pointer;">Record Expense</button> </div> </form> </div> </div> <script>lucide.createIcons();</script> </body> </html>