123]) * @param string|null $lang 'en' or 'ar'. If null, sends both combined. */ public static function send(string $eventName, array $user, array $data = [], ?string $lang = null) { $pdo = db(); $stmt = $pdo->prepare("SELECT * FROM notification_templates WHERE event_name = ?"); $stmt->execute([$eventName]); $template = $stmt->fetch(); if (!$template) { error_log("Notification template not found: $eventName"); return; } // Prepare data for replacement $placeholders = []; $values = []; $data['user_name'] = $user['full_name'] ?? 'User'; foreach ($data as $key => $val) { $placeholders[] = '{' . $key . '}'; $values[] = $val; } // Determine Subject and Body based on Lang $subject = ''; $body = ''; $whatsapp = ''; if ($lang === 'en') { $subject = $template['email_subject_en']; $body = $template['email_body_en']; $whatsapp = $template['whatsapp_body_en']; } elseif ($lang === 'ar') { $subject = $template['email_subject_ar']; $body = $template['email_body_ar']; $whatsapp = $template['whatsapp_body_ar']; } else { // Combined $subject = $template['email_subject_en'] . ' / ' . $template['email_subject_ar']; $body = $template['email_body_en'] . "\n\n---\n\n" . $template['email_body_ar']; $whatsapp = $template['whatsapp_body_en'] . "\n\n" . $template['whatsapp_body_ar']; } // Replace $subject = str_replace($placeholders, $values, $subject); $body = str_replace($placeholders, $values, $body); $whatsapp = str_replace($placeholders, $values, $whatsapp); // Send Email if (!empty($user['email'])) { // Convert newlines to BR for HTML $htmlBody = nl2br(htmlspecialchars($body)); MailService::sendMail($user['email'], $subject, $htmlBody, $body); } // Send WhatsApp if enabled if (get_setting('whatsapp_enabled') === '1') { $phone = self::getPhoneNumber($user); if ($phone) { // Return value ignored in async/background context, but logged inside self::sendWhatsApp($phone, $whatsapp); } else { error_log("WHATSAPP Notification skipped for {$user['email']}: Phone number not found."); } } } /** * Retrieve phone number for a user, fetching from profile if necessary. */ private static function getPhoneNumber(array $user): ?string { if (!empty($user['phone'])) { return $user['phone']; } if (empty($user['id']) || empty($user['role'])) { return null; } $pdo = db(); if ($user['role'] === 'shipper') { $stmt = $pdo->prepare("SELECT phone FROM shipper_profiles WHERE user_id = ?"); $stmt->execute([$user['id']]); return $stmt->fetchColumn() ?: null; } elseif ($user['role'] === 'truck_owner') { $stmt = $pdo->prepare("SELECT phone FROM truck_owner_profiles WHERE user_id = ?"); $stmt->execute([$user['id']]); return $stmt->fetchColumn() ?: null; } return null; } /** * Send a WhatsApp message via Wablas API. * @return array ['success' => bool, 'message' => string, 'response' => mixed] */ public static function sendWhatsApp(string $phone, string $message): array { // 1. Format Phone Number // Remove non-numeric characters $phone = preg_replace('/[^0-9]/', '', $phone); // If 8 digits, prepend 968 (Oman country code) if (strlen($phone) === 8) { $phone = '968' . $phone; } // 2. Get Settings $domain = get_setting('wablas_domain'); $token = get_setting('wablas_api_token'); if (!$domain || !$token) { error_log("WHATSAPP Error: Wablas domain or token not configured."); return ['success' => false, 'message' => 'Domain or Token missing']; } // Ensure domain has no trailing slash and correct scheme $domain = rtrim($domain, '/'); // If domain doesn't start with http/https, prepend https:// if (!preg_match('/^https?:\/\//', $domain)) { $domain = 'https://' . $domain; } // 3. Send API Request // Endpoint: /api/send-message (StandardWablas) $url = $domain . "/api/send-message"; $payload = json_encode([ 'phone' => $phone, 'message' => $message, ]); $ch = curl_init($url); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: $token", "Content-Type: application/json" ]); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 15); // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlErr = curl_error($ch); curl_close($ch); if ($curlErr) { error_log("WHATSAPP cURL Error: $curlErr"); return ['success' => false, 'message' => "Connection error: $curlErr"]; } $decoded = json_decode($response, true); $statusMsg = $decoded['message'] ?? $response; // Log result error_log("WHATSAPP Sent to $phone. Status: $httpCode. Response: " . substr($response, 0, 100)); // Wablas usually returns {'status': true, ...} or {'status': 'pending'} // We consider 200 OK and no explicit 'status': false as success for now $isSuccess = ($httpCode >= 200 && $httpCode < 300); if (isset($decoded['status']) && $decoded['status'] === false) { $isSuccess = false; } return [ 'success' => $isSuccess, 'message' => "API ($httpCode): " . (is_string($statusMsg) ? $statusMsg : json_encode($statusMsg)), 'response' => $decoded ]; } }