diff --git a/api/checkout.php b/api/checkout.php
index 7a4bcdf..bb939a8 100644
--- a/api/checkout.php
+++ b/api/checkout.php
@@ -16,36 +16,26 @@ $items = $input['items'] ?? [];
$vat_total = (float)($input['vat_total'] ?? 0);
$total_price = (float)($input['total_price'] ?? 0);
$payment_method = $input['payment_method'] ?? null;
+$points_to_redeem = (float)($input['points_to_redeem'] ?? 0);
$branch_id = $_SESSION['branch_id'];
$user_id = $_SESSION['user_id'];
-// Check if branch_id is 'all' (happens when super_admin views all branches)
+// Check if branch_id is 'all'
if ($branch_id === 'all') {
- // We need a specific branch_id to save an order.
- // If we're in "all" mode, we'll try to get the user's primary branch or just the first available branch.
try {
$pdo = db();
$stmt_u = $pdo->prepare("SELECT branch_id FROM users WHERE id = ?");
$stmt_u->execute([$user_id]);
$u_branch = $stmt_u->fetchColumn();
-
if ($u_branch && $u_branch != 'all') {
$branch_id = $u_branch;
} else {
- // Fallback to first branch in user_branches
$stmt_ub = $pdo->prepare("SELECT branch_id FROM user_branches WHERE user_id = ? LIMIT 1");
$stmt_ub->execute([$user_id]);
$ub_branch = $stmt_ub->fetchColumn();
- if ($ub_branch) {
- $branch_id = $ub_branch;
- } else {
- // Last resort: first branch in system
- $branch_id = $pdo->query("SELECT id FROM branches LIMIT 1")->fetchColumn();
- }
+ $branch_id = $ub_branch ?: $pdo->query("SELECT id FROM branches LIMIT 1")->fetchColumn();
}
- } catch (Exception $e) {
- // Silently continue, might fail at insert
- }
+ } catch (Exception $e) {}
}
if (empty($items)) {
@@ -60,72 +50,92 @@ try {
$payment_status = ($payment_method && $payment_method !== 'pay_later') ? 'paid' : 'unpaid';
if ($order_id) {
- // Update existing order
$stmt = $pdo->prepare("UPDATE orders SET customer_id = ?, total_price = ?, vat_total = ?, payment_status = ? WHERE id = ? AND branch_id = ?");
$stmt->execute([$customer_id, $total_price, $vat_total, $payment_status, $order_id, $branch_id]);
-
- // Remove existing items
$stmt = $pdo->prepare("DELETE FROM order_items WHERE order_id = ?");
$stmt->execute([$order_id]);
} else {
- // Create new order
$stmt = $pdo->prepare("INSERT INTO orders (branch_id, customer_id, user_id, order_number, total_price, vat_total, status, payment_status)
VALUES (?, ?, ?, NULL, ?, ?, 'received', ?)");
$stmt->execute([$branch_id, $customer_id, $user_id, $total_price, $vat_total, $payment_status]);
$order_id = $pdo->lastInsertId();
- // Get branch prefix
+ // Order Number Generation
$stmt_prefix = $pdo->prepare("SELECT prefix FROM branches WHERE id = ?");
$stmt_prefix->execute([$branch_id]);
- $prefix = $stmt_prefix->fetchColumn() ?: 'ORD';
- if (strlen($prefix) > 3) $prefix = substr($prefix, 0, 3);
- $prefix = strtoupper(str_pad($prefix, 3, 'X'));
+ $prefix = strtoupper(str_pad(substr($stmt_prefix->fetchColumn() ?: 'ORD', 0, 3), 3, 'X'));
- // Determine the next serial number for this branch
$stmt_max = $pdo->prepare("SELECT order_number FROM orders WHERE branch_id = ? AND order_number LIKE ? ORDER BY id DESC LIMIT 100");
$stmt_max->execute([$branch_id, "$prefix-%"]);
- $existing_orders = $stmt_max->fetchAll(PDO::FETCH_COLUMN);
-
+ $existing = $stmt_max->fetchAll(PDO::FETCH_COLUMN);
$max_serial = 0;
- foreach ($existing_orders as $onum) {
+ foreach ($existing as $onum) {
if (preg_match('/' . preg_quote($prefix) . '-(\d{6})/', $onum, $matches)) {
- $serial = (int)$matches[1];
- if ($serial > $max_serial) $max_serial = $serial;
+ if ((int)$matches[1] > $max_serial) $max_serial = (int)$matches[1];
}
}
- $next_serial = $max_serial + 1;
-
- // Format order_number as XXX-###### (6 digits)
- $order_number = $prefix . '-' . str_pad($next_serial, 6, '0', STR_PAD_LEFT);
-
- // Update the order with the generated order_number
- $stmt_update = $pdo->prepare("UPDATE orders SET order_number = ? WHERE id = ?");
- $stmt_update->execute([$order_number, $order_id]);
+ $order_number = $prefix . '-' . str_pad($max_serial + 1, 6, '0', STR_PAD_LEFT);
+ $pdo->prepare("UPDATE orders SET order_number = ? WHERE id = ?")->execute([$order_number, $order_id]);
}
- $stmt_item = $pdo->prepare("INSERT INTO order_items (order_id, item_id, variant_id, service_id, quantity, unit_price, vat_amount, subtotal)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
+ $stmt_item = $pdo->prepare("INSERT INTO order_items (order_id, item_id, variant_id, service_id, quantity, unit_price, vat_amount, subtotal) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
foreach ($items as $item) {
- $subtotal = ($item['price'] * $item['quantity']);
- $stmt_item->execute([
- $order_id,
- $item['itemId'],
- $item['variantId'] ?: null,
- $item['serviceId'],
- $item['quantity'],
- $item['price'],
- $item['vatAmount'] ?: 0,
- $subtotal
- ]);
+ $stmt_item->execute([$order_id, $item['itemId'], $item['variantId'] ?: null, $item['serviceId'], $item['quantity'], $item['price'], $item['vatAmount'] ?: 0, ($item['price'] * $item['quantity'])]);
}
- // Handle Payment recording
- if ($payment_method && $payment_method !== 'pay_later') {
- $stmt_payment = $pdo->prepare("INSERT INTO payments (order_id, amount, payment_method) VALUES (?, ?, ?)");
- $stmt_payment->execute([$order_id, $total_price, $payment_method]);
+ // Loyalty Redemption Logic
+ $redeem_amount = 0;
+ if ($customer_id && $points_to_redeem > 0 && get_setting('loyalty_enabled') === '1') {
+ $stmt_c = $pdo->prepare("SELECT loyalty_points FROM customers WHERE id = ? FOR UPDATE");
+ $stmt_c->execute([$customer_id]);
+ $curr_points = (float)$stmt_c->fetchColumn();
+
+ if ($curr_points >= $points_to_redeem) {
+ $point_val = (float)get_setting('loyalty_currency_per_point', 0.05);
+ $redeem_amount = $points_to_redeem * $point_val;
+
+ // Cap redemption at order total
+ if ($redeem_amount > $total_price) {
+ $redeem_amount = $total_price;
+ $points_to_redeem = $redeem_amount / $point_val;
+ }
+
+ // Deduct points
+ $pdo->prepare("UPDATE customers SET loyalty_points = loyalty_points - ? WHERE id = ?")->execute([$points_to_redeem, $customer_id]);
+
+ // Record loyalty transaction
+ $pdo->prepare("INSERT INTO loyalty_transactions (customer_id, order_id, points, type, description) VALUES (?, ?, ?, 'redeemed', ?)")
+ ->execute([$customer_id, $order_id, -$points_to_redeem, "Redeemed for order $order_number"]);
+
+ // Record loyalty payment
+ $pdo->prepare("INSERT INTO payments (order_id, amount, payment_method) VALUES (?, ?, 'loyalty')")
+ ->execute([$order_id, $redeem_amount]);
+
+ // Save loyalty discount to order
+ $pdo->prepare("UPDATE orders SET loyalty_discount = ? WHERE id = ?")
+ ->execute([$redeem_amount, $order_id]);
+ }
+ }
+
+ // Handle Remaining Payment
+ $remaining_to_pay = $total_price - $redeem_amount;
+ if ($payment_method && $payment_method !== 'pay_later' && $remaining_to_pay > 0) {
+ $pdo->prepare("INSERT INTO payments (order_id, amount, payment_method) VALUES (?, ?, ?)")
+ ->execute([$order_id, $remaining_to_pay, $payment_method]);
+ }
+
+ // Loyalty Earning Logic
+ if ($customer_id && get_setting('loyalty_enabled') === '1' && $payment_status === 'paid') {
+ $pts_per_curr = (float)get_setting('loyalty_points_per_currency', 1);
+ $points_earned = $remaining_to_pay * $pts_per_curr;
+
+ if ($points_earned > 0) {
+ $pdo->prepare("UPDATE customers SET loyalty_points = loyalty_points + ? WHERE id = ?")->execute([$points_earned, $customer_id]);
+ $pdo->prepare("INSERT INTO loyalty_transactions (customer_id, order_id, points, type, description) VALUES (?, ?, ?, 'earned', ?)")
+ ->execute([$customer_id, $order_id, $points_earned, "Earned from order $order_number"]);
+ }
}
- // Fetch customer details for notifications
$customer = null;
if ($customer_id) {
$stmt_cust = $pdo->prepare('SELECT name_ar, phone FROM customers WHERE id = ?');
@@ -135,10 +145,9 @@ try {
$pdo->commit();
- // WhatsApp Notifications
+ // WhatsApp
try {
if (get_setting('whatsapp_enabled') === '1' && $customer && !empty($customer['phone'])) {
- // 1. Order Created Notification
$template = get_setting('msg_order_created_ar');
if (!empty($template)) {
$details_parts = [];
@@ -148,39 +157,11 @@ try {
$names = $stmt_names->fetch();
$details_parts[] = ($names['item_name'] ?? 'صنف') . ' (' . ($names['service_name'] ?? 'خدمة') . ') x' . $item['quantity'];
}
- $order_details = implode(', ', $details_parts);
-
- // Get order number if not already available
- if (!isset($order_number)) {
- $stmt_onum = $pdo->prepare('SELECT order_number FROM orders WHERE id = ?');
- $stmt_onum->execute([$order_id]);
- $order_number = $stmt_onum->fetchColumn();
- }
-
- $message = str_replace(
- ['{customer_name}', '{order_number}', '{order_details}', '{total_price}'],
- [$customer['name_ar'], $order_number, $order_details, $total_price],
- $template
- );
+ $message = str_replace(['{customer_name}', '{order_number}', '{order_details}', '{total_price}'], [$customer['name_ar'], $order_number, implode(', ', $details_parts), $total_price], $template);
send_whatsapp_message($customer['phone'], $message);
}
-
- // 2. Payment Received Notification (if paid during checkout)
- if ($payment_method && $payment_method !== 'pay_later') {
- $template_pay = get_setting('msg_payment_ar');
- if (!empty($template_pay)) {
- $message_pay = str_replace(
- ['{customer_name}', '{order_number}', '{amount}', '{remaining_balance}'],
- [$customer['name_ar'], $order_number, $total_price, 0],
- $template_pay
- );
- send_whatsapp_message($customer['phone'], $message_pay);
- }
- }
}
- } catch (Exception $e) {
- // Silently fail for notifications
- }
+ } catch (Exception $e) {}
echo json_encode(['success' => true, 'order_id' => $order_id]);
} catch (Exception $e) {
diff --git a/api/search_customers.php b/api/search_customers.php
index 54b949d..416c3cd 100644
--- a/api/search_customers.php
+++ b/api/search_customers.php
@@ -16,10 +16,10 @@ if (strlen($query) < 2) {
}
try {
- $stmt = db()->prepare("SELECT id, name_en, name_ar, phone FROM customers WHERE name_en LIKE ? OR name_ar LIKE ? OR phone LIKE ? LIMIT 10");
+ $stmt = db()->prepare("SELECT id, name_en, name_ar, phone, loyalty_points FROM customers WHERE name_en LIKE ? OR name_ar LIKE ? OR phone LIKE ? LIMIT 10");
$stmt->execute(["%$query%", "%$query%", "%$query%"]);
$customers = $stmt->fetchAll();
echo json_encode($customers);
} catch (Exception $e) {
echo json_encode([]);
-}
+}
\ No newline at end of file
diff --git a/company_profile.php b/company_profile.php
index dd357a0..7147313 100644
--- a/company_profile.php
+++ b/company_profile.php
@@ -3,7 +3,6 @@ $title = 'company_profile';
require_once __DIR__ . '/includes/header.php';
if ($current_role === 'limited_viewer') { header('Location: admin.php'); exit; }
-// Only super_admin can access company profile
if ($current_role !== 'super_admin') {
echo '
' . __('Access Denied') . '
';
require_once __DIR__ . '/includes/footer.php';
@@ -14,7 +13,6 @@ $success = '';
$error = '';
$is_super = ($current_role === 'super_admin');
-// Get company data
$stmt = db()->query("SELECT * FROM companies LIMIT 1");
$company = $stmt->fetch();
@@ -26,45 +24,34 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$phone = $_POST['phone'] ?? '';
$address_en = $_POST['address_en'] ?? '';
$address_ar = $_POST['address_ar'] ?? '';
- $vat_number = $_POST['vat_no'] ?? ''; // Keep for compatibility
- $ctr_no = $_POST['ctr_no'] ?? '';
$vat_no = $_POST['vat_no'] ?? '';
+ $ctr_no = $_POST['ctr_no'] ?? '';
- // Handle Logo Upload
$logo = $company['logo'];
if (isset($_FILES['logo']) && $_FILES['logo']['error'] === UPLOAD_ERR_OK) {
$ext = pathinfo($_FILES['logo']['name'], PATHINFO_EXTENSION);
$filename = 'logo_' . time() . '.' . $ext;
$target = 'assets/images/company/' . $filename;
- if (move_uploaded_file($_FILES['logo']['tmp_name'], $target)) {
- $logo = $target;
- }
+ if (move_uploaded_file($_FILES['logo']['tmp_name'], $target)) $logo = $target;
}
- // Handle Favicon Upload
$favicon = $company['favicon'];
if (isset($_FILES['favicon']) && $_FILES['favicon']['error'] === UPLOAD_ERR_OK) {
$ext = pathinfo($_FILES['favicon']['name'], PATHINFO_EXTENSION);
$filename = 'favicon_' . time() . '.' . $ext;
$target = 'assets/images/company/' . $filename;
- if (move_uploaded_file($_FILES['favicon']['tmp_name'], $target)) {
- $favicon = $target;
- }
+ if (move_uploaded_file($_FILES['favicon']['tmp_name'], $target)) $favicon = $target;
}
try {
$stmt = db()->prepare("UPDATE companies SET name_en = ?, name_ar = ?, logo = ?, favicon = ?, email = ?, phone = ?, address_en = ?, address_ar = ?, vat_number = ?, ctr_no = ?, vat_no = ? WHERE id = ?");
- $stmt->execute([$name_en, $name_ar, $logo, $favicon, $email, $phone, $address_en, $address_ar, $vat_number, $ctr_no, $vat_no, $company['id']]);
+ $stmt->execute([$name_en, $name_ar, $logo, $favicon, $email, $phone, $address_en, $address_ar, $vat_no, $ctr_no, $vat_no, $company['id']]);
$success = __('success_update');
- // Refresh data
$stmt = db()->query("SELECT * FROM companies LIMIT 1");
$company = $stmt->fetch();
- } catch (Exception $e) {
- $error = __('error_update') . ' ' . $e->getMessage();
- }
+ } catch (Exception $e) { $error = __('error_update') . ' ' . $e->getMessage(); }
}
- // Handle WhatsApp Settings Save
if ($is_super && isset($_POST['save_whatsapp_settings'])) {
set_setting('whatsapp_enabled', $_POST['whatsapp_enabled'] ?? '0');
set_setting('wablas_token', $_POST['wablas_token'] ?? '');
@@ -73,10 +60,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
set_setting('msg_order_created_ar', $_POST['msg_order_created_ar'] ?? '');
set_setting('msg_order_ready_ar', $_POST['msg_order_ready_ar'] ?? '');
set_setting('msg_payment_ar', $_POST['msg_payment_ar'] ?? '');
- $success = is_arabic() ? 'تم حفظ إعدادات الواتساب بنجاح' : 'WhatsApp settings saved successfully';
+ $success = __('success_update');
+ }
+
+ if ($is_super && isset($_POST['save_loyalty_settings'])) {
+ set_setting('loyalty_enabled', $_POST['loyalty_enabled'] ?? '0');
+ set_setting('loyalty_points_per_currency', $_POST['loyalty_points_per_currency'] ?? '1');
+ set_setting('loyalty_currency_per_point', $_POST['loyalty_currency_per_point'] ?? '0.05');
+ $success = __('success_update');
}
}
-
?>
@@ -84,122 +77,105 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- = $success ?>
-
-
-
- = $error ?>
-
-
-
-
= is_arabic() ? 'معلومات الشركة' : 'Company Information' ?>
-
-
-
-
-
-
= __('whatsapp_settings') ?>
-
+
+ = $success ?>
+
-
\ No newline at end of file
+
+
+ = $error ?>
+
+
+
+
+
+
= is_arabic() ? 'معلومات الشركة' : 'Company Information' ?>
+
+
+
+
+
+
+
+
= is_arabic() ? 'قوالب الرسائل' : 'Message Templates' ?>
+
+
+
+
+
diff --git a/customer_statement.php b/customer_statement.php
index d9cb4b3..18037b3 100644
--- a/customer_statement.php
+++ b/customer_statement.php
@@ -3,45 +3,24 @@ $title = 'customer_statement';
require_once __DIR__ . '/includes/header.php';
$customer_id = $_GET['id'] ?? null;
-if (!$customer_id) {
- header('Location: customers.php');
- exit;
-}
+if (!$customer_id) { header('Location: customers.php'); exit; }
-// Fetch customer details
$stmt = db()->prepare("SELECT * FROM customers WHERE id = ?");
$stmt->execute([$customer_id]);
$customer = $stmt->fetch();
-
-if (!$customer) {
- header('Location: customers.php');
- exit;
-}
+if (!$customer) { header('Location: customers.php'); exit; }
$from_date = $_GET['from_date'] ?? '';
$to_date = $_GET['to_date'] ?? '';
+$active_tab = $_GET['tab'] ?? 'financial';
-// Base queries
+// Financial Logic
$orders_sql = "SELECT id, order_number, total_price, created_at FROM orders WHERE customer_id = ?";
-$payments_sql = "SELECT p.id, p.amount, p.payment_method, p.created_at, o.order_number
- FROM payments p
- JOIN orders o ON p.order_id = o.id
- WHERE o.customer_id = ?";
-$params = [$customer_id];
-
-if ($from_date) {
- $orders_sql .= " AND DATE(created_at) >= ?";
- $payments_sql .= " AND DATE(p.created_at) >= ?";
- $params[] = $from_date;
-}
-if ($to_date) {
- $orders_sql .= " AND DATE(created_at) <= ?";
- $payments_sql .= " AND DATE(p.created_at) <= ?";
- $params[] = $to_date;
-}
+$payments_sql = "SELECT p.id, p.amount, p.payment_method, p.created_at, o.order_number FROM payments p JOIN orders o ON p.order_id = o.id WHERE o.customer_id = ?";
+if ($from_date) { $orders_sql .= " AND DATE(created_at) >= ?"; $payments_sql .= " AND DATE(p.created_at) >= ?"; }
+if ($to_date) { $orders_sql .= " AND DATE(created_at) <= ?"; $payments_sql .= " AND DATE(p.created_at) <= ?"; }
$stmt_orders = db()->prepare($orders_sql);
-// We need to be careful with params if both filters are set
$orders_params = [$customer_id];
if ($from_date) $orders_params[] = $from_date;
if ($to_date) $orders_params[] = $to_date;
@@ -55,292 +34,161 @@ if ($to_date) $payments_params[] = $to_date;
$stmt_payments->execute($payments_params);
$payments = $stmt_payments->fetchAll();
-// Combine and sort
$transactions = [];
-foreach ($orders as $o) {
- $transactions[] = [
- 'date' => $o['created_at'],
- 'type' => 'order',
- 'ref' => $o['order_number'],
- 'debit' => $o['total_price'],
- 'credit' => 0,
- 'description' => __('order') . ' #' . $o['order_number']
- ];
-}
-foreach ($payments as $p) {
- $transactions[] = [
- 'date' => $p['created_at'],
- 'type' => 'payment',
- 'ref' => $p['order_number'],
- 'debit' => 0,
- 'credit' => $p['amount'],
- 'description' => __('payment') . ' (' . __($p['payment_method']) . ') - ' . __('order') . ' #' . $p['order_number']
- ];
+foreach ($orders as $o) { $transactions[] = ['date' => $o['created_at'], 'type' => 'order', 'ref' => $o['order_number'], 'debit' => $o['total_price'], 'credit' => 0, 'description' => __('order') . ' #' . $o['order_number']]; }
+foreach ($payments as $p) { $transactions[] = ['date' => $p['created_at'], 'type' => 'payment', 'ref' => $p['order_number'], 'debit' => 0, 'credit' => $p['amount'], 'description' => __('payment') . ' (' . __($p['payment_method']) . ') - ' . __('order') . ' #' . $p['order_number']]; }
+usort($transactions, function($a, $b) { return strtotime($a['date']) - strtotime($b['date']); });
+$total_debit = 0; $total_credit = 0; $balance = 0;
+foreach ($transactions as &$t) { $total_debit += $t['debit']; $total_credit += $t['credit']; $balance += ($t['debit'] - $t['credit']); $t['running_balance'] = $balance; }
+
+// Loyalty Logic
+$loyalty_sql = "SELECT lt.*, o.order_number FROM loyalty_transactions lt LEFT JOIN orders o ON lt.order_id = o.id WHERE lt.customer_id = ?";
+if ($from_date) $loyalty_sql .= " AND DATE(lt.created_at) >= ?";
+if ($to_date) $loyalty_sql .= " AND DATE(lt.created_at) <= ?";
+$loyalty_sql .= " ORDER BY lt.created_at ASC";
+$stmt_loyalty = db()->prepare($loyalty_sql);
+$loyalty_params = [$customer_id];
+if ($from_date) $loyalty_params[] = $from_date;
+if ($to_date) $loyalty_params[] = $to_date;
+$stmt_loyalty->execute($loyalty_params);
+$loyalty_transactions = $stmt_loyalty->fetchAll();
+
+$loyalty_balance = 0;
+foreach ($loyalty_transactions as &$lt) {
+ $loyalty_balance += $lt['points'];
+ $lt['running_balance'] = $loyalty_balance;
}
-usort($transactions, function($a, $b) {
- return strtotime($a['date']) - strtotime($b['date']);
-});
-
-$total_debit = 0;
-$total_credit = 0;
-$balance = 0;
-foreach ($transactions as &$t) {
- $total_debit += $t['debit'];
- $total_credit += $t['credit'];
- $balance += ($t['debit'] - $t['credit']);
- $t['running_balance'] = $balance;
-}
-
-// Fallback values if database is empty
$display_company_name = ($lang === 'ar' ? ($company_info['name_ar'] ?: $company_info['name_en']) : $company_info['name_en']) ?: 'Laundry Brand';
$display_address = ($lang === 'ar' ? ($company_info['address_ar'] ?: $company_info['address_en']) : $company_info['address_en']);
-$display_phone = $company_info['phone'];
-$display_email = $company_info['email'];
-$display_vat = $company_info['vat_no'] ?: $company_info['vat_number'];
-$display_ctr = $company_info['ctr_no'];
-
?>
-
+
-
-
+
+
+
+
+
-
-

-
-
-
- Laundry Management
-
-
+
= htmlspecialchars($display_company_name) ?>
-
-
- = htmlspecialchars($display_address) ?>
-
-
-
- = __('phone') ?>: = htmlspecialchars($display_phone) ?>
-
-
-
- = $display_phone ? ' | ' : '' ?>= __('email') ?>: = htmlspecialchars($display_email) ?>
-
-
-
-
-
- = __('vat_no') ?>: = htmlspecialchars($display_vat) ?>
-
-
-
- = $display_vat ? ' | ' : '' ?>= __('ctr_no') ?>: = htmlspecialchars($display_ctr) ?>
-
-
+
= htmlspecialchars($display_address) ?>
= __('phone') ?>: = htmlspecialchars($company_info['phone']) ?>
-
= __('statement') ?>
-
+
= $active_tab === 'loyalty' ? (__('loyalty_statement') ?? 'Loyalty Statement') : __('statement') ?>
+
= __('date') ?>: = date('d/m/Y') ?>
-
= __('cashier') ?>: = htmlspecialchars($_SESSION['full_name'] ?? 'System Admin') ?>
-
-
- = $from_date ? __('from_date') . ': ' . date('d/m/Y', strtotime($from_date)) : '' ?>
- = $to_date ? ' ' . __('to_date') . ': ' . date('d/m/Y', strtotime($to_date)) : '' ?>
-
-
+
= $from_date ? __('from_date').': '.date('d/m/Y',strtotime($from_date)) : '' ?> = $to_date ? __('to_date').': '.date('d/m/Y',strtotime($to_date)) : '' ?>
-
-
-
= __('customer_details') ?>
-
= $lang === 'ar' ? ($customer['name_ar'] ?: $customer['name_en']) : $customer['name_en'] ?>
-
= $customer['phone'] ?> = $customer['email'] ? ' | ' . $customer['email'] : '' ?>
-
+
= __('customer_details') ?>
= $lang === 'ar' ? ($customer['name_ar'] ?: $customer['name_en']) : $customer['name_en'] ?>
= $customer['phone'] ?> = $customer['email'] ? ' | '.$customer['email'] : '' ?>
= $lang === 'ar' ? ($customer['name_ar'] ?: $customer['name_en']) : $customer['name_en'] ?>
-
= $customer['phone'] ?> = $customer['email'] ? ' | ' . $customer['email'] : '' ?>
+
= $customer['phone'] ?> = $customer['email'] ? ' | '.$customer['email'] : '' ?>
-
-
-
-
- | = __('date') ?> |
- = __('description') ?> |
- = __('ref') ?? 'Ref' ?> |
- = __('debit') ?> |
- = __('credit') ?> |
- = __('balance') ?> |
-
-
-
-
-
- |
- = __('no_transactions_found') ?? 'No transactions found' ?>
- |
-
-
-
-
- | = date('d/m/Y H:i', strtotime($t['date'])) ?> |
- = $t['description'] ?> |
- = $t['ref'] ?> |
- = $t['debit'] > 0 ? format_amount($t['debit']) : '-' ?> |
- = $t['credit'] > 0 ? format_amount($t['credit']) : '-' ?> |
- = format_amount($t['running_balance']) ?> |
-
-
-
-
-
-
- | = __('total') ?> |
- = format_amount($total_debit) ?> |
- = format_amount($total_credit) ?> |
- = format_amount($balance) ?> |
-
-
-
-
-
-
-
-
-
-
= __('summary') ?? 'Summary' ?>
-
- = __('total_debit') ?>:
- = format_amount($total_debit) ?>
-
-
- = __('total_credit') ?>:
- = format_amount($total_credit) ?>
-
-
- = __('closing_balance') ?>:
- = format_amount($balance) ?>
-
-
-
+
+
+
+
+ | = __('date') ?> | = __('description') ?> | = __('ref') ?> | = __('debit') ?> | = __('credit') ?> | = __('balance') ?> |
+
+
+ | = __('no_transactions_found') ?> |
+
+ | = date('d/m/Y H:i', strtotime($t['date'])) ?> | = $t['description'] ?> | = $t['ref'] ?> | = $t['debit'] > 0 ? format_amount($t['debit']) : '-' ?> | = $t['credit'] > 0 ? format_amount($t['credit']) : '-' ?> | = format_amount($t['running_balance']) ?> |
+
+
+ | = __('total') ?> | = format_amount($total_debit) ?> | = format_amount($total_credit) ?> | = format_amount($balance) ?> |
+
-
-
-
-
-
-
-
_______________________
-
= __('customer_signature') ?? 'Customer Signature' ?>
-
-
-
= date('d/m/Y H:i') ?>
-
= __('print_date') ?? 'Print Date' ?>
-
-
-
_______________________
-
= __('authorized_signature') ?? 'Authorized Signature' ?>
+
+
+
+
+ | = __('date') ?> | = __('description') ?> | = __('ref') ?> | = __('earned') ?? 'Earned' ?> | = __('redeemed') ?? 'Redeemed' ?> | = __('balance') ?> |
+
+
+ | = __('no_transactions_found') ?> |
+
+
+ | = date('d/m/Y H:i', strtotime($lt['created_at'])) ?> |
+ = $lt['description'] ?> = __($lt['type']) ?> |
+ = $lt['order_number'] ? ''.$lt['order_number'].'' : '-' ?> |
+ = $lt['points'] > 0 ? '+'.number_format($lt['points'], 2) : '-' ?> |
+ = $lt['points'] < 0 ? number_format($lt['points'], 2) : '-' ?> |
+ = number_format($lt['running_balance'], 2) ?> |
+
+
+
+ | = __('current_balance') ?? 'Current Balance' ?> | = number_format($customer['loyalty_points'], 2) ?> |
+
+
+
+
+
+
+
+
+
= __('summary') ?>
+
+
= __('total_debit') ?>:= format_amount($total_debit) ?>
+
= __('total_credit') ?>:= format_amount($total_credit) ?>
+
= __('closing_balance') ?>:= format_amount($balance) ?>
+
+
= __('loyalty_points') ?>:= number_format($customer['loyalty_points'], 2) ?>
+
-
\ No newline at end of file
+
diff --git a/customers.php b/customers.php
index 2ea97e6..7e07674 100644
--- a/customers.php
+++ b/customers.php
@@ -1,5 +1,4 @@
prepare("SELECT COUNT(*) FROM orders WHERE customer_id = ?");
$stmt->execute([$id]);
if ($stmt->fetchColumn() > 0) {
header('Location: customers.php?error=customer_has_orders');
exit;
}
-
$stmt = db()->prepare("DELETE FROM customers WHERE id = ?");
$stmt->execute([$id]);
header('Location: customers.php?success=customer_deleted');
exit;
+ } elseif ($action === 'adjust_points') {
+ $id = $_POST['id'];
+ $points = (float)$_POST['points'];
+ $type = $_POST['type']; // 'add' or 'subtract'
+ $desc = $_POST['description'] ?? 'Manual adjustment';
+
+ $pdo = db();
+ $pdo->beginTransaction();
+ try {
+ $val = ($type === 'add') ? $points : -$points;
+ $pdo->prepare("UPDATE customers SET loyalty_points = loyalty_points + ? WHERE id = ?")->execute([$val, $id]);
+ $pdo->prepare("INSERT INTO loyalty_transactions (customer_id, points, type, description) VALUES (?, ?, 'adjusted', ?)")
+ ->execute([$id, $val, $desc]);
+ $pdo->commit();
+ header('Location: customers.php?success=points_adjusted');
+ exit;
+ } catch (Exception $e) {
+ $pdo->rollBack();
+ header('Location: customers.php?error=' . urlencode($e->getMessage()));
+ exit;
+ }
}
}
$title = 'customers';
require_once __DIR__ . '/includes/header.php';
-
$search = $_GET['search'] ?? '';
$sql = "SELECT * FROM customers WHERE 1=1";
$params = [];
-
if ($search) {
$sql .= " AND (name_en LIKE ? OR name_ar LIKE ? OR phone LIKE ?)";
- $params[] = "%$search%";
- $params[] = "%$search%";
- $params[] = "%$search%";
+ $params[] = "%$search%"; $params[] = "%$search%"; $params[] = "%$search%";
}
-
$sql .= " ORDER BY created_at DESC";
$stmt = db()->prepare($sql);
$stmt->execute($params);
$customers = $stmt->fetchAll();
-
?>
@@ -104,31 +114,27 @@ $customers = $stmt->fetchAll();
-
-
- = __($_GET['success']) ?? 'Action completed successfully' ?>
+
+
+ = __($_GET['success']) ?? 'Action completed successfully' ?>
-
-
- = __($_GET['error']) ?? 'Permission Denied' ?>
+
+
+ = __($_GET['error']) ?? 'An error occurred' ?>
@@ -140,33 +146,41 @@ $customers = $stmt->fetchAll();
# |
= __('name') ?> |
= __('phone') ?> |
+
+
= __('loyalty_points') ?? 'Loyalty Points' ?> |
+
= __('email') ?> |
= __('date') ?> |
= __('actions') ?> |
-
+
+
| = $c['id'] ?> |
-
- = $lang === 'ar' ? ($c['name_ar'] ?: $c['name_en']) : $c['name_en'] ?>
- |
+ = $lang === 'ar' ? ($c['name_ar'] ?: $c['name_en']) : $c['name_en'] ?> |
= $c['phone'] ?> |
+
+
+
+ = number_format($c['loyalty_points'], 2) ?>
+
+ |
+
= $c['email'] ?: '-' ?> |
= date('d/m/Y', strtotime($c['created_at'])) ?> |
-
+
- |
-
- |
-
- = __('no_customers_found') ?? 'No customers found' ?>
- |
-
+
+ | = __('no_customers_found') ?? 'No customers found' ?> |
@@ -190,66 +199,94 @@ $customers = $stmt->fetchAll();
-
-
+
+
+
+
+
+
+
+
+
+
0.00
+
+
-