diff --git a/admin.php b/admin.php index d154764..325a4e2 100644 --- a/admin.php +++ b/admin.php @@ -2,6 +2,17 @@ $title = 'dashboard'; require_once __DIR__ . '/includes/header.php'; +// Handle WhatsApp Settings Save +if ($is_super && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_whatsapp_settings'])) { + set_setting('whatsapp_enabled', $_POST['whatsapp_enabled'] ?? '0'); + set_setting('wablas_token', $_POST['wablas_token'] ?? ''); + set_setting('wablas_server', $_POST['wablas_server'] ?? ''); + 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_msg = is_arabic() ? 'تم حفظ الإعدادات بنجاح' : 'Settings saved successfully'; +} + // Helper functions for status colors if (!function_exists('getStatusColor')) { function getStatusColor($status) { @@ -281,8 +292,59 @@ if (!$is_limited) { }); } + + +
+
+
+
+ +
+ +
+
+
+
+
+ > + +
+
+
+ + +
+
+ + +
+
+ + + Tags: {customer_name}, {order_number}, {order_details}, {total_price} +
+
+ + + Tags: {customer_name}, {order_number} +
+
+ + + Tags: {customer_name}, {order_number}, {amount}, {remaining_balance} +
+
+ +
+
+
+
+
+ \ No newline at end of file +?> diff --git a/api/checkout.php b/api/checkout.php index 195ea64..1b16cf4 100644 --- a/api/checkout.php +++ b/api/checkout.php @@ -1,6 +1,7 @@ execute([$order_id, $total_price, $payment_method]); } + // Fetch customer details for notifications + $customer = null; + if ($customer_id) { + $stmt_cust = $pdo->prepare('SELECT name_ar, phone FROM customers WHERE id = ?'); + $stmt_cust->execute([$customer_id]); + $customer = $stmt_cust->fetch(); + } + $pdo->commit(); + + // WhatsApp Notifications + 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 = []; + foreach ($items as $item) { + $stmt_names = $pdo->prepare('SELECT i.name_ar as item_name, s.name_ar as service_name FROM items i, services s WHERE i.id = ? AND s.id = ?'); + $stmt_names->execute([$item['itemId'], $item['serviceId']]); + $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 + ); + 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 + } + echo json_encode(['success' => true, 'order_id' => $order_id]); } catch (Exception $e) { if (isset($pdo)) $pdo->rollBack(); echo json_encode(['success' => false, 'error' => $e->getMessage()]); -} \ No newline at end of file +} diff --git a/api/update_order_status.php b/api/update_order_status.php index 892d6ba..51b61d7 100644 --- a/api/update_order_status.php +++ b/api/update_order_status.php @@ -1,6 +1,7 @@ execute([$status, $id]); if ($stmt->rowCount() > 0) { + // WhatsApp Notification for Order Ready + try { + if ($status === 'ready') { + if (get_setting('whatsapp_enabled') === '1') { + $stmt_details = $pdo->prepare('SELECT o.order_number, c.name_ar, c.phone FROM orders o JOIN customers c ON o.customer_id = c.id WHERE o.id = ?'); + $stmt_details->execute([$id]); + $order = $stmt_details->fetch(); + + if ($order && !empty($order['phone'])) { + $template = get_setting('msg_order_ready_ar'); + if (!empty($template)) { + $message = str_replace( + ['{customer_name}', '{order_number}'], + [$order['name_ar'], $order['order_number']], + $template + ); + send_whatsapp_message($order['phone'], $message); + } + } + } + } + } catch (Exception $e) { + // Silently fail for notification + } + echo json_encode(['success' => true]); } else { echo json_encode(['success' => false, 'error' => 'Order not found or status already same']); } } catch (Exception $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); -} +} \ No newline at end of file diff --git a/db/config.php b/db/config.php index 59b4412..8767e7a 100644 --- a/db/config.php +++ b/db/config.php @@ -43,7 +43,23 @@ function check_permission($page = null, $user_id = null) { return $result; } +function get_setting($key, $default = null) { + try { + $stmt = db()->prepare('SELECT setting_value FROM settings WHERE setting_key = ?'); + $stmt->execute([$key]); + $val = $stmt->fetchColumn(); + return ($val !== false) ? $val : $default; + } catch (Exception $e) { + return $default; + } +} + +function set_setting($key, $value) { + $stmt = db()->prepare('INSERT INTO settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = ?, updated_at = CURRENT_TIMESTAMP'); + $stmt->execute([$key, $value, $value]); +} + function has_permission($action, $page = null, $user_id = null) { $perms = check_permission($page, $user_id); return !empty($perms[$action]); -} \ No newline at end of file +} diff --git a/db/migrations/14_add_whatsapp_settings.sql b/db/migrations/14_add_whatsapp_settings.sql new file mode 100644 index 0000000..409edf3 --- /dev/null +++ b/db/migrations/14_add_whatsapp_settings.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS settings ( + setting_key VARCHAR(100) PRIMARY KEY, + setting_value TEXT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Initial WhatsApp settings +INSERT INTO settings (setting_key, setting_value) VALUES +('whatsapp_enabled', '0'), +('wablas_token', ''), +('wablas_server', 'https://console.wablas.com'), +('msg_order_created_ar', 'عزيزي {customer_name}، تم استلام طلبك رقم {order_number}. التفاصيل: {order_details}. الإجمالي: {total_price}. شكراً لتعاملك معنا.'), +('msg_order_ready_ar', 'عزيزي {customer_name}، طلبك رقم {order_number} جاهز للاستلام. شكراً لتعاملك معنا.'), +('msg_payment_ar', 'عزيزي {customer_name}، تم استلام دفعة بمبلغ {amount} لطلبك رقم {order_number}. الرصيد المتبقي: {remaining_balance}. شكراً لتعاملك معنا.'); diff --git a/includes/lang.php b/includes/lang.php index 2b83ba9..07cfb91 100644 --- a/includes/lang.php +++ b/includes/lang.php @@ -18,6 +18,7 @@ $translations = [ 'branches' => 'Branches', 'users' => 'Users', 'settings' => 'Settings', +'whatsapp_settings' => 'WhatsApp Settings', 'whatsapp_enabled' => 'WhatsApp Enabled', 'wablas_token' => 'Wablas API Token', 'wablas_server' => 'Wablas Server URL', 'msg_order_created_ar' => 'Order Created Message (Arabic)', 'msg_order_ready_ar' => 'Order Ready Message (Arabic)', 'msg_payment_ar' => 'Payment Received Message (Arabic)', 'logout' => 'Logout', 'login' => 'Login', 'username' => 'Username', @@ -206,6 +207,7 @@ $translations = [ 'branches' => 'الفروع', 'users' => 'المستخدمين', 'settings' => 'الإعدادات', +'whatsapp_settings' => 'إعدادات الواتساب', 'whatsapp_enabled' => 'تفعيل الواتساب', 'wablas_token' => 'رمز API Wablas', 'wablas_server' => 'رابط خادم Wablas', 'msg_order_created_ar' => 'رسالة إنشاء الطلب (بالعربية)', 'msg_order_ready_ar' => 'رسالة الطلب جاهز (بالعربية)', 'msg_payment_ar' => 'رسالة استلام الدفعة (بالعربية)', 'logout' => 'تسجيل الخروج', 'login' => 'تسجيل الدخول', 'username' => 'اسم المستخدم', diff --git a/includes/whatsapp.php b/includes/whatsapp.php new file mode 100644 index 0000000..9238b4a --- /dev/null +++ b/includes/whatsapp.php @@ -0,0 +1,51 @@ + false, 'error' => 'WhatsApp is disabled']; + } + + $token = get_setting('wablas_token'); + $server = get_setting('wablas_server', 'https://console.wablas.com'); + + if (empty($token) || empty($server)) { + return ['success' => false, 'error' => 'Wablas configuration is incomplete']; + } + + // Clean phone number (ensure it has country code, e.g., 966 for Saudi Arabia if not provided) + // For now, assume user provides it or we just use it as is if it looks correct. + $phone = preg_replace('/[^0-9]/', '', $phone); + + // Wablas API expects phone number. + $curl = curl_init(); + $data = [ + 'phone' => $phone, + 'message' => $message, + ]; + + curl_setopt($curl, CURLOPT_HTTPHEADER, [ + "Authorization: $token", + ]); + curl_setopt($curl, CURLOPT_URL, rtrim($server, '/') . "/api/send-message"); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST"); + curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data)); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_TIMEOUT, 10); + + $result = curl_exec($curl); + $error = curl_error($curl); + curl_close($curl); + + if ($error) { + return ['success' => false, 'error' => $error]; + } + + $response = json_decode($result, true); + if (isset($response['status']) && $response['status'] == true) { + return ['success' => true, 'response' => $response]; + } + + return ['success' => false, 'error' => $response['message'] ?? 'Unknown error from Wablas']; +} diff --git a/order_details.php b/order_details.php index 8ba6919..4d850d8 100644 --- a/order_details.php +++ b/order_details.php @@ -2,6 +2,7 @@ // ACTION HANDLING FIRST require_once __DIR__ . '/db/config.php'; require_once __DIR__ . '/includes/lang.php'; +require_once __DIR__ . '/includes/whatsapp.php'; $order_id = $_GET['id'] ?? null; if (!$order_id) { @@ -27,10 +28,26 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $new_status = $_POST['status']; $stmt = db()->prepare("UPDATE orders SET status = ? WHERE id = ?"); $stmt->execute([$new_status, $order_id]); + + // WhatsApp Notification for Order Ready + try { + if ($new_status === 'ready' && get_setting('whatsapp_enabled') === '1' && !empty($order['customer_phone'])) { + $template = get_setting('msg_order_ready_ar'); + if (!empty($template)) { + $message = str_replace( + ['{customer_name}', '{order_number}'], + [$order['customer_name_ar'], $order['order_number']], + $template + ); + send_whatsapp_message($order['customer_phone'], $message); + } + } + } catch (Exception $e) {} + header("Location: order_details.php?id=$order_id"); exit; } elseif ($_POST['action'] === 'add_payment') { - $amount = $_POST['amount']; + $amount = (float)$_POST['amount']; $method = $_POST['payment_method']; $stmt = db()->prepare("INSERT INTO payments (order_id, amount, payment_method) VALUES (?, ?, ?)"); $stmt->execute([$order_id, $amount, $method]); @@ -43,6 +60,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $stmt = db()->prepare("UPDATE orders SET payment_status = ? WHERE id = ?"); $stmt->execute([$payment_status, $order_id]); + // WhatsApp Notification for Payment Received + try { + if (get_setting('whatsapp_enabled') === '1' && !empty($order['customer_phone'])) { + $remaining_now = (float)$order['total_price'] - (float)$total_paid; + $template = get_setting('msg_payment_ar'); + if (!empty($template)) { + $message = str_replace( + ['{customer_name}', '{order_number}', '{amount}', '{remaining_balance}'], + [$order['customer_name_ar'], $order['order_number'], $amount, max(0, $remaining_now)], + $template + ); + send_whatsapp_message($order['customer_phone'], $message); + } + } + } catch (Exception $e) {} + header("Location: order_details.php?id=$order_id"); exit; } @@ -193,7 +226,7 @@ $payments = $stmt->fetchAll(); $stmt = db()->prepare("SELECT SUM(amount) as total_paid FROM payments WHERE order_id = ?"); $stmt->execute([$order_id]); $total_paid = $stmt->fetch()['total_paid'] ?? 0; - $remaining = $order['total_price'] - $total_paid; + $remaining = (float)$order['total_price'] - (float)$total_paid; ?>
@@ -255,4 +288,4 @@ function getPaymentStatusColor($status) { ][$status] ?? 'info'; } require_once __DIR__ . '/includes/footer.php'; -?> +?> \ No newline at end of file