JezK
Edit File: process_financial.php
<?php require_once __DIR__ . '/../config/auth.php'; require_role('operator', 'admin', 'accountant'); if (!verify_csrf_token($_POST['csrf_token'] ?? '')) die('Invalid CSRF'); $pdo = db(); $user = current_user(); $lab_id = $user['lab_id']; $action = $_POST['action'] ?? ''; function redirect_back(string $page): void { header("Location: $page"); exit; } // ─── Collect Installment ────────────────────────────────────────── if ($action === 'collect_installment') { require_role('operator'); $bill_id = (int)($_POST['billing_id'] ?? 0); $amount = max(0, (float)($_POST['amount'] ?? 0)); $mode = in_array($_POST['payment_mode'] ?? '', ['cash','upi','card']) ? $_POST['payment_mode'] : 'cash'; $bill = $pdo->prepare("SELECT b.*, p.lab_id AS p_lab_id FROM billings b JOIN patients p ON p.id=b.patient_id WHERE b.id=?"); $bill->execute([$bill_id]); $bill = $bill->fetch(); if (!$bill || $bill['p_lab_id'] != $lab_id || $bill['status'] === 'paid') { set_flash('error', 'Invalid or already paid billing.'); redirect_back('../operator/billing_history.php'); } $due = max(0, $bill['total_amount'] - $bill['paid_amount']); $amount = min($amount, $due); if ($amount <= 0) { set_flash('error','Invalid amount.'); redirect_back('../operator/billing_history.php'); } $inst_status = ($mode === 'cash') ? 'pending' : 'verified'; $pdo->prepare("INSERT INTO installments (billing_id, amount, paid_on, payment_mode, status) VALUES (?, ?, NOW(), ?, ?)") ->execute([$bill_id, $amount, $mode, $inst_status]); $new_paid = $bill['paid_amount'] + $amount; $new_status = ($new_paid >= $bill['total_amount']) ? 'paid' : 'partial'; $pdo->prepare("UPDATE billings SET paid_amount=?, status=? WHERE id=?") ->execute([$new_paid, $new_status, $bill_id]); set_flash('success', "₹" . number_format($amount, 2) . " collected successfully."); redirect_back('../operator/billing_history.php'); } // ─── Request Refund ─────────────────────────────────────────────── if ($action === 'request_refund') { require_role('operator'); $bill_id = (int)($_POST['billing_id'] ?? 0); $amount = max(0, (float)($_POST['amount'] ?? 0)); $reason = trim($_POST['reason'] ?? ''); $bill = $pdo->prepare("SELECT b.*, p.lab_id AS p_lab_id FROM billings b JOIN patients p ON p.id=b.patient_id WHERE b.id=?"); $bill->execute([$bill_id]); $bill = $bill->fetch(); if (!$bill || $bill['p_lab_id'] != $lab_id || $amount > $bill['paid_amount'] || $amount <= 0 || empty($reason)) { set_flash('error', 'Invalid refund request.'); redirect_back('../operator/billing_history.php'); } $pdo->prepare("INSERT INTO refund_requests (lab_id, patient_id, reference_id, operator_id, amount, reason) VALUES (?,?,?,?,?,?)") ->execute([$lab_id, $bill['patient_id'], $bill_id, $user['id'], $amount, $reason]); set_flash('success', "Refund of ₹" . number_format($amount, 2) . " requested. Awaiting admin approval."); redirect_back('../operator/billing_history.php'); } // ─── Submit EOD Cash Declaration ────────────────────────────────── if ($action === 'submit_eod') { require_role('operator'); $declared = max(0, (float)($_POST['declared_cash'] ?? 0)); $today = date('Y-m-d'); if (isset($_POST['deposit_date']) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $_POST['deposit_date']) && $_POST['deposit_date'] <= $today) { $today = $_POST['deposit_date']; } $exists = $pdo->prepare("SELECT id FROM cash_deposits WHERE operator_id=? AND deposit_date=? AND lab_id=?"); $exists->execute([$user['id'], $today, $lab_id]); if ($exists->fetch()) { set_flash('error', 'EOD already submitted for today.'); redirect_back('../operator/eod_closure.php'); } // Calculate system expected cash (cash installments for this lab/operator today) $sys = $pdo->prepare("SELECT COALESCE(SUM(i.amount),0) FROM installments i JOIN billings b ON b.id=i.billing_id JOIN patients p ON p.id=b.patient_id WHERE p.lab_id=? AND i.payment_mode='cash' AND DATE(i.paid_on)=?"); $sys->execute([$lab_id, $today]); $system_cash = (float)$sys->fetchColumn(); $pdo->prepare("INSERT INTO cash_deposits (lab_id, operator_id, deposit_date, system_cash_calculated, declared_cash) VALUES (?,?,?,?,?)") ->execute([$lab_id, $user['id'], $today, $system_cash, $declared]); $dep_id = $pdo->lastInsertId(); log_audit('submit_eod', 'cash_deposits', $dep_id, null, ['declared_cash' => $declared, 'system_cash' => $system_cash, 'date' => $today]); set_flash('success', 'EOD closure submitted successfully.'); redirect_back('../operator/eod_closure.php'); } // ─── Submit Bank Deposit ────────────────────────────────────────── if ($action === 'submit_bank_deposit') { require_role('operator'); $amount = max(0, (float)($_POST['amount'] ?? 0)); $dep_date = sanitize_input($_POST['deposit_date'] ?? date('Y-m-d')); $bank_name = sanitize_input($_POST['bank_name'] ?? ''); $ref_number = sanitize_input($_POST['reference_number'] ?? ''); if ($amount <= 0) { set_flash('error', 'Invalid amount.'); redirect_back('../operator/bank_deposit.php'); } $pdo->prepare("INSERT INTO bank_deposits (lab_id, deposited_by, amount, deposit_date, bank_name, reference_number) VALUES (?,?,?,?,?,?)") ->execute([$lab_id, $user['id'], $amount, $dep_date, $bank_name, $ref_number]); $dep_id = $pdo->lastInsertId(); log_audit('submit_bank_deposit', 'bank_deposits', $dep_id, null, ['amount' => $amount, 'bank' => $bank_name, 'ref' => $ref_number]); set_flash('success', 'Bank deposit logged. Awaiting accountant verification.'); redirect_back('../operator/bank_deposit.php'); } // ─── Accountant/Admin: Verify EOD ──────────────────────────────── if (in_array($action, ['verify_eod','flag_eod'])) { require_role('accountant', 'admin'); $id = (int)($_POST['id'] ?? 0); $notes = sanitize_input($_POST['notes'] ?? ''); $stmt = $pdo->prepare("SELECT status, notes FROM cash_deposits WHERE id=?"); $stmt->execute([$id]); $old_record = $stmt->fetch(PDO::FETCH_ASSOC); $status = ($action === 'verify_eod') ? 'verified' : 'discrepancy'; $pdo->prepare("UPDATE cash_deposits SET status=?, verified_by=?, notes=? WHERE id=?") ->execute([$status, $user['id'], $notes, $id]); log_audit($action, 'cash_deposits', $id, $old_record, ['status' => $status, 'notes' => $notes]); set_flash('success', 'EOD record updated.'); redirect_back('../accountant/cash_reconciliation.php'); } // ─── Accountant/Admin: Verify Bank Deposit ──────────────────────── if ($action === 'verify_bank') { require_role('accountant', 'admin'); $id = (int)($_POST['id'] ?? 0); $stmt = $pdo->prepare("SELECT status FROM bank_deposits WHERE id=?"); $stmt->execute([$id]); $old_record = $stmt->fetch(PDO::FETCH_ASSOC); $pdo->prepare("UPDATE bank_deposits SET status='verified', verified_by=? WHERE id=?") ->execute([$user['id'], $id]); log_audit('verify_bank', 'bank_deposits', $id, $old_record, ['status' => 'verified']); set_flash('success', 'Bank deposit verified.'); redirect_back('../accountant/cash_reconciliation.php'); } // ─── Admin: Approve/Reject Refund ──────────────────────────────── if (in_array($action, ['approve_refund','reject_refund'])) { require_role('admin'); $id = (int)($_POST['id'] ?? 0); $status = ($action === 'approve_refund') ? 'approved' : 'rejected'; $pdo->prepare("UPDATE refund_requests SET status=?, approved_by=?, processed_at=NOW() WHERE id=?") ->execute([$status, $user['id'], $id]); if ($status === 'approved') { $rr = $pdo->prepare("SELECT * FROM refund_requests WHERE id=?"); $rr->execute([$id]); $rr = $rr->fetch(); if ($rr) { $pdo->prepare("UPDATE billings SET paid_amount = GREATEST(0, paid_amount - ?), status = IF(paid_amount - ? <= 0, 'partial', status) WHERE id=?") ->execute([$rr['amount'], $rr['amount'], $rr['reference_id']]); } } set_flash('success', "Refund request {$status}."); redirect_back('../accountant/cash_reconciliation.php'); } set_flash('error', 'Unknown action.'); redirect_back('../operator/billing_history.php');