Deploy: 2026-06-18 15:04:52
This commit is contained in:
@@ -2,75 +2,111 @@
|
||||
|
||||
namespace App\Core\Flows;
|
||||
|
||||
use App\Services\GeminiService;
|
||||
use App\Models\ChatbotRule;
|
||||
use App\Services\SiroService;
|
||||
|
||||
/**
|
||||
* PaymentFlow
|
||||
* Handles payment receipt uploads and verification.
|
||||
* PaymentFlow — Smart Payment Verification
|
||||
*
|
||||
* Flow: start → await_receipt → finished
|
||||
*
|
||||
* Automatically:
|
||||
* • Detects country from phone prefix (963→Syria, 962→Jordan)
|
||||
* • Sets payment method (Syria→shamcash, Jordan→cliq)
|
||||
* • Forwards raw receipt image to payment server for AI verification
|
||||
* • Payment server auto-finds the latest pending invoice by phone
|
||||
* → no need for the user to type an invoice number
|
||||
*/
|
||||
class PaymentFlow extends BaseFlow
|
||||
{
|
||||
public function handleStep(string $step, array $messageData, array &$context): FlowResult
|
||||
{
|
||||
$companyId = $context['company_id'] ?? 1;
|
||||
$phone = $messageData['phone'] ?? '';
|
||||
$text = $messageData['body'] ?? $messageData['text'] ?? '';
|
||||
$image = $messageData['image'] ?? '';
|
||||
$imageMimeType = $messageData['imageMimeType'] ?? 'image/jpeg';
|
||||
|
||||
switch ($step) {
|
||||
// ─────────────────────────────────────────────────
|
||||
// START: detect country, set method, ask for receipt
|
||||
// ─────────────────────────────────────────────────
|
||||
case 'start':
|
||||
$country = SiroService::detectCountry($phone);
|
||||
$paymentMethod = match ($country) {
|
||||
'jordan' => 'cliq',
|
||||
default => 'shamcash',
|
||||
};
|
||||
|
||||
$context['payment_method'] = $paymentMethod;
|
||||
$context['country'] = $country;
|
||||
$context['user_type'] = 'driver';
|
||||
|
||||
$methodName = match ($paymentMethod) {
|
||||
'cliq' => 'كليك (Cliq)',
|
||||
default => 'شام كاش (ShamCash)',
|
||||
};
|
||||
|
||||
return new FlowResult(
|
||||
"أهلاً بك كابتن. يرجى إرسال صورة **إيصال التحويل المالي أو وصل الدفع** لكي نقوم بمراجعته وإضافته لحسابك:",
|
||||
"awaiting_receipt"
|
||||
"أهلاً بك. للتحقق من عملية الدفع:\n"
|
||||
. "💰 طريقة الدفع المتوقعة: {$methodName}\n"
|
||||
. "📍 الدولة: " . ($country === 'syria' ? 'سوريا' : ($country === 'jordan' ? 'الأردن' : $country))
|
||||
. "\n\n📸 يرجى إرسال صورة الإيصال أو وصل التحويل للتحقق منه.",
|
||||
"await_receipt"
|
||||
);
|
||||
|
||||
case 'awaiting_receipt':
|
||||
if (empty($messageData['image']) || empty($messageData['imageMimeType'])) {
|
||||
return new FlowResult("الرجاء إرسال صورة وصل الدفع بوضوح للاستمرار، أو اكتب 'إلغاء' للخروج:", "awaiting_receipt");
|
||||
// ─────────────────────────────────────────────────
|
||||
// AWAIT_RECEIPT: collect receipt image
|
||||
// ─────────────────────────────────────────────────
|
||||
case 'await_receipt':
|
||||
if (empty($image)) {
|
||||
return new FlowResult(
|
||||
"الرجاء إرسال صورة واضحة لوصل الدفع أو صورة الشاشة:",
|
||||
"await_receipt"
|
||||
);
|
||||
}
|
||||
|
||||
if ($companyId !== 1) {
|
||||
if (!\App\Models\CompanySubscriptionUsage::hasRemainingLimit($companyId, 'ocr')) {
|
||||
return new FlowResult("⚠️ عذراً، تجاوز المتجر الحد المسموح لمعالجة الصور لهذا الشهر.", "finished", true);
|
||||
}
|
||||
}
|
||||
|
||||
$rule = ChatbotRule::findActiveForRule($companyId);
|
||||
$configuredGeminiKey = ($rule && !empty($rule['gemini_api_key'])) ? $rule['gemini_api_key'] : null;
|
||||
$apiKey = GeminiService::getGeminiApiKey($configuredGeminiKey);
|
||||
|
||||
if (empty($apiKey)) {
|
||||
return new FlowResult("عذراً، عطل فني في خادم معالجة الصور بالذكاء الاصطناعي. يرجى المحاولة لاحقاً.", "finished", true);
|
||||
}
|
||||
|
||||
$imageSystemPrompt = "أنت خبير في مراجعة إيصالات الدفع. استخرج البيانات التالية بدقة بالغة واكتبها بصيغة JSON محاطة بـ [PAYMENT_RECEIPT: { ... }] كالتالي:\n[PAYMENT_RECEIPT: {\"transaction_id\": \"رقم المعاملة أو الحوالة هنا\", \"amount\": \"المبلغ المستخرج كأرقام فقط\", \"method\": \"طريقة الدفع مثل Syriatel Cash أو Bemo Bank\"}]\nفي حال عدم وضوح الإيصال، أرجع JSON فارغًا.";
|
||||
|
||||
$mimeType = $messageData['imageMimeType'];
|
||||
if (strpos($mimeType, ';') !== false) {
|
||||
$mimeType = trim(explode(';', $mimeType)[0]);
|
||||
}
|
||||
|
||||
$replyText = GeminiService::generateResponseFromImage($apiKey, $imageSystemPrompt, $messageData['image'], $mimeType);
|
||||
|
||||
if ($companyId !== 1) {
|
||||
\App\Models\CompanySubscriptionUsage::incrementUsage($companyId, 'ocr');
|
||||
\App\Models\CompanySubscriptionUsage::incrementUsage($companyId, 'request');
|
||||
}
|
||||
|
||||
if (!empty($replyText) && preg_match('/\[PAYMENT_RECEIPT:\s*(\{.*?\})\]/s', $replyText, $matches)) {
|
||||
$jsonStr = $matches[1];
|
||||
$verificationResult = \App\Controllers\WhatsAppController::verifyPaymentSlipStatic($companyId, $phone, $jsonStr);
|
||||
|
||||
if ($verificationResult) {
|
||||
return new FlowResult("تم فحص الإيصال:\n" . $verificationResult, "finished", true);
|
||||
} else {
|
||||
return new FlowResult("لم نتمكن من التأكد من بيانات الإيصال. يرجى إرسال صورة أوضح أو التواصل مع الدعم الفني.", "finished", true);
|
||||
}
|
||||
}
|
||||
|
||||
return new FlowResult("لم أتمكن من التعرف على بيانات الإيصال المرفق. يرجى التأكد من وضوح الصورة وإعادة المحاولة.", "awaiting_receipt");
|
||||
return $this->sendToVerification($phone, $context, $image, $imageMimeType);
|
||||
|
||||
default:
|
||||
return new FlowResult("حدث خطأ في المسار.", "finished", true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward receipt image + phone to payment server for AI verification.
|
||||
* Payment server internally resolves phone→driverID via Siro backend.
|
||||
* Nabeh only makes ONE API call (to payment server).
|
||||
*/
|
||||
private function sendToVerification(
|
||||
string $phone,
|
||||
array &$context,
|
||||
string $image,
|
||||
string $imageMimeType
|
||||
): FlowResult {
|
||||
$companyId = $context['company_id'] ?? 1;
|
||||
|
||||
if (strpos($imageMimeType, ';') !== false) {
|
||||
$imageMimeType = trim(explode(';', $imageMimeType)[0]);
|
||||
}
|
||||
|
||||
$result = \App\Controllers\WhatsAppController::verifyPaymentSlipStatic(
|
||||
companyId: $companyId,
|
||||
phone: $phone,
|
||||
jsonStr: '',
|
||||
userType: $context['user_type'] ?? 'driver',
|
||||
paymentMethod: $context['payment_method'] ?? 'shamcash',
|
||||
invoiceNumber: '',
|
||||
receiptImage: $image,
|
||||
imageMimeType: $imageMimeType,
|
||||
);
|
||||
|
||||
if ($result) {
|
||||
return new FlowResult($result, "finished", true);
|
||||
}
|
||||
|
||||
return new FlowResult(
|
||||
"لم نتمكن من التحقق من الدفع حالياً. يرجى المحاولة مرة أخرى أو التواصل مع الدعم الفني.",
|
||||
"finished",
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user