Deploy: 2026-05-22 01:25:54
This commit is contained in:
@@ -219,13 +219,29 @@ class WhatsAppController extends BaseController
|
||||
|
||||
// 2. Log the incoming message in history log
|
||||
$isAudioMsg = !empty($msgData['audio']) && !empty($msgData['mimeType']);
|
||||
$isImageMsg = !empty($msgData['image']) && !empty($msgData['imageMimeType']);
|
||||
|
||||
$msgType = 'text';
|
||||
if ($isAudioMsg) {
|
||||
$msgType = 'audio';
|
||||
} elseif ($isImageMsg) {
|
||||
$msgType = 'image';
|
||||
}
|
||||
|
||||
$msgBody = $msgData['body'];
|
||||
if ($isAudioMsg) {
|
||||
$msgBody = $msgData['body'] ?: '[Voice Note]';
|
||||
} elseif ($isImageMsg) {
|
||||
$msgBody = $msgData['body'] ?: '[Image]';
|
||||
}
|
||||
|
||||
\App\Models\MessageLog::logMessage([
|
||||
'company_id' => $session['company_id'],
|
||||
'session_id' => $session['id'],
|
||||
'contact_phone' => $msgData['phone'],
|
||||
'direction' => 'inbound',
|
||||
'message_type' => $isAudioMsg ? 'audio' : 'text',
|
||||
'message_body' => $isAudioMsg ? ($msgData['body'] ?: '[Voice Note]') : $msgData['body'],
|
||||
'message_type' => $msgType,
|
||||
'message_body' => $msgBody,
|
||||
'whatsapp_message_id' => $msgData['id'],
|
||||
'status' => 'read'
|
||||
]);
|
||||
@@ -290,8 +306,9 @@ class WhatsAppController extends BaseController
|
||||
|
||||
$incomingText = isset($msgData['body']) ? trim($msgData['body']) : '';
|
||||
$hasAudio = !empty($msgData['audio']) && !empty($msgData['mimeType']);
|
||||
$hasImage = !empty($msgData['image']) && !empty($msgData['imageMimeType']);
|
||||
|
||||
if (empty($incomingText) && !$hasAudio) {
|
||||
if (empty($incomingText) && !$hasAudio && !$hasImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,12 +346,35 @@ class WhatsAppController extends BaseController
|
||||
$mimeType = trim(explode(';', $mimeType)[0]);
|
||||
}
|
||||
$replyText = \App\Services\GeminiService::generateResponseFromAudio($apiKey, $systemPrompt, $msgData['audio'], $mimeType);
|
||||
} elseif ($hasImage) {
|
||||
$mimeType = $msgData['imageMimeType'];
|
||||
if (strpos($mimeType, ';') !== false) {
|
||||
$mimeType = trim(explode(';', $mimeType)[0]);
|
||||
}
|
||||
|
||||
// Instruct Gemini to identify payment slips and output a specific command format if found
|
||||
$imageSystemPrompt = $systemPrompt . "\n\nإرشادات إضافية للصور والوصولات:\nإذا كانت الصورة المرفقة عبارة عن وصل دفع أو إيصال تحويل مالي (مثل زين كاش أو إيداع بنكي)، يرجى استخراج البيانات التالية بدقة بالغة وكتابتها في بداية ردك بصيغة JSON محاطة بـ [PAYMENT_RECEIPT: { ... }] كالتالي:\n[PAYMENT_RECEIPT: {\"transaction_id\": \"رقم المعاملة أو الحوالة هنا\", \"amount\": \"المبلغ المستخرج كأرقام فقط\", \"method\": \"طريقة الدفع مثل Zain Cash أو Bank\"}]\nثم أكمل ردك الطبيعي بالترحيب بالسائق/العميل وإخباره بأنه جاري التحقق من عملية الدفع الآن.";
|
||||
|
||||
$replyText = \App\Services\GeminiService::generateResponseFromImage($apiKey, $imageSystemPrompt, $msgData['image'], $mimeType);
|
||||
} else {
|
||||
$replyText = \App\Services\GeminiService::generateResponse($apiKey, $systemPrompt, $incomingText);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($replyText)) {
|
||||
// Check if the reply contains [PAYMENT_RECEIPT: { ... }] tag from Gemini
|
||||
if (preg_match('/\[PAYMENT_RECEIPT:\s*(\{.*?\})\]/s', $replyText, $matches)) {
|
||||
$jsonStr = $matches[1];
|
||||
// Strip the tag from the final reply sent to user
|
||||
$replyText = trim(str_replace($matches[0], '', $replyText));
|
||||
|
||||
// Call the payment verification API
|
||||
$verificationResult = $this->verifyPaymentSlip($msgData['phone'], $jsonStr);
|
||||
if ($verificationResult) {
|
||||
$replyText .= "\n\n" . $verificationResult;
|
||||
}
|
||||
}
|
||||
|
||||
// Send reply back to the contact via Node.js Gateway
|
||||
$gatewayUrl = rtrim(getenv('WHATSAPP_GATEWAY_URL') ?: 'http://localhost:3722', '/');
|
||||
if (substr($gatewayUrl, -4) === '/api') {
|
||||
@@ -394,4 +434,69 @@ class WhatsAppController extends BaseController
|
||||
error_log("[Chatbot Exception] Error: " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call external Entaleq API to verify payment slip
|
||||
*/
|
||||
private function verifyPaymentSlip(string $phone, string $jsonStr): ?string
|
||||
{
|
||||
try {
|
||||
$data = json_decode($jsonStr, true);
|
||||
if (!$data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$transactionId = $data['transaction_id'] ?? '';
|
||||
$amount = $data['amount'] ?? '';
|
||||
$method = $data['method'] ?? '';
|
||||
|
||||
if (empty($transactionId) || empty($amount)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Determine API URL (default to localhost mock endpoint)
|
||||
$apiUrl = getenv('ENTALEQ_PAYMENT_API_URL');
|
||||
if (empty($apiUrl)) {
|
||||
$appUrl = rtrim(getenv('APP_URL') ?: 'https://nabeh.intaleqapp.com', '/');
|
||||
$apiUrl = $appUrl . '/api/external/verify-payment';
|
||||
}
|
||||
|
||||
$payload = json_encode([
|
||||
'phone' => $phone,
|
||||
'transaction_id' => $transactionId,
|
||||
'amount' => $amount,
|
||||
'method' => $method
|
||||
]);
|
||||
|
||||
$ch = curl_init($apiUrl);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'X-API-Key: ' . (getenv('ENTALEQ_API_KEY') ?: 'mock-key')
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode !== 200) {
|
||||
return "⏳ تم استلام وصل الدفع ويجري التحقق منه حالياً من قبل المحاسب يدوياً. سنقوم بشحن رصيدك وتنبيهك فور انتهاء العملية.";
|
||||
}
|
||||
|
||||
$resData = json_decode($response, true);
|
||||
if (isset($resData['status']) && $resData['status'] === 'success') {
|
||||
$amtStr = $resData['data']['amount'] ?? $amount;
|
||||
return "✅ تم التحقق من وصل الدفع تلقائياً بنجاح!\n• رقم العملية: " . $transactionId . "\n• القيمة: " . $amtStr . " دينار\n• تم تحديث رصيد حسابك بنجاح.";
|
||||
} else {
|
||||
$reason = $resData['message'] ?? 'العملية مسجلة مسبقاً أو غير صالحة';
|
||||
return "⚠️ لم نتمكن من تأكيد العملية تلقائياً:\n• السبب: " . $reason . "\n\nيجري الآن تحويل المعاملة للمراجعة اليدوية من قبل الإدارة وسنقوم بالرد عليك قريباً.";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
error_log("[Payment Verification Exception] " . $e->getMessage());
|
||||
return "⏳ تم استلام وصل الدفع بنجاح. يجري الآن مراجعته وتدقيقه يدوياً من قبل الإدارة الفنية لتأكيد شحن رصيدك.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user