39038-vm/includes/NotificationService.php
2026-03-13 13:31:02 +00:00

178 lines
6.2 KiB
PHP

<?php
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../mail/MailService.php';
require_once __DIR__ . '/app.php';
class NotificationService
{
/**
* Send a notification for a specific event.
*
* @param string $eventName The event name (e.g., 'shipment_created')
* @param array $user The recipient user array (must contain 'id', 'email', 'full_name', 'role')
* @param array $data Data to replace in placeholders (e.g., ['shipment_id' => 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) {
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.
*/
public static function sendWhatsApp(string $phone, string $message)
{
// 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;
}
// Ensure domain has no trailing slash and correct scheme
$domain = rtrim($domain, '/');
if (!preg_match('/^https?:\\/', $domain)) {
$domain = 'https://' . $domain;
}
// 3. Send API Request
// Endpoint: /api/send-message (StandardWablas)
$url = $domain . "/api/send-message";
$data = [
'phone' => $phone,
'message' => $message,
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: $token",
"Content-Type: application/json" // Wablas often accepts JSON or form-data. Trying JSON first, or form-data if that fails.
// Actually, many Wablas instances use form-data or x-www-form-urlencoded.
// Let's try standard POST fields which curl sends as application/x-www-form-urlencoded by default if passing array.
]);
// Resetting headers to just Authorization for form-urlencoded default
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: $token"
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // For dev env
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
error_log("WHATSAPP cURL Error: $error");
return;
}
// Log result
error_log("WHATSAPP Sent to $phone. Status: $httpCode. Response: " . substr($response, 0, 100));
}
}