View file File name : api.php Content :<?php /** * OmniFlow SaaS API Handler */ session_start(); date_default_timezone_set('America/Belize'); require_once '_helpers.php'; $conn = get_db_connection(); if (!$conn) { echo json_encode(['success' => false, 'message' => 'Database connection failed']); exit; } // --- DATABASE INITIALIZATION --- $conn->query("CREATE TABLE IF NOT EXISTS business_settings ( id INT PRIMARY KEY, businessName VARCHAR(100) DEFAULT 'OmniFlow', ratePerUnit DECIMAL(10,2) DEFAULT 0.15, primary_color VARCHAR(20) DEFAULT '#2563eb', logo_url VARCHAR(255) DEFAULT '', phone VARCHAR(20) DEFAULT '', support_phone VARCHAR(20) DEFAULT '5016115121', bank_name VARCHAR(100) DEFAULT '', bank_account_name VARCHAR(100) DEFAULT '', bank_number VARCHAR(100) DEFAULT '' )"); // SCHEMA SYNC: Ensure all columns exist in business_settings $cols_needed = [ 'businessName' => "VARCHAR(100) DEFAULT 'OmniFlow'", 'ratePerUnit' => "DECIMAL(10,2) DEFAULT 0.15", 'primary_color' => "VARCHAR(20) DEFAULT '#2563eb'", 'logo_url' => "VARCHAR(255) DEFAULT ''", 'phone' => "VARCHAR(20) DEFAULT ''", 'support_phone' => "VARCHAR(20) DEFAULT '5016115121'", 'bank_name' => "VARCHAR(100) DEFAULT ''", 'bank_account_name' => "VARCHAR(100) DEFAULT ''", 'bank_number' => "VARCHAR(100) DEFAULT ''" ]; foreach ($cols_needed as $col => $def) { $check = $conn->query("SHOW COLUMNS FROM business_settings LIKE '$col'"); if ($check && $check->num_rows == 0) { $conn->query("ALTER TABLE business_settings ADD COLUMN $col $def"); } } // Ensure at least one settings row exists $conn->query("INSERT IGNORE INTO business_settings (id, businessName) VALUES (1, 'OmniFlow')"); $conn->query("CREATE TABLE IF NOT EXISTS admins ( id VARCHAR(50) PRIMARY KEY, name VARCHAR(100) NOT NULL, username VARCHAR(50) UNIQUE NOT NULL, phone VARCHAR(20) DEFAULT '', password VARCHAR(255) NOT NULL )"); $check_admin_phone = $conn->query("SHOW COLUMNS FROM admins LIKE 'phone'"); if ($check_admin_phone && $check_admin_phone->num_rows == 0) { $conn->query("ALTER TABLE admins ADD COLUMN phone VARCHAR(20) DEFAULT ''"); } $conn->query("INSERT IGNORE INTO admins (id, name, username, password) VALUES ('adm_1', 'Admin', 'admin', 'admin123')"); $conn->query("CREATE TABLE IF NOT EXISTS agents ( id VARCHAR(50) PRIMARY KEY, name VARCHAR(100) NOT NULL, username VARCHAR(50) UNIQUE NOT NULL, phone VARCHAR(20) DEFAULT '', password VARCHAR(255) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP )"); $check_agent_phone = $conn->query("SHOW COLUMNS FROM agents LIKE 'phone'"); if ($check_agent_phone && $check_agent_phone->num_rows == 0) { $conn->query("ALTER TABLE agents ADD COLUMN phone VARCHAR(20) DEFAULT ''"); } $conn->query("CREATE TABLE IF NOT EXISTS customers ( id VARCHAR(50) PRIMARY KEY, name VARCHAR(100) NOT NULL, username VARCHAR(50) UNIQUE NOT NULL, phone VARCHAR(20) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, balance DECIMAL(10,2) DEFAULT 0.00, status VARCHAR(50) DEFAULT 'Active', qrCodeValue VARCHAR(100), meter_number VARCHAR(50) DEFAULT '', is_golden_citizen TINYINT(1) DEFAULT 0, prev_meter_reading BIGINT DEFAULT 0, curr_meter_reading BIGINT DEFAULT 0, joinedDate DATETIME DEFAULT CURRENT_TIMESTAMP )"); // SCHEMA SYNC: Ensure columns exist in customers $cust_cols_needed = [ 'meter_number' => "VARCHAR(50) DEFAULT ''", 'is_golden_citizen' => "TINYINT(1) DEFAULT 0", 'prev_meter_reading' => "BIGINT DEFAULT 0", 'curr_meter_reading' => "BIGINT DEFAULT 0" ]; foreach ($cust_cols_needed as $col => $def) { $check = $conn->query("SHOW COLUMNS FROM customers LIKE '$col'"); if ($check && $check->num_rows == 0) { $conn->query("ALTER TABLE customers ADD COLUMN $col $def"); } } $conn->query("CREATE TABLE IF NOT EXISTS readings ( id INT AUTO_INCREMENT PRIMARY KEY, customer_id VARCHAR(50), prev_reading BIGINT, current_reading BIGINT, consumption BIGINT, amount DECIMAL(10,2), reading_date DATETIME DEFAULT CURRENT_TIMESTAMP, recorded_by VARCHAR(50), FOREIGN KEY (customer_id) REFERENCES customers(id) )"); $conn->query("CREATE TABLE IF NOT EXISTS payments ( id INT AUTO_INCREMENT PRIMARY KEY, customer_id VARCHAR(50), amount DECIMAL(10,2), method VARCHAR(50), payment_date DATETIME DEFAULT CURRENT_TIMESTAMP, recorded_by VARCHAR(50), FOREIGN KEY (customer_id) REFERENCES customers(id) )"); $conn->query("CREATE TABLE IF NOT EXISTS expenses ( id INT AUTO_INCREMENT PRIMARY KEY, amount DECIMAL(10,2) NOT NULL, category VARCHAR(100) NOT NULL, description TEXT, date DATETIME DEFAULT CURRENT_TIMESTAMP, recorded_by VARCHAR(100) )"); $action = $_POST['action'] ?? $_GET['action'] ?? ''; // --- PUBLIC ACTIONS --- if ($action === 'login') { $type = $_POST['type'] ?? 'customer'; $user_in = $_POST['username'] ?? ''; $pass_in = $_POST['password'] ?? ''; if ($type === 'admin') { $stmt = $conn->prepare("SELECT * FROM admins WHERE username = ?"); $stmt->bind_param("s", $user_in); } elseif ($type === 'agent') { $stmt = $conn->prepare("SELECT * FROM agents WHERE username = ?"); $stmt->bind_param("s", $user_in); } else { $stmt = $conn->prepare("SELECT * FROM customers WHERE phone = ? OR username = ?"); $stmt->bind_param("ss", $user_in, $user_in); } $stmt->execute(); $res = get_stmt_result($stmt); if (!empty($res)) { $user = $res[0]; $is_valid = password_verify($pass_in, $user['password']) || $pass_in === $user['password']; if ($is_valid) { $_SESSION['user_id'] = $user['id']; $_SESSION['user_type'] = $type; $_SESSION['user_name'] = $user['name']; // Re-hash if needed if ($pass_in === $user['password'] && !password_get_info($user['password'])['algo']) { $new_hash = password_hash($pass_in, PASSWORD_DEFAULT); $table = ($type === 'admin') ? 'admins' : (($type === 'agent') ? 'agents' : 'customers'); $conn->query("UPDATE $table SET password = '$new_hash' WHERE id = '{$user['id']}'"); } unset($user['password']); echo json_encode(['success' => true, 'userType' => $type, 'user' => $user]); } else { echo json_encode(['success' => false, 'message' => 'Invalid password']); } } else { echo json_encode(['success' => false, 'message' => $type === 'customer' ? 'Credentials not registered' : 'User not found']); } exit; } if ($action === 'check_session') { if (isset($_SESSION['user_id'])) { $type = $_SESSION['user_type']; if ($type === 'admin') $table = 'admins'; elseif ($type === 'agent') $table = 'agents'; else $table = 'customers'; $stmt = $conn->prepare("SELECT * FROM $table WHERE id = ?"); $stmt->bind_param("s", $_SESSION['user_id']); $stmt->execute(); $res = get_stmt_result($stmt); if (!empty($res)) { $user = $res[0]; unset($user['password']); echo json_encode(['success' => true, 'userType' => $_SESSION['user_type'], 'user' => $user]); } else { echo json_encode(['success' => false]); } } else { echo json_encode(['success' => false]); } exit; } // --- AUTHENTICATED ACTIONS --- if (!isset($_SESSION['user_id'])) { http_response_code(401); die(json_encode(['success' => false, 'message' => 'Unauthorized'])); } switch ($action) { case 'get_dashboard_data': $data = []; $data['totalCustomers'] = $conn->query("SELECT COUNT(*) FROM customers")->fetch_row()[0]; $data['activeConnections'] = $conn->query("SELECT COUNT(*) FROM customers WHERE status = 'Active'")->fetch_row()[0]; $data['pendingPayments'] = $conn->query("SELECT COUNT(*) FROM customers WHERE balance > 0")->fetch_row()[0]; $data['disconnectedUsers'] = $conn->query("SELECT COUNT(*) FROM customers WHERE status = 'Disconnected'")->fetch_row()[0]; $data['pendingDisconnections'] = $conn->query("SELECT COUNT(*) FROM customers WHERE status = 'Pending Disconnection'")->fetch_row()[0]; $data['monthlyRevenue'] = $conn->query("SELECT SUM(amount) FROM payments WHERE MONTH(payment_date) = MONTH(CURRENT_DATE) AND YEAR(payment_date) = YEAR(CURRENT_DATE)")->fetch_row()[0] ?? 0; $data['totalUsage'] = $conn->query("SELECT SUM(consumption) FROM readings WHERE MONTH(reading_date) = MONTH(CURRENT_DATE) AND YEAR(reading_date) = YEAR(CURRENT_DATE)")->fetch_row()[0] ?? 0; $settings_res = $conn->query("SELECT * FROM business_settings WHERE id = 1"); $data['settings'] = $settings_res->fetch_assoc(); if ($_SESSION['user_type'] === 'admin') { $admins_res = $conn->query("SELECT id, name, username, phone FROM admins"); $data['admins'] = []; while($a = $admins_res->fetch_assoc()) { $data['admins'][] = $a; } $agents_res = $conn->query("SELECT id, name, username, phone FROM agents"); $data['agents'] = []; while($a = $agents_res->fetch_assoc()) { $data['agents'][] = $a; } } $historical = []; for ($i = 5; $i >= 0; $i--) { $month_key = date('Y-m', strtotime("-$i months")); $historical[$month_key] = ['month' => date('M', strtotime("-$i months")), 'revenue' => 0, 'usage' => 0]; } $rev_res = $conn->query("SELECT DATE_FORMAT(payment_date, '%Y-%m') as m, SUM(amount) as total FROM payments WHERE payment_date >= DATE_SUB(CURRENT_DATE, INTERVAL 6 MONTH) GROUP BY m"); while($row = $rev_res->fetch_assoc()) { if(isset($historical[$row['m']])) $historical[$row['m']]['revenue'] = (float)$row['total']; } $use_res = $conn->query("SELECT DATE_FORMAT(reading_date, '%Y-%m') as m, SUM(consumption) as total FROM readings WHERE reading_date >= DATE_SUB(CURRENT_DATE, INTERVAL 6 MONTH) GROUP BY m"); while($row = $use_res->fetch_assoc()) { if(isset($historical[$row['m']])) $historical[$row['m']]['usage'] = (float)$row['total']; } $data['historicalData'] = array_values($historical); $curr_m = date('Y-m'); $last_m = date('Y-m', strtotime('-1 month')); $comparison = [ 'current' => ['label' => date('F'), 'revenue' => 0, 'usage' => 0], 'last' => ['label' => date('F', strtotime('-1 month')), 'revenue' => 0, 'usage' => 0] ]; $comp_rev = $conn->query("SELECT DATE_FORMAT(payment_date, '%Y-%m') as m, SUM(amount) as total FROM payments WHERE DATE_FORMAT(payment_date, '%Y-%m') IN ('$curr_m', '$last_m') GROUP BY m"); while($row = $comp_rev->fetch_assoc()) { if($row['m'] === $curr_m) $comparison['current']['revenue'] = (float)$row['total']; if($row['m'] === $last_m) $comparison['last']['revenue'] = (float)$row['total']; } $comp_use = $conn->query("SELECT DATE_FORMAT(reading_date, '%Y-%m') as m, SUM(consumption) as total FROM readings WHERE DATE_FORMAT(reading_date, '%Y-%m') IN ('$curr_m', '$last_m') GROUP BY m"); while($row = $comp_use->fetch_assoc()) { if($row['m'] === $curr_m) $comparison['current']['usage'] = (float)$row['total']; if($row['m'] === $last_m) $comparison['last']['usage'] = (float)$row['total']; } $data['comparisonData'] = $comparison; $recent = []; $res = $conn->query("SELECT 'reading' as type, r.amount, r.reading_date as date, c.name FROM readings r JOIN customers c ON r.customer_id = c.id ORDER BY r.reading_date DESC LIMIT 10"); while($row = $res->fetch_assoc()) { $recent[] = $row; } $res = $conn->query("SELECT 'payment' as type, p.amount, p.payment_date as date, c.name FROM payments p JOIN customers c ON p.customer_id = c.id ORDER BY p.payment_date DESC LIMIT 10"); while($row = $res->fetch_assoc()) { $recent[] = $row; } usort($recent, function($a, $b) { return strtotime($b['date']) - strtotime($a['date']); }); $data['recentActivity'] = array_slice($recent, 0, 5); echo json_encode(['success' => true, 'data' => $data]); break; case 'get_customers': $res = $conn->query("SELECT id, name, username, phone, balance, status, qrCodeValue, meter_number, is_golden_citizen, prev_meter_reading, curr_meter_reading FROM customers ORDER BY name ASC"); $customers = []; while($row = $res->fetch_assoc()) { $customers[] = $row; } echo json_encode(['success' => true, 'data' => $customers]); break; case 'get_customer_details': $id = $_GET['id'] ?? $_SESSION['user_id']; $stmt = $conn->prepare("SELECT * FROM customers WHERE id = ?"); $stmt->bind_param("s", $id); $stmt->execute(); $res = get_stmt_result($stmt); if (empty($res)) die(json_encode(['success' => false, 'message' => 'Not found'])); $user = $res[0]; unset($user['password']); $res = $conn->query("SELECT * FROM readings WHERE customer_id = '$id' ORDER BY reading_date DESC LIMIT 10"); $user['readings'] = []; while($row = $res->fetch_assoc()) { $user['readings'][] = $row; } $res = $conn->query("SELECT * FROM payments WHERE customer_id = '$id' ORDER BY payment_date DESC LIMIT 10"); $user['payments'] = []; while($row = $res->fetch_assoc()) { $user['payments'][] = $row; } echo json_encode(['success' => true, 'data' => $user]); break; case 'add_customer': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $id = 'cust_' . time(); $name = $_POST['name']; $user = $_POST['username']; $phone = $_POST['phone']; $meter = $_POST['meter_number'] ?? ''; $golden = isset($_POST['is_golden_citizen']) ? 1 : 0; $prev_reading = (int)($_POST['prev_meter_reading'] ?? 0); $curr_reading = (int)($_POST['curr_meter_reading'] ?? 0); $pass = password_hash($_POST['password'], PASSWORD_DEFAULT); $stmt_check = $conn->prepare("SELECT id FROM customers WHERE phone = ?"); $stmt_check->bind_param("s", $phone); $stmt_check->execute(); $stmt_check->store_result(); if ($stmt_check->num_rows > 0) { die(json_encode(['success' => false, 'message' => 'Phone number is already associated with an account.'])); } $stmt_check->close(); $stmt = $conn->prepare("INSERT INTO customers (id, name, username, phone, password, qrCodeValue, meter_number, is_golden_citizen, prev_meter_reading, curr_meter_reading) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->bind_param("sssssssiii", $id, $name, $user, $phone, $pass, $id, $meter, $golden, $prev_reading, $curr_reading); if ($stmt->execute()) echo json_encode(['success' => true, 'message' => 'Customer added']); else echo json_encode(['success' => false, 'message' => 'Username already exists']); break; case 'update_customer': $id = $_POST['id'] ?? $_SESSION['user_id']; $name = $_POST['name'] ?? null; $phone = $_POST['phone'] ?? null; $status = $_POST['status'] ?? null; $meter = $_POST['meter_number'] ?? null; $golden = isset($_POST['is_golden_citizen']) ? (int)$_POST['is_golden_citizen'] : 0; $prev_reading = isset($_POST['prev_meter_reading']) ? (int)$_POST['prev_meter_reading'] : 0; $curr_reading = isset($_POST['curr_meter_reading']) ? (int)$_POST['curr_meter_reading'] : 0; if ($phone) { $stmt_check = $conn->prepare("SELECT id FROM customers WHERE phone = ? AND id != ?"); $stmt_check->bind_param("ss", $phone, $id); $stmt_check->execute(); $stmt_check->store_result(); if ($stmt_check->num_rows > 0) { die(json_encode(['success' => false, 'message' => 'Phone number is already in use.'])); } $stmt_check->close(); } if ($_SESSION['user_type'] === 'admin') { $stmt = $conn->prepare("UPDATE customers SET name = ?, phone = ?, status = ?, meter_number = ?, is_golden_citizen = ?, prev_meter_reading = ?, curr_meter_reading = ? WHERE id = ?"); $stmt->bind_param("ssssiiis", $name, $phone, $status, $meter, $golden, $prev_reading, $curr_reading, $id); } else { $stmt = $conn->prepare("UPDATE customers SET phone = ? WHERE id = ?"); $stmt->bind_param("ss", $phone, $_SESSION['user_id']); } if ($stmt->execute()) echo json_encode(['success' => true, 'message' => 'Profile updated']); else echo json_encode(['success' => false, 'message' => 'Update failed']); break; case 'reset_customer_password': $id = $_POST['id'] ?? $_SESSION['user_id']; $new_pass = $_POST['new_password'] ?? substr(md5(time() . rand()), 0, 8); $hash = password_hash($new_pass, PASSWORD_DEFAULT); $stmt = $conn->prepare("UPDATE customers SET password = ? WHERE id = ?"); $stmt->bind_param("ss", $hash, $id); if ($stmt->execute()) echo json_encode(['success' => true, 'message' => 'Password updated', 'new_password' => $new_pass]); else echo json_encode(['success' => false]); break; case 'delete_customer': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $id = $_POST['id']; $conn->query("DELETE FROM readings WHERE customer_id = '$id'"); $conn->query("DELETE FROM payments WHERE customer_id = '$id'"); $conn->query("DELETE FROM customers WHERE id = '$id'"); echo json_encode(['success' => true, 'message' => 'Customer deleted']); break; case 'record_reading': $custId = $_POST['customerId']; $currentInput = (int)$_POST['reading']; // Fetch current state from customer $cust_stmt = $conn->prepare("SELECT curr_meter_reading FROM customers WHERE id = ?"); $cust_stmt->bind_param("s", $custId); $cust_stmt->execute(); $cust_res = get_stmt_result($cust_stmt); if (empty($cust_res)) die(json_encode(['success' => false, 'message' => 'Customer not found'])); $customer = $cust_res[0]; $cust_stmt->close(); $prev = (int)$customer['curr_meter_reading']; // Strict Validation: New reading must be >= previous reading if ($currentInput < $prev) { die(json_encode(['success' => false, 'message' => "New reading ($currentInput) cannot be lower than previous reading ($prev)."])); } $consumption = $currentInput - $prev; // Correctly fetch rate from row using column name $rate_query = $conn->query("SELECT ratePerUnit FROM business_settings WHERE id = 1"); $settings_row = $rate_query->fetch_assoc(); $rate = $settings_row ? (float)$settings_row['ratePerUnit'] : 0.15; $amount = $consumption * $rate; $conn->begin_transaction(); try { // 1. Record reading history $stmt = $conn->prepare("INSERT INTO readings (customer_id, prev_reading, current_reading, consumption, amount, recorded_by) VALUES (?, ?, ?, ?, ?, ?)"); $stmt->bind_param("siiids", $custId, $prev, $currentInput, $consumption, $amount, $_SESSION['user_id']); $stmt->execute(); // 2. Update customer balance (add to arrears) and meter state $stmt_upd = $conn->prepare("UPDATE customers SET balance = balance + ?, prev_meter_reading = ?, curr_meter_reading = ? WHERE id = ?"); $stmt_upd->bind_param("diis", $amount, $prev, $currentInput, $custId); $stmt_upd->execute(); update_customer_status($conn, $custId); $conn->commit(); echo json_encode(['success' => true, 'message' => 'Reading saved and added to total balance']); } catch (Exception $e) { $conn->rollback(); echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]); } break; case 'record_payment': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Only administrators can record payments.'])); $custId = $_POST['customerId']; $amount = (float)$_POST['amount']; $method = $_POST['method']; $conn->begin_transaction(); try { $stmt = $conn->prepare("INSERT INTO payments (customer_id, amount, method, recorded_by) VALUES (?, ?, ?, ?)"); $stmt->bind_param("sdss", $custId, $amount, $method, $_SESSION['user_id']); $stmt->execute(); $conn->query("UPDATE customers SET balance = balance - $amount WHERE id = '$custId'"); update_customer_status($conn, $custId); $conn->commit(); echo json_encode(['success' => true, 'message' => 'Payment recorded']); } catch (Exception $e) { $conn->rollback(); echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]); } break; case 'get_reports': $type = $_GET['type']; $period = $_GET['period']; if ($type === 'revenue') { $res = $conn->query("SELECT p.*, c.name FROM payments p JOIN customers c ON p.customer_id = c.id WHERE DATE_FORMAT(p.payment_date, '%Y-%m') = '$period' ORDER BY p.payment_date DESC"); } elseif ($type === 'expenses') { $res = $conn->query("SELECT * FROM expenses WHERE DATE_FORMAT(date, '%Y-%m') = '$period' ORDER BY date DESC"); } else { $res = $conn->query("SELECT r.*, c.name FROM readings r JOIN customers c ON r.customer_id = c.id WHERE DATE_FORMAT(r.reading_date, '%Y-%m') = '$period' ORDER BY r.reading_date DESC"); } $data = []; if($res) { while($row = $res->fetch_assoc()) { $data[] = $row; } } echo json_encode(['success' => true, 'data' => $data]); break; case 'add_admin': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $id = 'adm_' . time(); $name = $_POST['name']; $user = $_POST['username']; $pass = password_hash($_POST['password'], PASSWORD_DEFAULT); $stmt = $conn->prepare("INSERT INTO admins (id, name, username, password) VALUES (?, ?, ?, ?)"); $stmt->bind_param("ssss", $id, $name, $user, $pass); if ($stmt->execute()) echo json_encode(['success' => true, 'message' => 'Admin added']); else echo json_encode(['success' => false, 'message' => 'Username already exists']); break; case 'delete_admin': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $id = $_POST['id']; if ($id === $_SESSION['user_id']) die(json_encode(['success' => false, 'message' => 'Cannot delete yourself'])); $conn->query("DELETE FROM admins WHERE id = '$id'"); echo json_encode(['success' => true, 'message' => 'Admin deleted']); break; case 'reset_admin_password': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $id = $_POST['id']; $new_pass = $_POST['password']; $hash = password_hash($new_pass, PASSWORD_DEFAULT); $stmt = $conn->prepare("UPDATE admins SET password = ? WHERE id = ?"); $stmt->bind_param("ss", $hash, $id); if ($stmt->execute()) echo json_encode(['success' => true, 'message' => 'Admin password updated']); else echo json_encode(['success' => false, 'message' => 'Update failed']); break; case 'add_agent': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $id = 'age_' . time(); $name = $_POST['name']; $user = $_POST['username']; $pass = password_hash($_POST['password'], PASSWORD_DEFAULT); $stmt = $conn->prepare("INSERT INTO agents (id, name, username, password) VALUES (?, ?, ?, ?)"); $stmt->bind_param("ssss", $id, $name, $user, $pass); if ($stmt->execute()) echo json_encode(['success' => true, 'message' => 'Agent added']); else echo json_encode(['success' => false, 'message' => 'Username already exists']); break; case 'delete_agent': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $id = $_POST['id']; $conn->query("DELETE FROM agents WHERE id = '$id'"); echo json_encode(['success' => true, 'message' => 'Agent deleted']); break; case 'reset_agent_password': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $id = $_POST['id']; $new_pass = $_POST['password']; $hash = password_hash($new_pass, PASSWORD_DEFAULT); $stmt = $conn->prepare("UPDATE agents SET password = ? WHERE id = ?"); $stmt->bind_param("ss", $hash, $id); if ($stmt->execute()) echo json_encode(['success' => true, 'message' => 'Agent password updated']); else echo json_encode(['success' => false, 'message' => 'Update failed']); break; case 'update_settings': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $rate = (float)($_POST['ratePerUnit'] ?? 0); $name = $_POST['businessName'] ?? 'OmniFlow'; $phone = $_POST['phone'] ?? ''; $support_phone = $_POST['support_phone'] ?? '5016115121'; $bankName = $_POST['bankName'] ?? ''; $bankAccountName = $_POST['bankAccountName'] ?? ''; $bankNumber = $_POST['bankNumber'] ?? ''; $color = $_POST['primaryColor'] ?? '#2563eb'; // Ensure configuration row exists $conn->query("INSERT IGNORE INTO business_settings (id) VALUES (1)"); $stmt = $conn->prepare("UPDATE business_settings SET ratePerUnit = ?, businessName = ?, phone = ?, support_phone = ?, bank_name = ?, bank_account_name = ?, bank_number = ?, primary_color = ? WHERE id = 1"); if (!$stmt) die(json_encode(['success' => false, 'message' => 'SQL Prepare failed: ' . $conn->error])); $stmt->bind_param("dsssssss", $rate, $name, $phone, $support_phone, $bankName, $bankAccountName, $bankNumber, $color); if ($stmt->execute()) { if (!empty($_POST['adminPassword'])) { $pass = password_hash($_POST['adminPassword'], PASSWORD_DEFAULT); $stmt_p = $conn->prepare("UPDATE admins SET password = ? WHERE id = ?"); $stmt_p->bind_param("ss", $pass, $_SESSION['user_id']); $stmt_p->execute(); } if (isset($_POST['adminPhone'])) { $ph = $_POST['adminPhone']; $stmt_ph = $conn->prepare("UPDATE admins SET phone = ? WHERE id = ?"); $stmt_ph->bind_param("ss", $ph, $_SESSION['user_id']); $stmt_ph->execute(); } echo json_encode(['success' => true, 'message' => 'Settings saved successfully']); } else { echo json_encode(['success' => false, 'message' => 'Database update failed: ' . $stmt->error]); } break; case 'update_self_profile': if ($_SESSION['user_type'] !== 'agent') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $id = $_SESSION['user_id']; $phone = $_POST['phone'] ?? null; $pass = $_POST['password'] ?? null; $updates = []; $params = []; $types = ""; if ($phone !== null) { $updates[] = "phone = ?"; $params[] = $phone; $types .= "s"; } if (!empty($pass)) { $updates[] = "password = ?"; $params[] = password_hash($pass, PASSWORD_DEFAULT); $types .= "s"; } if (empty($updates)) die(json_encode(['success' => false, 'message' => 'No changes provided'])); $sql = "UPDATE agents SET " . implode(", ", $updates) . " WHERE id = ?"; $params[] = $id; $types .= "s"; $stmt = $conn->prepare($sql); $stmt->bind_param($types, ...$params); if ($stmt->execute()) echo json_encode(['success' => true, 'message' => 'Profile updated']); else echo json_encode(['success' => false, 'message' => 'Update failed']); break; case 'get_expenses': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $res = $conn->query("SELECT * FROM expenses ORDER BY date DESC"); $expenses = []; if($res) { while($row = $res->fetch_assoc()) { $expenses[] = $row; } } echo json_encode(['success' => true, 'data' => $expenses]); break; case 'record_expense': if ($_SESSION['user_type'] !== 'admin') die(json_encode(['success' => false, 'message' => 'Unauthorized'])); $amount = (float)$_POST['amount']; $category = $_POST['category']; $description = $_POST['description']; $stmt = $conn->prepare("INSERT INTO expenses (amount, category, description, recorded_by) VALUES (?, ?, ?, ?)"); $stmt->bind_param("dsss", $amount, $category, $description, $_SESSION['user_id']); if ($stmt->execute()) echo json_encode(['success' => true, 'message' => 'Expense recorded']); else echo json_encode(['success' => false, 'message' => 'Error saving expense']); break; case 'upload_temp_image': if (!isset($_FILES['image'])) die(json_encode(['success' => false, 'message' => 'No image uploaded'])); $upload_dir = 'uploads/reports/'; if (!is_dir($upload_dir)) mkdir($upload_dir, 0755, true); $filename = 'report_' . time() . '_' . rand(1000, 9999) . '.jpg'; $destination = $upload_dir . $filename; if (move_uploaded_file($_FILES['image']['tmp_name'], $destination)) { $protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http"); $base_url = $protocol . "://" . $_SERVER['HTTP_HOST'] . str_replace(basename($_SERVER['PHP_SELF']), '', $_SERVER['PHP_SELF']); $url = $base_url . $destination; echo json_encode(['success' => true, 'url' => $url, 'filename' => $filename]); } else { echo json_encode(['success' => false, 'message' => 'Upload failed']); } break; case 'cleanup_temp_image': $filename = $_POST['filename'] ?? ''; if ($filename) { $path = 'uploads/reports/' . basename($filename); if (file_exists($path)) unlink($path); } echo json_encode(['success' => true]); break; case 'logout': session_destroy(); echo json_encode(['success' => true]); break; } $conn->close(); ?>