JezK
Edit File: b2b.php
<?php require_once __DIR__ . '/../config/auth.php'; require_role('accounts'); $pdo = db(); $user = current_user(); // Handle B2B Actions if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { csrf_check(); $action = $_POST['action']; if ($action === 'create_partner') { $name = sanitize($_POST['name']); $contact = sanitize($_POST['contact_person']); $phone = sanitize($_POST['phone']); $limit = sanitize_float($_POST['credit_limit'] ?? 50000); $pdo->prepare("INSERT INTO b2b_partners (name, contact_person, phone, credit_limit) VALUES (?, ?, ?, ?)") ->execute([$name, $contact, $phone, $limit]); log_audit('CREATE_B2B_PARTNER', 'B2B', $name, "Created B2B partner: $name"); set_flash('success', "Partner '$name' created."); } if ($action === 'record_payment') { $partner_id = sanitize_int($_POST['partner_id']); $amount = sanitize_float($_POST['amount']); $desc = sanitize($_POST['description'] ?: 'Credit Payment'); $pdo->beginTransaction(); try { // 1. Record payment in ledger $pdo->prepare("INSERT INTO b2b_ledger (partner_id, type, amount, description) VALUES (?, 'payment', ?, ?)") ->execute([$partner_id, $amount, $desc]); // 2. Update current balance (reduce outstanding) $pdo->prepare("UPDATE b2b_partners SET current_balance = current_balance - ? WHERE id = ?") ->execute([$amount, $partner_id]); $pdo->commit(); set_flash('success', 'Payment recorded and ledger updated.'); } catch (Exception $e) { $pdo->rollBack(); set_flash('error', 'Error recording payment: ' . $e->getMessage()); } } redirect('b2b.php'); } // Fetch Partners $partners = $pdo->query("SELECT * FROM b2b_partners ORDER BY name")->fetchAll(); // Detailed Partner View (if selected) $selected_id = sanitize_int($_GET['view_id'] ?? 0); $selected_partner = null; $ledger = []; if ($selected_id) { $stmt = $pdo->prepare("SELECT * FROM b2b_partners WHERE id = ?"); $stmt->execute([$selected_id]); $selected_partner = $stmt->fetch(); if ($selected_partner) { $lstmt = $pdo->prepare("SELECT * FROM b2b_ledger WHERE partner_id = ? ORDER BY created_at DESC LIMIT 50"); $lstmt->execute([$selected_id]); $ledger = $lstmt->fetchAll(); // Calculate margin and total cases from transactions $mstmt = $pdo->prepare(" SELECT COUNT(id) as total_cases, SUM(total_combined) as total_revenue, SUM(amt_charged_outsource - amt_paid_outsource) as total_margin FROM transactions WHERE b2b_partner_id = ? AND payment_status = 'paid' "); $mstmt->execute([$selected_id]); $margin_data = $mstmt->fetch(); $total_cases = $margin_data['total_cases'] ?? 0; $total_revenue = $margin_data['total_revenue'] ?? 0; $total_margin = $margin_data['total_margin'] ?? 0; } } ?> <!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"> <title>B2B Clinics & Ledger — TrustOne Accounts</title> <link rel="stylesheet" href="../assets/css/style.css"> <style> .b2b-grid { display: grid; grid-template-columns: 1fr 2fr; gap: 24px; } .partner-list-item { padding: 12px 16px; border-bottom: 1px solid var(--border); cursor: pointer; transition: background 0.2s; display: flex; justify-content: space-between; align-items: center; } .partner-list-item:hover { background: #f8fafc; } .partner-list-item.active { background: #eff6ff; border-left: 4px solid var(--primary); } .balance-indicator { font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 99px; } .balance-bad { background: #fef2f2; color: #ef4444; } .balance-good { background: #f0fdf4; color: #16a34a; } </style> </head> <body> <div class="app-layout"> <?php include '../layouts/sidebar_accounts.php'; ?> <header class="topbar"> <button class="topbar-hamburger" id="hamburger-btn"><span></span><span></span><span></span></button> <div class="topbar-title">B2B Clinics & Ledger</div> <div class="topbar-right"> <button class="btn btn-primary" data-modal-open="modal-add-partner"> <i data-lucide="plus" style="width:15px;height:15px"></i> New Partner </button> </div> </header> <main class="main-content"> <?= render_flash() ?> <div class="b2b-grid"> <!-- Sidebar List --> <div class="card"> <div class="card-header"><div class="card-title">Partners / Clinics</div></div> <div class="card-body" style="padding:0;"> <?php foreach($partners as $p): ?> <div class="partner-list-item <?= $selected_id==$p['id']?'active':'' ?>" onclick="location.href='b2b.php?view_id=<?= $p['id'] ?>'"> <div> <div style="font-weight:600;font-size:14px;"><?= htmlspecialchars($p['name']) ?></div> <div style="font-size:11px;color:#94a3b8;"><?= htmlspecialchars($p['contact_person']) ?></div> </div> <div class="balance-indicator <?= $p['current_balance']>0?'balance-bad':'balance-good' ?>"> ₹<?= number_format($p['current_balance'], 2) ?> </div> </div> <?php endforeach; ?> <?php if (empty($partners)): ?> <div style="padding:30px;text-align:center;color:#94a3b8;">No partners configured.</div> <?php endif; ?> </div> </div> <!-- Details View --> <div class="card"> <?php if (!$selected_partner): ?> <div style="padding:60px;text-align:center;color:#94a3b8;"> <i data-lucide="building-2" style="width:48px;height:48px;margin-bottom:16px;opacity:0.3;"></i> <h3>Select a partner to view details</h3> </div> <?php else: ?> <div class="card-header" style="justify-content:space-between;align-items:flex-start;"> <div> <div class="card-title"><?= htmlspecialchars($selected_partner['name']) ?></div> <p style="font-size:12px;color:#64748b;margin-top:4px;"><?= htmlspecialchars($selected_partner['contact_person']) ?> · <?= htmlspecialchars($selected_partner['phone']) ?></p> </div> <button class="btn btn-sm btn-success" data-modal-open="modal-record-payment">Record Payment</button> </div> <div class="card-body"> <div style="display:flex;gap:20px;margin-bottom:24px;"> <div style="flex:1;background:#f8fafc;padding:15px;border-radius:10px;border:1px solid var(--border);"> <div style="font-size:11px;color:#64748b;text-transform:uppercase;">Outstanding Ledger Balance</div> <div style="font-size:24px;font-weight:800;color:<?= $selected_partner['current_balance']>0?'#ef4444':'#16a34a' ?>;">₹<?= number_format($selected_partner['current_balance'], 2) ?></div> </div> <div style="flex:1;background:#f8fafc;padding:15px;border-radius:10px;border:1px solid var(--border);"> <div style="font-size:11px;color:#64748b;text-transform:uppercase;">Generated Revenue (<?= $total_cases ?> Cases)</div> <div style="font-size:24px;font-weight:800;color:#0f172a;">₹<?= number_format($total_revenue, 2) ?></div> </div> <div style="flex:1;background:#f0f9ff;padding:15px;border-radius:10px;border:1px solid #bae6fd;"> <div style="font-size:11px;color:#0369a1;text-transform:uppercase;">Net Margin / Payout Due</div> <div style="font-size:24px;font-weight:800;color:#0369a1;">₹<?= number_format($total_margin, 2) ?></div> </div> </div> <div class="card-title" style="font-size:14px;margin-bottom:15px;">Transaction Ledger (Recent 50)</div> <div class="table-wrap"> <table class="data-table"> <thead><tr><th>Date</th><th>Type</th><th>Description</th><th>Amount</th></tr></thead> <tbody> <?php foreach($ledger as $l): ?> <tr> <td style="font-size:11px;"><?= date('d M Y, h:i A', strtotime($l['created_at'])) ?></td> <td><span class="badge badge-<?= $l['type']=='payment'?'success':'grey' ?>"><?= strtoupper($l['type']) ?></span></td> <td style="font-size:12px;"><?= htmlspecialchars($l['description']) ?></td> <td style="font-weight:700;color:<?= $l['type']=='payment'?'#16a34a':'#ef4444' ?>;"> <?= $l['type']=='payment'?'+':'-' ?> ₹<?= number_format($l['amount'], 2) ?> </td> </tr> <?php endforeach; ?> <?php if (empty($ledger)): ?> <tr><td colspan="4" style="text-align:center;padding:20px;color:#94a3b8;">No ledger entries yet.</td></tr> <?php endif; ?> </tbody> </table> </div> </div> <?php endif; ?> </div> </div> </main> </div> <!-- Modals --> <div class="modal-overlay" id="modal-add-partner"> <div class="modal"> <div class="modal-header"><span class="modal-title">Add B2B Partner</span><button class="modal-close" data-modal-close="modal-add-partner">✕</button></div> <form method="post"><input type="hidden" name="action" value="create_partner"><?= csrf_field() ?> <div class="modal-body"> <div class="form-group"><label class="form-label">Partner / Clinic Name *</label><input type="text" name="name" class="form-control" required></div> <div class="form-grid-2"> <div class="form-group"><label class="form-label">Contact Person</label><input type="text" name="contact_person" class="form-control"></div> <div class="form-group"><label class="form-label">Phone</label><input type="text" name="phone" class="form-control"></div> </div> <div class="form-group"><label class="form-label">Credit Limit (₹)</label><input type="number" name="credit_limit" class="form-control" value="50000"></div> </div> <div class="modal-footer"><button type="submit" class="btn btn-primary">Create Partner</button></div> </form> </div> </div> <div class="modal-overlay" id="modal-record-payment"> <div class="modal"> <div class="modal-header"><span class="modal-title">Record Credit Payment</span><button class="modal-close" data-modal-close="modal-record-payment">✕</button></div> <form method="post"><input type="hidden" name="action" value="record_payment"><?= csrf_field() ?><input type="hidden" name="partner_id" value="<?= $selected_id ?>"> <div class="modal-body"> <div class="form-group"><label class="form-label">Payment Amount (₹) *</label><input type="number" step="0.01" name="amount" class="form-control" required></div> <div class="form-group"><label class="form-label">Notes / Reference</label><input type="text" name="description" class="form-control" placeholder="e.g. Cheque #123456, Cash deposit"></div> </div> <div class="modal-footer"><button type="submit" class="btn btn-success" style="width:100%;">Record Payment</button></div> </form> </div> </div> <script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script> <script src="../assets/js/main.js"></script> <script>lucide.createIcons();</script> </body></html>