Edit file File name : pos_api.php Content :<?php // This is the dedicated API endpoint for POS systems. // It is separate from the main api.php to keep concerns separated. header('Content-Type: application/json'); date_default_timezone_set('America/Belize'); require 'db_config.php'; // --- HELPER FUNCTIONS --- function send_json_error($message, $code = 400) { http_response_code($code); echo json_encode(['success' => false, 'message' => $message]); exit(); } function send_json_success($data = []) { echo json_encode(['success' => true, 'data' => $data]); exit(); } function get_stmt_result($stmt) { $result = []; $stmt->store_result(); if ($stmt->num_rows === 0) return $result; $meta = $stmt->result_metadata(); if (!$meta) return []; $fields = []; $row = []; while ($field = $meta->fetch_field()) { $fields[] = &$row[$field->name]; } call_user_func_array([$stmt, 'bind_result'], $fields); while ($stmt->fetch()) { $result_row = []; foreach ($row as $key => $val) { $result_row[$key] = $val; } $result[] = $result_row; } $stmt->free_result(); return $result; } // --- MAIN EXECUTION --- try { $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { throw new Exception('Database connection failed: ' . $conn->connect_error); } // --- AUTHORIZATION --- $api_key = $_POST['api_key'] ?? null; if (!$api_key) { send_json_error('API key is required.', 401); } $stmt = $conn->prepare("SELECT api_key FROM business_settings LIMIT 1"); $stmt->execute(); $result = get_stmt_result($stmt); $stmt->close(); if (empty($result) || !$result[0]['api_key'] || !hash_equals($result[0]['api_key'], $api_key)) { send_json_error('Invalid API key.', 403); } // --- PARAMETER VALIDATION --- $customer_identifier = $_POST['customer_identifier'] ?? null; $points_to_add = (int)($_POST['points'] ?? 0); $transaction_id = $_POST['transaction_id'] ?? 'POS Transaction'; if (!$customer_identifier || $points_to_add <= 0) { send_json_error('Customer identifier and a positive number of points are required.'); } // --- FIND CUSTOMER --- // The identifier can be either a phone number or a QR code value $stmt = $conn->prepare("SELECT id, name, points, rewards FROM customers WHERE phone = ? OR qrCodeValue = ?"); $stmt->bind_param("ss", $customer_identifier, $customer_identifier); $stmt->execute(); $result = get_stmt_result($stmt); $stmt->close(); if (empty($result)) { send_json_error('Customer not found with the provided identifier.'); } $customer = $result[0]; $customer_id = $customer['id']; // --- ADD POINTS LOGIC (DUPLICATED FROM api.php FOR CONSISTENCY) --- $conn->begin_transaction(); try { $points = (int)$customer['points'] + $points_to_add; $rewards = (int)$customer['rewards']; $new_rewards_earned = floor($points / 10); $points = $points % 10; $rewards += $new_rewards_earned; $stmt_update = $conn->prepare("UPDATE customers SET points = ?, rewards = ? WHERE id = ?"); $stmt_update->bind_param("iis", $points, $rewards, $customer_id); $stmt_update->execute(); $stmt_update->close(); $history_id = 'h_' . time() . rand(100, 999); $date = date("Y-m-d H:i:s"); $description = "{$points_to_add} point(s) from " . htmlspecialchars($transaction_id); $stmt_history = $conn->prepare("INSERT INTO point_history (id, customer_id, date, description, points) VALUES (?, ?, ?, ?, ?)"); $stmt_history->bind_param("ssssi", $history_id, $customer_id, $date, $description, $points_to_add); $stmt_history->execute(); $stmt_history->close(); // Check and update VIP status $stmt_rewards_count = $conn->prepare("SELECT COUNT(*) as count FROM point_history WHERE customer_id = ? AND description = 'Reward Redeemed'"); $stmt_rewards_count->bind_param("s", $customer_id); $stmt_rewards_count->execute(); $rewards_result = get_stmt_result($stmt_rewards_count); $stmt_rewards_count->close(); $redeemed_count = $rewards_result[0]['count'] ?? 0; if ($redeemed_count >= 5) { $conn->query("UPDATE customers SET isVIP = 1 WHERE id = '" . $conn->real_escape_string($customer_id) . "'"); } $conn->commit(); send_json_success([ 'message' => "Successfully added {$points_to_add} points to {$customer['name']}.", 'new_points_balance' => $points, 'new_rewards_balance' => $rewards ]); } catch (Exception $e) { $conn->rollback(); throw $e; // Re-throw to be caught by the outer catch block } } catch (Exception $e) { send_json_error('A critical error occurred: ' . $e->getMessage(), 500); } if ($conn) { $conn->close(); } ?> Save