diff --git a/admin/company.php b/admin/company.php index e771a51..522f5f5 100644 --- a/admin/company.php +++ b/admin/company.php @@ -21,6 +21,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $currency_decimals = $_POST['currency_decimals'] ?? 2; $ctr_number = $_POST['ctr_number'] ?? ''; $vat_number = $_POST['vat_number'] ?? ''; + $commission_enabled = isset($_POST['commission_enabled']) ? 1 : 0; // Handle File Uploads $uploadDir = __DIR__ . '/../assets/images/company/'; @@ -66,11 +67,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $exists = $pdo->query("SELECT COUNT(*) FROM company_settings")->fetchColumn(); if ($exists) { - $stmt = $pdo->prepare("UPDATE company_settings SET company_name=?, address=?, phone=?, email=?, vat_rate=?, currency_symbol=?, currency_decimals=?, ctr_number=?, vat_number=?, logo_url=?, favicon_url=?, updated_at=NOW()"); - $stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $ctr_number, $vat_number, $logo_url, $favicon_url]); + $stmt = $pdo->prepare("UPDATE company_settings SET company_name=?, address=?, phone=?, email=?, vat_rate=?, currency_symbol=?, currency_decimals=?, ctr_number=?, vat_number=?, logo_url=?, favicon_url=?, commission_enabled=?, updated_at=NOW()"); + $stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled]); } else { - $stmt = $pdo->prepare("INSERT INTO company_settings (company_name, address, phone, email, vat_rate, currency_symbol, currency_decimals, ctr_number, vat_number, logo_url, favicon_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $ctr_number, $vat_number, $logo_url, $favicon_url]); + $stmt = $pdo->prepare("INSERT INTO company_settings (company_name, address, phone, email, vat_rate, currency_symbol, currency_decimals, ctr_number, vat_number, logo_url, favicon_url, commission_enabled) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled]); } $message = '
Company settings updated successfully!
'; @@ -81,6 +82,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $settings['vat_number'] = $vat_number; $settings['logo_url'] = $logo_url; $settings['favicon_url'] = $favicon_url; + $settings['commission_enabled'] = $commission_enabled; } catch (Exception $e) { $message = '
Error updating settings: ' . htmlspecialchars($e->getMessage()) . '
'; @@ -153,6 +155,18 @@ include 'includes/header.php'; +
+
Commission System
+
+
+
+ > + +
When enabled, commissions will be calculated for each order based on the cashier's commission rate.
+
+
+
+
Branding
diff --git a/admin/orders.php b/admin/orders.php index d424773..3338a0c 100644 --- a/admin/orders.php +++ b/admin/orders.php @@ -86,18 +86,21 @@ if (!empty($_GET['search'])) { $where_clause = !empty($where) ? 'WHERE ' . implode(' AND ', $where) : ''; -// Calculate Total Sum for filtered orders -$sum_query = "SELECT SUM(total_amount) as total_sum FROM orders o $where_clause"; +// Calculate Total Sum and Total Commission for filtered orders +$sum_query = "SELECT SUM(total_amount) as total_sum, SUM(commission_amount) as total_commission FROM orders o $where_clause"; $stmt_sum = $pdo->prepare($sum_query); $stmt_sum->execute($params); -$total_sum = $stmt_sum->fetchColumn() ?: 0; +$sum_data = $stmt_sum->fetch(PDO::FETCH_ASSOC); +$total_sum = (float)($sum_data['total_sum'] ?? 0); +$total_commission = (float)($sum_data['total_commission'] ?? 0); // Main Query -$query = "SELECT o.*, ot.name as outlet_name, pt.name as payment_type_name, +$query = "SELECT o.*, ot.name as outlet_name, pt.name as payment_type_name, u.username as cashier_name, (SELECT GROUP_CONCAT(CONCAT(p.name, ' x', oi.quantity) SEPARATOR ', ') FROM order_items oi JOIN products p ON oi.product_id = p.id WHERE oi.order_id = o.id) as items_summary FROM orders o LEFT JOIN outlets ot ON o.outlet_id = ot.id LEFT JOIN payment_types pt ON o.payment_type_id = pt.id + LEFT JOIN users u ON o.user_id = u.id $where_clause ORDER BY o.created_at DESC"; @@ -107,6 +110,9 @@ $orders = $orders_pagination['data']; // Add total sum to pagination object for rendering $orders_pagination['total_amount_sum'] = $total_sum; +$settings = get_company_settings(); +$commission_enabled = !empty($settings['commission_enabled']); + include 'includes/header.php'; ?> @@ -149,7 +155,7 @@ include 'includes/header.php';
-
+
@@ -164,7 +170,24 @@ include 'includes/header.php';
-
+ +
+
+
+
+
+ +
+
+
Total Commission
+
+
+
+
+
+
+ +
@@ -179,7 +202,7 @@ include 'includes/header.php';
-
+
@@ -253,11 +276,14 @@ include 'includes/header.php'; ID Outlet + Cashier Customer Type Source - Items Total + + Commission + Payment Status Time @@ -274,6 +300,9 @@ include 'includes/header.php'; + + @ +
@@ -303,8 +332,12 @@ include 'includes/header.php'; - - + + + + + + - + No active orders found matching your criteria. diff --git a/admin/users.php b/admin/users.php index a48d9de..5658438 100644 --- a/admin/users.php +++ b/admin/users.php @@ -16,6 +16,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $group_id = (int)$_POST['group_id']; $is_active = isset($_POST['is_active']) ? 1 : 0; $is_ratable = isset($_POST['is_ratable']) ? 1 : 0; + $commission_rate = (float)($_POST['commission_rate'] ?? 0); $id = isset($_POST['id']) ? (int)$_POST['id'] : null; $profile_pic = null; @@ -46,13 +47,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { if (!has_permission('users_edit') && !has_permission('users_add')) { $message = '
Access Denied: You do not have permission to edit users.
'; } else { - $sql = "UPDATE users SET username = ?, full_name = ?, full_name_ar = ?, email = ?, group_id = ?, is_active = ?, is_ratable = ?, profile_pic = ? WHERE id = ?"; - $params = [$username, $full_name, $full_name_ar, $email, $group_id, $is_active, $is_ratable, $profile_pic, $id]; + $sql = "UPDATE users SET username = ?, full_name = ?, full_name_ar = ?, email = ?, group_id = ?, is_active = ?, is_ratable = ?, profile_pic = ?, commission_rate = ? WHERE id = ?"; + $params = [$username, $full_name, $full_name_ar, $email, $group_id, $is_active, $is_ratable, $profile_pic, $commission_rate, $id]; if (!empty($_POST['password'])) { $password = password_hash($_POST['password'], PASSWORD_DEFAULT); - $sql = "UPDATE users SET username = ?, full_name = ?, full_name_ar = ?, email = ?, group_id = ?, is_active = ?, is_ratable = ?, profile_pic = ?, password = ? WHERE id = ?"; - $params = [$username, $full_name, $full_name_ar, $email, $group_id, $is_active, $is_ratable, $profile_pic, $password, $id]; + $sql = "UPDATE users SET username = ?, full_name = ?, full_name_ar = ?, email = ?, group_id = ?, is_active = ?, is_ratable = ?, profile_pic = ?, commission_rate = ?, password = ? WHERE id = ?"; + $params = [$username, $full_name, $full_name_ar, $email, $group_id, $is_active, $is_ratable, $profile_pic, $commission_rate, $password, $id]; } $stmt = $pdo->prepare($sql); @@ -64,8 +65,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $message = '
Access Denied: You do not have permission to add users.
'; } else { $password = password_hash($_POST['password'] ?: '123456', PASSWORD_DEFAULT); - $stmt = $pdo->prepare("INSERT INTO users (username, password, full_name, full_name_ar, email, group_id, is_active, is_ratable, profile_pic) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$username, $password, $full_name, $full_name_ar, $email, $group_id, $is_active, $is_ratable, $profile_pic]); + $stmt = $pdo->prepare("INSERT INTO users (username, password, full_name, full_name_ar, email, group_id, is_active, is_ratable, profile_pic, commission_rate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$username, $password, $full_name, $full_name_ar, $email, $group_id, $is_active, $is_ratable, $profile_pic, $commission_rate]); $message = '
User created successfully!
'; } } @@ -137,7 +138,7 @@ include 'includes/header.php'; Email Role / Group Status - Ratable + Commission Actions @@ -168,11 +169,7 @@ include 'includes/header.php'; - - Yes - - No - + % @@ -261,6 +258,16 @@ include 'includes/header.php';
+
+
+ +
+ + % +
+ Percentage earned per sale processed by this user. +
+
@@ -299,6 +306,7 @@ function prepareAddForm() { document.getElementById('pwdHint').style.display = 'none'; document.getElementById('userPassword').required = true; document.getElementById('userImagePreviewContainer').style.display = 'none'; + document.getElementById('userCommissionRate').value = '0.0'; } function prepareEditForm(user) { @@ -313,6 +321,7 @@ function prepareEditForm(user) { document.getElementById('userGroupId').value = user.group_id || ''; document.getElementById('userIsActive').checked = user.is_active == 1; document.getElementById('userIsRatable').checked = user.is_ratable == 1; + document.getElementById('userCommissionRate').value = user.commission_rate || '0.0'; document.getElementById('userPassword').required = false; document.getElementById('pwdLabel').style.display = 'none'; document.getElementById('pwdHint').style.display = 'block'; diff --git a/api/order.php b/api/order.php index feb56b4..bbcc8dd 100644 --- a/api/order.php +++ b/api/order.php @@ -72,10 +72,10 @@ try { // Fetch Loyalty Settings $settingsStmt = $pdo->query("SELECT is_enabled, points_per_order, points_for_free_meal FROM loyalty_settings WHERE id = 1"); - $settings = $settingsStmt->fetch(PDO::FETCH_ASSOC); - $loyalty_enabled = $settings ? (bool)$settings['is_enabled'] : true; - $points_per_order = $settings ? intval($settings['points_per_order']) : 10; - $points_threshold = $settings ? intval($settings['points_for_free_meal']) : 70; + $loyaltySettings = $settingsStmt->fetch(PDO::FETCH_ASSOC); + $loyalty_enabled = $loyaltySettings ? (bool)$loyaltySettings['is_enabled'] : true; + $points_per_order = $loyaltySettings ? intval($loyaltySettings['points_per_order']) : 10; + $points_threshold = $loyaltySettings ? intval($loyaltySettings['points_for_free_meal']) : 70; $current_points = 0; $points_deducted = 0; @@ -189,6 +189,19 @@ try { $final_total = max(0, $calculated_total + $vat); + // Commission Calculation + $commission_amount = 0; + $companySettings = get_company_settings(); + if (!empty($companySettings['commission_enabled']) && $user_id) { + $userStmt = $pdo->prepare("SELECT commission_rate FROM users WHERE id = ?"); + $userStmt->execute([$user_id]); + $commission_rate = (float)$userStmt->fetchColumn(); + if ($commission_rate > 0) { + // Commission is usually calculated on the subtotal (before tax/VAT) + $commission_amount = $calculated_total * ($commission_rate / 100); + } + } + // Check for Existing Order ID (Update Mode) $order_id = isset($data['order_id']) ? intval($data['order_id']) : null; $is_update = false; @@ -208,21 +221,22 @@ try { $stmt = $pdo->prepare("UPDATE orders SET outlet_id = ?, table_id = ?, table_number = ?, order_type = ?, customer_id = ?, customer_name = ?, customer_phone = ?, - payment_type_id = ?, total_amount = ?, discount = ?, user_id = ?, status = 'pending' + payment_type_id = ?, total_amount = ?, discount = ?, user_id = ?, + commission_amount = ?, status = 'pending' WHERE id = ?"); $stmt->execute([ $outlet_id, $table_id, $table_number, $order_type, $customer_id, $customer_name, $customer_phone, $payment_type_id, $final_total, $vat, $user_id, - $order_id + $commission_amount, $order_id ]); $delStmt = $pdo->prepare("DELETE FROM order_items WHERE order_id = ?"); $delStmt->execute([$order_id]); } else { // INSERT New Order - $stmt = $pdo->prepare("INSERT INTO orders (outlet_id, table_id, table_number, order_type, customer_id, customer_name, customer_phone, payment_type_id, total_amount, discount, user_id, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')"); - $stmt->execute([$outlet_id, $table_id, $table_number, $order_type, $customer_id, $customer_name, $customer_phone, $payment_type_id, $final_total, $vat, $user_id]); + $stmt = $pdo->prepare("INSERT INTO orders (outlet_id, table_id, table_number, order_type, customer_id, customer_name, customer_phone, payment_type_id, total_amount, discount, user_id, commission_amount, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')"); + $stmt->execute([$outlet_id, $table_id, $table_number, $order_type, $customer_id, $customer_name, $customer_phone, $payment_type_id, $final_total, $vat, $user_id, $commission_amount]); $order_id = $pdo->lastInsertId(); } @@ -321,4 +335,4 @@ You've earned *{points_earned} points* with this order. if ($pdo->inTransaction()) $pdo->rollBack(); error_log("Order Error: " . $e->getMessage()); echo json_encode(['success' => false, 'error' => $e->getMessage()]); -} +} \ No newline at end of file diff --git a/db/migrations/034_commission_system.sql b/db/migrations/034_commission_system.sql new file mode 100644 index 0000000..98daa44 --- /dev/null +++ b/db/migrations/034_commission_system.sql @@ -0,0 +1,8 @@ +-- Add commission toggle to company_settings +ALTER TABLE company_settings ADD COLUMN commission_enabled TINYINT(1) DEFAULT 0; + +-- Add commission_rate to users +ALTER TABLE users ADD COLUMN commission_rate DECIMAL(5, 2) DEFAULT 0.00; + +-- Add commission_amount to orders +ALTER TABLE orders ADD COLUMN commission_amount DECIMAL(10, 2) DEFAULT 0.00; diff --git a/includes/functions.php b/includes/functions.php index 3933664..074f1f8 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -296,16 +296,39 @@ function require_permission($permission) { * @return string The base URL. */ function get_base_url() { - $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://"; + $protocol = 'http://'; + if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || + $_SERVER['SERVER_PORT'] == 443 || + (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')) { + $protocol = 'https://'; + } + $domainName = $_SERVER['HTTP_HOST']; - // Remove admin/ if we are in it + + // Calculate script directory $script_dir = dirname($_SERVER['SCRIPT_NAME']); - $script_dir = str_replace(['/admin', '/api'], '', $script_dir); - if ($script_dir === '/') $script_dir = ''; + // Replace only at the end to be safer + if (str_ends_with($script_dir, '/admin')) { + $script_dir = substr($script_dir, 0, -6); + } elseif (str_ends_with($script_dir, '/api')) { + $script_dir = substr($script_dir, 0, -4); + } + + if ($script_dir === DIRECTORY_SEPARATOR || $script_dir === '/') { + $script_dir = ''; + } return $protocol . $domainName . $script_dir . '/'; } +if (!function_exists('str_ends_with')) { + function str_ends_with($haystack, $needle) { + $length = strlen($needle); + if (!$length) return true; + return substr($haystack, -$length) === $needle; + } +} + /** * Backup functions */ diff --git a/login.php b/login.php index e404608..6cb50d4 100644 --- a/login.php +++ b/login.php @@ -6,9 +6,25 @@ init_session(); $baseUrl = get_base_url(); +/** + * Determine where to redirect the user based on permissions + */ +function get_redirect_url($baseUrl) { + if (has_permission('dashboard_view')) { + return $baseUrl . 'admin/index.php'; + } elseif (has_permission('pos')) { + return $baseUrl . 'pos.php'; + } elseif (has_permission('kitchen_view')) { + return $baseUrl . 'kitchen.php'; + } + // Fallback to admin index if no specific view permission found, + // the page itself will handle the final access denied + return $baseUrl . 'admin/index.php'; +} + // Redirect if already logged in if (get_logged_user()) { - header('Location: ' . $baseUrl . 'admin/index.php'); + header('Location: ' . get_redirect_url($baseUrl)); exit; } @@ -19,7 +35,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $password = $_POST['password'] ?? ''; if (login_user($username, $password)) { - header('Location: ' . $baseUrl . 'admin/index.php'); + header('Location: ' . get_redirect_url($baseUrl)); exit; } else { $error = 'Invalid username or password.'; diff --git a/test_url.php b/test_url.php deleted file mode 100644 index 70d733a..0000000 --- a/test_url.php +++ /dev/null @@ -1,7 +0,0 @@ -