Heray-Was-Here
Server : LiteSpeed
System : Linux uk-fast-web1372.main-hosting.eu 4.18.0-553.121.1.lve.el8.x86_64 #1 SMP Thu Apr 30 16:40:41 UTC 2026 x86_64
User : u390967363 ( 390967363)
PHP Version : 8.2.30
Disable Function : system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail
Directory :  /home/u390967363/domains/aibenproperties.com/public_html/app/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/u390967363/domains/aibenproperties.com/public_html/app/procurement-po.php
<?php
require_once __DIR__ . '/includes/header.php';

$uid = (int)($_SESSION['user_id'] ?? 0);
$role = $_SESSION['user_role'] ?? 'guest';
$roleNorm = strtolower(str_replace([' ', '-'], '_', (string)$role));
if ($uid <= 0 || $roleNorm === 'client') {
    header('Location: dashboard.php');
    exit;
}

try { if (function_exists('ensureProcurementSchema')) { ensureProcurementSchema($pdo); } } catch (Throwable $e) {}
try { if (function_exists('ensureManualExpensesTable')) { ensureManualExpensesTable(); } } catch (Throwable $e) {}

$companyId = 0;
try { $companyId = (int)(function_exists('getCurrentCompanyId') ? (getCurrentCompanyId() ?: 0) : ($_SESSION['company_id'] ?? 0)); } catch (Throwable $e) { $companyId = (int)($_SESSION['company_id'] ?? 0); }

$isSuperAdmin = in_array($roleNorm, ['super_admin', 'super_admins'], true);
$isAdminTier = (function_exists('isAdminTier') && isAdminTier($role)) || in_array($roleNorm, ['admin','head_admin'], true);
$isFinanceTier = (function_exists('isFinanceTier') && isFinanceTier($role)) || in_array($roleNorm, ['finance','finance_manager','finance_officer'], true);
$isExecTier = (function_exists('isExecutive') && isExecutive($role)) || in_array($roleNorm, ['chairman_ceo'], true);
$isProcOfficer = ($roleNorm === 'procurement_officer');
$isProcManager = ($roleNorm === 'procurement_manager');
$canView = $isSuperAdmin || $isAdminTier || $isFinanceTier || $isExecTier || $isProcOfficer || $isProcManager;
if (!$canView) {
    header('Location: dashboard.php');
    exit;
}

$canManage = $isSuperAdmin || $isAdminTier || $isProcManager;
$csrf = ap_csrf_token();
$error = '';
$notice = '';

$insPoHistory = function(int $poId, string $action, ?string $from, ?string $to, ?string $note) use ($pdo, $uid) {
    try {
        $pdo->prepare("INSERT INTO procurement_po_history (po_id, actor_id, action, from_status, to_status, note) VALUES (?,?,?,?,?,?)")
            ->execute([$poId, $uid ?: null, $action, $from, $to, $note]);
    } catch (Throwable $e) {}
};

$insReqHistory = function(int $requestId, string $action, ?string $note) use ($pdo, $uid) {
    try {
        $pdo->prepare("INSERT INTO procurement_request_history (request_id, actor_id, action, note) VALUES (?,?,?,?)")
            ->execute([$requestId, $uid ?: null, $action, $note]);
    } catch (Throwable $e) {}
};

$ensureProcPayable = function(array $poRow, ?array $vendorRow) use ($pdo, $uid, $roleNorm, $companyId) {
    try {
        if (!function_exists('ensureManualExpensesTable') || !ensureManualExpensesTable()) return;
        if (!(function_exists('tableHasColumn') && tableHasColumn('expenses_manual', 'reference_number') && tableHasColumn('expenses_manual', 'category') && tableHasColumn('expenses_manual', 'amount') && tableHasColumn('expenses_manual', 'expense_date'))) return;
        $ref = trim((string)($poRow['po_number'] ?? ''));
        if ($ref === '') return;
        $p = [$ref];
        $sql = "SELECT id FROM expenses_manual WHERE reference_number = ? AND LOWER(TRIM(category)) = 'procurement' LIMIT 1";
        if ($companyId > 0 && function_exists('tableHasColumn') && tableHasColumn('expenses_manual', 'company_id')) { $sql = "SELECT id FROM expenses_manual WHERE reference_number = ? AND LOWER(TRIM(category)) = 'procurement' AND (company_id = ? OR company_id IS NULL) LIMIT 1"; $p = [$ref, $companyId]; }
        $st = $pdo->prepare($sql);
        $st->execute($p);
        $existsId = (int)($st->fetchColumn() ?: 0);
        if ($existsId > 0) return;

        $title = 'Purchase Order ' . $ref;
        $poTitle = trim((string)($poRow['title'] ?? ''));
        if ($poTitle !== '') { $title .= ' - ' . $poTitle; }
        $desc = "Procurement Purchase Order.\nPO: {$ref}";
        if (!empty($vendorRow['name'])) { $desc .= "\nVendor: " . (string)$vendorRow['name']; }
        if (!empty($poRow['request_id'])) { $desc .= "\nRequest ID: " . (int)$poRow['request_id']; }

        $cols = ['title','category','amount','expense_date','description','status','recorded_by_user_id','recorded_by_role','reference_number','vendor_id'];
        $vals = [$title, 'Procurement', (float)($poRow['approved_amount'] ?? 0), date('Y-m-d H:i:s'), $desc, 'approved', $uid ?: null, $roleNorm !== '' ? $roleNorm : null, $ref, (int)($poRow['vendor_id'] ?? 0) ?: null];

        if (function_exists('tableHasColumn') && tableHasColumn('expenses_manual', 'department')) { $cols[] = 'department'; $vals[] = 'Procurement'; }
        if ($companyId > 0 && function_exists('tableHasColumn') && tableHasColumn('expenses_manual', 'company_id')) { $cols[] = 'company_id'; $vals[] = $companyId; }
        if (function_exists('tableHasColumn') && tableHasColumn('expenses_manual', 'approved_by')) { $cols[] = 'approved_by'; $vals[] = $uid ?: null; }
        if (function_exists('tableHasColumn') && tableHasColumn('expenses_manual', 'approved_at')) { $cols[] = 'approved_at'; $vals[] = date('Y-m-d H:i:s'); }

        $sql = "INSERT INTO expenses_manual (" . implode(',', $cols) . ") VALUES (" . implode(',', array_fill(0, count($cols), '?')) . ")";
        $pdo->prepare($sql)->execute($vals);
    } catch (Throwable $e) {}
};

$action = strtolower(trim((string)($_GET['action'] ?? '')));
$id = (int)($_GET['id'] ?? 0);

if ($action === 'pdf' && $id > 0) {
    try {
        require_once __DIR__ . '/includes/doc_generator.php';
        $gen = new DocGenerator($pdo);
        $pdfPath = null;
        if (method_exists($gen, 'generateProcurementPurchaseOrderPdf')) {
            $pdfPath = $gen->generateProcurementPurchaseOrderPdf($id, $uid);
        }
        if ($pdfPath && is_file($pdfPath)) {
            header('Content-Type: application/pdf');
            header('Content-Disposition: inline; filename="Purchase_Order_' . $id . '.pdf"');
            header('Content-Length: ' . filesize($pdfPath));
            readfile($pdfPath);
            exit;
        }
        $error = 'PDF generation unavailable.';
    } catch (Throwable $e) {
        $error = 'Failed to generate PDF.';
    }
}

if ($action === 'create_from_request' && $id > 0) {
    if (!$canManage) {
        header('Location: procurement-requests.php?action=view&id=' . $id);
        exit;
    }
    try {
        $p = [$id];
        $sql = "SELECT * FROM procurement_requests WHERE id = ? LIMIT 1";
        if ($companyId > 0 && function_exists('tableHasColumn') && tableHasColumn('procurement_requests','company_id')) { $sql = "SELECT * FROM procurement_requests WHERE id = ? AND (company_id = ? OR company_id IS NULL) LIMIT 1"; $p = [$id, $companyId]; }
        $st = $pdo->prepare($sql);
        $st->execute($p);
        $req = $st->fetch(PDO::FETCH_ASSOC) ?: null;
        if (!$req || strtolower((string)($req['status'] ?? '')) !== 'approved') {
            header('Location: procurement-requests.php?action=view&id=' . $id);
            exit;
        }
        $qid = (int)($req['selected_quotation_id'] ?? 0);
        if ($qid <= 0) {
            header('Location: procurement-quotations.php?request_id=' . $id);
            exit;
        }
        $st = $pdo->prepare("SELECT * FROM procurement_quotations WHERE id = ? AND request_id = ? LIMIT 1");
        $st->execute([$qid, $id]);
        $q = $st->fetch(PDO::FETCH_ASSOC) ?: null;
        if (!$q) {
            header('Location: procurement-quotations.php?request_id=' . $id);
            exit;
        }
        $vendorId = (int)($q['vendor_id'] ?? 0);
        if ($vendorId <= 0) {
            header('Location: procurement-quotations.php?request_id=' . $id);
            exit;
        }

        $tempNo = 'PO-TEMP-' . date('YmdHis') . '-' . (string)mt_rand(1000, 9999);
        $poTitle = trim((string)($req['title'] ?? ''));
        $currency = trim((string)($q['currency'] ?? ($req['currency'] ?? 'NGN')));
        $curUp = strtoupper($currency);
        if ($curUp === '₦' || $curUp === 'N' || $curUp === 'NAIRA') { $currency = 'NGN'; }
        if ($currency === '') { $currency = 'NGN'; }
        $amt = (float)($q['amount'] ?? ($req['estimated_amount'] ?? 0));
        $expected = trim((string)($req['required_date'] ?? ''));
        $expected = ($expected !== '' ? $expected : null);

        $pdo->prepare("INSERT INTO procurement_purchase_orders (company_id, po_number, request_id, vendor_id, quotation_id, title, currency, approved_amount, expected_delivery_date, status, created_by) VALUES (?,?,?,?,?,?,?,?,?,?,?)")
            ->execute([$companyId ?: null, $tempNo, $id, $vendorId, $qid, ($poTitle !== '' ? $poTitle : null), $currency, $amt, $expected, 'draft', $uid ?: null]);
        $poId = (int)$pdo->lastInsertId();
        $poNo = 'PO-' . date('Y') . '-' . str_pad((string)$poId, 6, '0', STR_PAD_LEFT);
        $pdo->prepare("UPDATE procurement_purchase_orders SET po_number = ? WHERE id = ?")->execute([$poNo, $poId]);

        $pdo->prepare("UPDATE procurement_requests SET status = 'converted_to_po', updated_at = NOW() WHERE id = ?")->execute([$id]);
        $insReqHistory($id, 'converted_to_po', 'Converted to PO: ' . $poNo);
        $insPoHistory($poId, 'create', null, 'draft', 'Created from request #' . $id);

        header('Location: procurement-po.php?action=view&id=' . $poId);
        exit;
    } catch (Throwable $e) {
        $error = 'Failed to create PO.';
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!ap_csrf_verify(ap_csrf_from_request())) {
        $error = 'Invalid CSRF token.';
    } else {
        $formAction = strtolower(trim((string)($_POST['form_action'] ?? '')));
        try {
            if ($formAction === 'add_item' && $canManage) {
                $poId = (int)($_POST['po_id'] ?? 0);
                $desc = trim((string)($_POST['description'] ?? ''));
                $qty = (float)str_replace([',',' '], '', (string)($_POST['quantity'] ?? '1'));
                $unit = (float)str_replace([',',' '], '', (string)($_POST['unit_price'] ?? '0'));
                if ($poId <= 0 || $desc === '' || $qty <= 0) {
                    $error = 'Invalid item.';
                } else {
                    $pdo->prepare("INSERT INTO procurement_po_items (po_id, description, quantity, unit_price) VALUES (?,?,?,?)")->execute([$poId, $desc, $qty, $unit]);
                    $insPoHistory($poId, 'item_added', null, null, $desc);
                    header('Location: procurement-po.php?action=view&id=' . $poId);
                    exit;
                }
            } elseif ($formAction === 'transition' && $canManage) {
                $poId = (int)($_POST['po_id'] ?? 0);
                $to = strtolower(trim((string)($_POST['to_status'] ?? '')));
                $note = trim((string)($_POST['note'] ?? ''));
                if ($poId <= 0 || $to === '') {
                    $error = 'Invalid action.';
                } else {
                    $p = [$poId];
                    $sql = "SELECT * FROM procurement_purchase_orders WHERE id = ? LIMIT 1";
                    if ($companyId > 0 && function_exists('tableHasColumn') && tableHasColumn('procurement_purchase_orders','company_id')) { $sql = "SELECT * FROM procurement_purchase_orders WHERE id = ? AND (company_id = ? OR company_id IS NULL) LIMIT 1"; $p = [$poId, $companyId]; }
                    $st = $pdo->prepare($sql);
                    $st->execute($p);
                    $po = $st->fetch(PDO::FETCH_ASSOC) ?: null;
                    if (!$po) {
                        $error = 'PO not found.';
                    } else {
                        $cur = strtolower(trim((string)($po['status'] ?? 'draft')));
                        $allowed = false;
                        if ($to === 'issued') $allowed = ($cur === 'draft');
                        elseif ($to === 'accepted') $allowed = in_array($cur, ['issued'], true);
                        elseif ($to === 'delivered') $allowed = in_array($cur, ['accepted','issued'], true);
                        elseif ($to === 'closed') $allowed = in_array($cur, ['delivered','accepted','issued'], true);
                        if (!$allowed) {
                            $error = 'Invalid transition.';
                        } else {
                            $fields = ['status = ?', 'updated_at = NOW()'];
                            $vals = [$to];
                            if ($to === 'issued') { $fields[] = "issued_at = NOW()"; }
                            if ($to === 'accepted') { $fields[] = "accepted_at = NOW()"; }
                            if ($to === 'delivered') { $fields[] = "delivered_at = NOW()"; }
                            if ($to === 'closed') { $fields[] = "closed_at = NOW()"; }
                            $vals[] = $poId;
                            $pdo->prepare("UPDATE procurement_purchase_orders SET " . implode(',', $fields) . " WHERE id = ?")->execute($vals);
                            $insPoHistory($poId, 'status_change', $cur, $to, ($note !== '' ? $note : null));
                            if ($to === 'issued') {
                                $vendor = null;
                                try {
                                    $stV = $pdo->prepare("SELECT * FROM vendors WHERE id = ? LIMIT 1");
                                    $stV->execute([(int)($po['vendor_id'] ?? 0)]);
                                    $vendor = $stV->fetch(PDO::FETCH_ASSOC) ?: null;
                                } catch (Throwable $e) { $vendor = null; }
                                $ensureProcPayable($po, $vendor);
                                try {
                                    if (function_exists('ap_notify_roles')) {
                                        $poNo = (string)($po['po_number'] ?? '');
                                        $title = (string)($po['title'] ?? '');
                                        ap_notify_roles($pdo, ['finance','finance_manager'], [
                                            'department' => 'Procurement',
                                            'title' => 'PO issued (finance settlement pending)',
                                            'message' => ($poNo !== '' ? $poNo : ('PO #' . (int)$poId)) . ($title !== '' ? (' - ' . $title) : ''),
                                            'type' => 'warning',
                                            'priority' => 'warning',
                                            'related_id' => (int)$poId,
                                            'related_module' => 'procurement-po.php?action=view&id=' . (int)$poId
                                        ]);
                                    }
                                } catch (Throwable $e) {}
                            }
                            header('Location: procurement-po.php?action=view&id=' . $poId);
                            exit;
                        }
                    }
                }
            }
        } catch (Throwable $e) {
            $error = 'Action failed.';
        }
    }
}

if ($action === 'view' && $id > 0) {
    $po = null;
    $items = [];
    $history = [];
    $vendor = null;
    $req = null;
    $deliveries = [];
    $payable = null;
    try {
        $p = [$id];
        $sql = "SELECT po.*, v.name AS vendor_name FROM procurement_purchase_orders po LEFT JOIN vendors v ON v.id = po.vendor_id WHERE po.id = ? LIMIT 1";
        if ($companyId > 0 && function_exists('tableHasColumn') && tableHasColumn('procurement_purchase_orders','company_id')) { $sql = "SELECT po.*, v.name AS vendor_name FROM procurement_purchase_orders po LEFT JOIN vendors v ON v.id = po.vendor_id WHERE po.id = ? AND (po.company_id = ? OR po.company_id IS NULL) LIMIT 1"; $p = [$id, $companyId]; }
        $st = $pdo->prepare($sql);
        $st->execute($p);
        $po = $st->fetch(PDO::FETCH_ASSOC) ?: null;
        if ($po) {
            $st = $pdo->prepare("SELECT * FROM procurement_po_items WHERE po_id = ? ORDER BY id ASC");
            $st->execute([$id]);
            $items = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];
            $st = $pdo->prepare("SELECT h.*, u.name AS actor_name FROM procurement_po_history h LEFT JOIN users u ON u.id = h.actor_id WHERE h.po_id = ? ORDER BY h.created_at DESC, h.id DESC LIMIT 120");
            $st->execute([$id]);
            $history = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];

            if (!empty($po['request_id'])) {
                $st = $pdo->prepare("SELECT id, title, status FROM procurement_requests WHERE id = ? LIMIT 1");
                $st->execute([(int)$po['request_id']]);
                $req = $st->fetch(PDO::FETCH_ASSOC) ?: null;
            }

            $st = $pdo->prepare("SELECT * FROM procurement_deliveries WHERE po_id = ? ORDER BY created_at DESC, id DESC LIMIT 30");
            $st->execute([$id]);
            $deliveries = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];

            if (function_exists('tableHasColumn') && tableHasColumn('expenses_manual', 'reference_number') && $pdo->query("SHOW TABLES LIKE 'expenses_manual'")->rowCount() > 0) {
                $ref = (string)($po['po_number'] ?? '');
                if ($ref !== '') {
                    $p2 = [$ref];
                    $sql2 = "SELECT id, status, amount, posted_at FROM expenses_manual WHERE reference_number = ? AND LOWER(TRIM(category)) = 'procurement' ORDER BY id DESC LIMIT 1";
                    if ($companyId > 0 && function_exists('tableHasColumn') && tableHasColumn('expenses_manual','company_id')) { $sql2 = "SELECT id, status, amount, posted_at FROM expenses_manual WHERE reference_number = ? AND LOWER(TRIM(category)) = 'procurement' AND (company_id = ? OR company_id IS NULL) ORDER BY id DESC LIMIT 1"; $p2 = [$ref, $companyId]; }
                    $st = $pdo->prepare($sql2);
                    $st->execute($p2);
                    $payable = $st->fetch(PDO::FETCH_ASSOC) ?: null;
                }
            }
        }
    } catch (Throwable $e) { $po = null; }

    if (!$po) {
        echo '<div class="container-fluid px-4 py-4"><div class="alert alert-danger">Purchase order not found.</div></div>';
        require_once __DIR__ . '/includes/footer.php';
        exit;
    }

    $status = strtolower(trim((string)($po['status'] ?? 'draft')));
    $statusBadge = [
        'draft' => ['Draft', 'bg-light text-secondary border'],
        'issued' => ['Issued', 'bg-primary'],
        'accepted' => ['Accepted', 'bg-info text-dark'],
        'delivered' => ['Delivered', 'bg-success'],
        'closed' => ['Closed', 'bg-dark'],
    ];
    [$stLbl, $stCls] = $statusBadge[$status] ?? [($po['status'] ?? '—'), 'bg-light text-secondary border'];

    $sumItems = 0.0;
    foreach ($items as $it) {
        $sumItems += ((float)($it['quantity'] ?? 0)) * ((float)($it['unit_price'] ?? 0));
    }
    ?>

    <div class="container-fluid px-4 pb-4">
        <div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center mt-4 mb-3 gap-2">
            <div>
                <div class="d-flex align-items-center gap-2 flex-wrap">
                    <h2 class="text-navy fw-bold mb-0">Purchase Order</h2>
                    <span class="badge <?= $stCls ?>"><?= htmlspecialchars((string)$stLbl) ?></span>
                </div>
                <div class="text-muted mt-1"><?= htmlspecialchars((string)($po['po_number'] ?? '')) ?> • <?= htmlspecialchars((string)($po['vendor_name'] ?? '')) ?></div>
            </div>
            <div class="d-flex gap-2 flex-wrap">
                <a href="procurement-po.php" class="btn btn-outline-secondary">Back</a>
                <a href="procurement-po.php?action=pdf&id=<?= (int)$po['id'] ?>" class="btn btn-outline-primary"><i class="fa-solid fa-file-pdf me-2"></i>PDF</a>
                <?php if ($canManage && $status === 'draft'): ?>
                    <form method="post" class="d-inline">
                        <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
                        <input type="hidden" name="form_action" value="transition">
                        <input type="hidden" name="po_id" value="<?= (int)$po['id'] ?>">
                        <input type="hidden" name="to_status" value="issued">
                        <button type="submit" class="btn btn-primary"><i class="fa-solid fa-paper-plane me-2"></i>Issue</button>
                    </form>
                <?php endif; ?>
            </div>
        </div>

        <?php if ($error !== ''): ?><div class="alert alert-danger"><?= htmlspecialchars($error) ?></div><?php endif; ?>
        <?php if ($notice !== ''): ?><div class="alert alert-success"><?= htmlspecialchars($notice) ?></div><?php endif; ?>

        <div class="row g-3">
            <div class="col-12 col-lg-8">
                <div class="card shadow-sm border-0 mb-3">
                    <div class="card-body">
                        <div class="row g-2">
                            <div class="col-12 col-md-6">
                                <div class="text-muted small fw-bold">Approved Amount</div>
                                <div class="fw-bold"><?= htmlspecialchars((string)($po['currency'] ?? '₦')) ?><?= number_format((float)($po['approved_amount'] ?? 0), 2) ?></div>
                            </div>
                            <div class="col-12 col-md-6">
                                <div class="text-muted small fw-bold">Expected Delivery Date</div>
                                <div class="fw-bold"><?= htmlspecialchars((string)($po['expected_delivery_date'] ?? '—')) ?></div>
                            </div>
                            <?php if ($req): ?>
                                <div class="col-12">
                                    <div class="text-muted small fw-bold">Linked Request</div>
                                    <a class="fw-semibold text-decoration-none" href="procurement-requests.php?action=view&id=<?= (int)$req['id'] ?>">
                                        <?= htmlspecialchars((string)($req['title'] ?? '')) ?>
                                    </a>
                                </div>
                            <?php endif; ?>
                        </div>

                        <?php if ($payable): ?>
                            <div class="alert alert-light border mt-3 mb-0">
                                <div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
                                    <div>
                                        <div class="fw-bold">Finance Sync</div>
                                        <div class="text-muted small">Linked payable record exists in Finance → Payables.</div>
                                    </div>
                                    <div class="text-end">
                                        <div class="fw-bold">₦<?= number_format((float)($payable['amount'] ?? 0), 2) ?></div>
                                        <div class="text-muted small"><?= htmlspecialchars((string)($payable['posted_at'] ?? 'Not settled')) ?></div>
                                    </div>
                                </div>
                            </div>
                        <?php endif; ?>
                    </div>
                </div>

                <div class="card shadow-sm border-0 mb-3">
                    <div class="card-header bg-white d-flex justify-content-between align-items-center">
                        <div class="fw-bold">Items</div>
                        <div class="text-muted small">Total: <?= htmlspecialchars((string)($po['currency'] ?? '₦')) ?><?= number_format($sumItems, 2) ?></div>
                    </div>
                    <div class="card-body p-0">
                        <div class="table-responsive">
                            <table class="table table-hover align-middle mb-0">
                                <thead class="bg-light">
                                    <tr>
                                        <th>Description</th>
                                        <th class="text-end">Qty</th>
                                        <th class="text-end">Unit</th>
                                        <th class="text-end">Line Total</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php if (empty($items)): ?>
                                        <tr><td colspan="4" class="text-muted fst-italic py-4 px-3">No items added yet.</td></tr>
                                    <?php else: ?>
                                        <?php foreach ($items as $it): ?>
                                            <?php $line = ((float)($it['quantity'] ?? 0)) * ((float)($it['unit_price'] ?? 0)); ?>
                                            <tr>
                                                <td class="fw-semibold"><?= htmlspecialchars((string)($it['description'] ?? '')) ?></td>
                                                <td class="text-end"><?= number_format((float)($it['quantity'] ?? 0), 2) ?></td>
                                                <td class="text-end"><?= number_format((float)($it['unit_price'] ?? 0), 2) ?></td>
                                                <td class="text-end"><?= number_format($line, 2) ?></td>
                                            </tr>
                                        <?php endforeach; ?>
                                    <?php endif; ?>
                                </tbody>
                            </table>
                        </div>
                    </div>
                    <?php if ($canManage && $status === 'draft'): ?>
                        <div class="card-body border-top">
                            <form method="post" class="row g-2">
                                <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
                                <input type="hidden" name="form_action" value="add_item">
                                <input type="hidden" name="po_id" value="<?= (int)$po['id'] ?>">
                                <div class="col-12 col-md-6">
                                    <label class="form-label small text-muted fw-bold">Item</label>
                                    <input name="description" class="form-control" required>
                                </div>
                                <div class="col-6 col-md-2">
                                    <label class="form-label small text-muted fw-bold">Qty</label>
                                    <input name="quantity" class="form-control" inputmode="decimal" value="1">
                                </div>
                                <div class="col-6 col-md-2">
                                    <label class="form-label small text-muted fw-bold">Unit Price</label>
                                    <input name="unit_price" class="form-control" inputmode="decimal" value="0">
                                </div>
                                <div class="col-12 col-md-2 d-grid align-items-end">
                                    <button class="btn btn-outline-primary mt-md-4" type="submit">Add</button>
                                </div>
                            </form>
                        </div>
                    <?php endif; ?>
                </div>

                <div class="card shadow-sm border-0">
                    <div class="card-header bg-white fw-bold">Deliveries</div>
                    <div class="card-body p-0">
                        <div class="table-responsive">
                            <table class="table table-hover align-middle mb-0">
                                <thead class="bg-light">
                                    <tr>
                                        <th>Date</th>
                                        <th>Status</th>
                                        <th>Received By</th>
                                        <th>Evidence</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php if (empty($deliveries)): ?>
                                        <tr><td colspan="4" class="text-muted fst-italic py-4 px-3">No delivery records yet.</td></tr>
                                    <?php else: ?>
                                        <?php foreach ($deliveries as $d): ?>
                                            <tr>
                                                <td><?= htmlspecialchars((string)($d['delivery_date'] ?? '')) ?></td>
                                                <td><?= htmlspecialchars((string)($d['delivery_status'] ?? '')) ?></td>
                                                <td><?= htmlspecialchars((string)($d['received_by'] ?? '')) ?></td>
                                                <td>
                                                    <?php if (!empty($d['attachment_path'])): ?>
                                                        <a target="_blank" href="<?= htmlspecialchars((string)$d['attachment_path']) ?>">View</a>
                                                    <?php else: ?>
                                                        <span class="text-muted">—</span>
                                                    <?php endif; ?>
                                                </td>
                                            </tr>
                                        <?php endforeach; ?>
                                    <?php endif; ?>
                                </tbody>
                            </table>
                        </div>
                    </div>
                    <div class="card-body border-top">
                        <a href="procurement-deliveries.php?po_id=<?= (int)$po['id'] ?>" class="btn btn-sm btn-outline-secondary">Manage Deliveries</a>
                    </div>
                </div>
            </div>

            <div class="col-12 col-lg-4">
                <div class="card shadow-sm border-0 mb-3">
                    <div class="card-header bg-white fw-bold">Status Actions</div>
                    <div class="card-body">
                        <?php if ($canManage): ?>
                            <form method="post" class="d-flex flex-column gap-2">
                                <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
                                <input type="hidden" name="form_action" value="transition">
                                <input type="hidden" name="po_id" value="<?= (int)$po['id'] ?>">
                                <textarea name="note" class="form-control" rows="2" placeholder="Note (optional)"></textarea>
                                <div class="d-grid gap-2">
                                    <?php if ($status === 'issued'): ?>
                                        <button name="to_status" value="accepted" class="btn btn-outline-primary" type="submit">Mark Accepted</button>
                                    <?php endif; ?>
                                    <?php if (in_array($status, ['issued','accepted'], true)): ?>
                                        <button name="to_status" value="delivered" class="btn btn-outline-success" type="submit">Mark Delivered</button>
                                    <?php endif; ?>
                                    <?php if (in_array($status, ['issued','accepted','delivered'], true)): ?>
                                        <button name="to_status" value="closed" class="btn btn-dark" type="submit">Close PO</button>
                                    <?php endif; ?>
                                </div>
                            </form>
                        <?php else: ?>
                            <div class="text-muted">No actions available.</div>
                        <?php endif; ?>
                    </div>
                </div>

                <div class="card shadow-sm border-0">
                    <div class="card-header bg-white fw-bold">Approval Trail</div>
                    <div class="card-body">
                        <?php if (empty($history)): ?>
                            <div class="text-muted fst-italic">No history yet.</div>
                        <?php else: ?>
                            <div class="d-flex flex-column gap-2">
                                <?php foreach ($history as $h): ?>
                                    <div class="border rounded-3 p-2">
                                        <div class="d-flex justify-content-between align-items-center">
                                            <div class="fw-semibold"><?= htmlspecialchars((string)($h['action'] ?? '')) ?></div>
                                            <div class="text-muted small"><?= htmlspecialchars((string)($h['created_at'] ?? '')) ?></div>
                                        </div>
                                        <div class="text-muted small"><?= htmlspecialchars((string)($h['actor_name'] ?? 'System')) ?></div>
                                        <?php if (!empty($h['note'])): ?>
                                            <div class="text-muted mt-1" style="white-space:pre-wrap;"><?= htmlspecialchars((string)$h['note']) ?></div>
                                        <?php endif; ?>
                                    </div>
                                <?php endforeach; ?>
                            </div>
                        <?php endif; ?>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <?php
    require_once __DIR__ . '/includes/footer.php';
    exit;
}

$q = trim((string)($_GET['q'] ?? ''));
$statusFilter = strtolower(trim((string)($_GET['status'] ?? '')));
$page = max(1, (int)($_GET['page'] ?? 1));
$perPage = 15;
$offset = ($page - 1) * $perPage;
$rows = [];
$total = 0;

try {
    $where = ["1=1"];
    $params = [];
    if ($companyId > 0 && function_exists('tableHasColumn') && tableHasColumn('procurement_purchase_orders','company_id')) { $where[] = "(po.company_id = ? OR po.company_id IS NULL)"; $params[] = $companyId; }
    if ($q !== '') { $where[] = "(LOWER(po.po_number) LIKE ? OR LOWER(COALESCE(po.title,'')) LIKE ? OR LOWER(COALESCE(v.name,'')) LIKE ?)"; $like = '%' . strtolower($q) . '%'; $params[] = $like; $params[] = $like; $params[] = $like; }
    if ($statusFilter !== '') { $where[] = "LOWER(TRIM(po.status)) = ?"; $params[] = $statusFilter; }
    $w = implode(' AND ', $where);

    $st = $pdo->prepare("SELECT COUNT(*) FROM procurement_purchase_orders po LEFT JOIN vendors v ON v.id = po.vendor_id WHERE $w");
    $st->execute($params);
    $total = (int)($st->fetchColumn() ?: 0);

    $st = $pdo->prepare("SELECT po.id, po.po_number, po.title, po.status, po.approved_amount, po.currency, po.created_at, v.name AS vendor_name FROM procurement_purchase_orders po LEFT JOIN vendors v ON v.id = po.vendor_id WHERE $w ORDER BY po.created_at DESC, po.id DESC LIMIT $perPage OFFSET $offset");
    $st->execute($params);
    $rows = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];
} catch (Throwable $e) { $rows = []; }

$totalPages = max(1, (int)ceil($total / $perPage));
if ($page > $totalPages) $page = $totalPages;

$statusBadge = [
    'draft' => ['Draft', 'bg-light text-secondary border'],
    'issued' => ['Issued', 'bg-primary'],
    'accepted' => ['Accepted', 'bg-info text-dark'],
    'delivered' => ['Delivered', 'bg-success'],
    'closed' => ['Closed', 'bg-dark'],
];

?>

<div class="container-fluid px-4 pb-4">
    <div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center mt-4 mb-3 gap-2">
        <div>
            <h2 class="text-navy fw-bold mb-1">Purchase Orders</h2>
            <div class="text-muted">Issue POs, confirm delivery, and sync obligations to Finance.</div>
        </div>
        <div class="d-flex gap-2 flex-wrap">
            <a href="procurement-dashboard.php" class="btn btn-outline-secondary">Dashboard</a>
            <a href="procurement-requests.php" class="btn btn-outline-secondary">Requests</a>
        </div>
    </div>

    <?php if ($error !== ''): ?><div class="alert alert-danger"><?= htmlspecialchars($error) ?></div><?php endif; ?>
    <?php if ($notice !== ''): ?><div class="alert alert-success"><?= htmlspecialchars($notice) ?></div><?php endif; ?>

    <div class="card shadow-sm border-0">
        <div class="card-body">
            <form method="get" class="row g-2 align-items-end mb-3">
                <div class="col-12 col-md-6">
                    <label class="form-label small text-muted fw-bold">Search</label>
                    <input name="q" class="form-control" value="<?= htmlspecialchars($q) ?>" placeholder="PO number / title / vendor">
                </div>
                <div class="col-12 col-md-3">
                    <label class="form-label small text-muted fw-bold">Status</label>
                    <select name="status" class="form-select">
                        <option value="">All</option>
                        <?php foreach ($statusBadge as $k => $meta): ?>
                            <option value="<?= htmlspecialchars($k) ?>" <?= $statusFilter === $k ? 'selected' : '' ?>><?= htmlspecialchars((string)$meta[0]) ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <div class="col-12 col-md-3 d-flex gap-2 justify-content-end">
                    <a href="procurement-po.php" class="btn btn-outline-secondary">Reset</a>
                    <button class="btn btn-primary" type="submit">Filter</button>
                </div>
            </form>

            <div class="table-responsive">
                <table class="table table-hover align-middle mb-0">
                    <thead class="bg-light">
                        <tr>
                            <th>PO</th>
                            <th>Vendor</th>
                            <th>Status</th>
                            <th class="text-end">Amount</th>
                            <th class="text-end">Open</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php if (empty($rows)): ?>
                            <tr><td colspan="5" class="text-muted fst-italic py-4">No purchase orders found.</td></tr>
                        <?php else: ?>
                            <?php foreach ($rows as $r): ?>
                                <?php
                                    $stKey = strtolower(trim((string)($r['status'] ?? 'draft')));
                                    [$lbl, $cls] = $statusBadge[$stKey] ?? [($r['status'] ?? '—'), 'bg-light text-secondary border'];
                                ?>
                                <tr>
                                    <td class="fw-semibold">
                                        <?= htmlspecialchars((string)($r['po_number'] ?? '')) ?>
                                        <div class="text-muted small"><?= htmlspecialchars((string)($r['title'] ?? '')) ?></div>
                                    </td>
                                    <td><?= htmlspecialchars((string)($r['vendor_name'] ?? '')) ?></td>
                                    <td><span class="badge <?= $cls ?>"><?= htmlspecialchars((string)$lbl) ?></span></td>
                                    <td class="text-end"><?= htmlspecialchars((string)($r['currency'] ?? '₦')) ?><?= number_format((float)($r['approved_amount'] ?? 0), 2) ?></td>
                                    <td class="text-end">
                                        <a class="btn btn-sm btn-outline-primary" href="procurement-po.php?action=view&id=<?= (int)$r['id'] ?>">View</a>
                                    </td>
                                </tr>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </tbody>
                </table>
            </div>

            <div class="d-flex justify-content-between align-items-center mt-3">
                <div class="text-muted small">Showing <?= number_format(count($rows)) ?> of <?= number_format($total) ?></div>
                <nav>
                    <ul class="pagination pagination-sm mb-0">
                        <?php
                            $mkUrl = function(int $p) use ($q, $statusFilter) {
                                $params = [];
                                if ($q !== '') $params['q'] = $q;
                                if ($statusFilter !== '') $params['status'] = $statusFilter;
                                $params['page'] = $p;
                                return 'procurement-po.php?' . http_build_query($params);
                            };
                        ?>
                        <li class="page-item <?= $page <= 1 ? 'disabled' : '' ?>"><a class="page-link" href="<?= htmlspecialchars($mkUrl(max(1, $page - 1))) ?>">Prev</a></li>
                        <li class="page-item disabled"><span class="page-link"><?= (int)$page ?>/<?= (int)$totalPages ?></span></li>
                        <li class="page-item <?= $page >= $totalPages ? 'disabled' : '' ?>"><a class="page-link" href="<?= htmlspecialchars($mkUrl(min($totalPages, $page + 1))) ?>">Next</a></li>
                    </ul>
                </nav>
            </div>
        </div>
    </div>
</div>

<?php require_once __DIR__ . '/includes/footer.php'; ?>

Hry