Files
Siro/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/confirm_payment.php

203 lines
9.2 KiB
PHP
Executable File

<?php
// /v1/main/ride/syriatel/passenger/confirm_payment.php
include "../../../jwtconnect.php";
include_once __DIR__ . "/syriatel_token_handler.php";
header('Content-Type: application/json; charset=utf-8');
/** Helpers **/
function mlog(string $msg) { error_log($msg); }
// تعريف دالة توليد التوكن محلياً (نفس منطق السائق ولكن للراكب)
if (!function_exists('generateLocalToken')) {
function generateLocalToken($con, $userId, $amount) {
// مفتاح سري بسيط للتشفير (يمكنك تغييره أو جلبه من ملف الإعدادات)
$secretKey = 'Tripz_Passenger_Secret_Key';
$data = $userId . $amount . time() . $secretKey;
$hash = hash('sha256', $data);
$randomBytes = bin2hex(random_bytes(16));
$token = substr($hash . $randomBytes, 0, 64);
$stmt = $con->prepare("INSERT INTO payment_tokens (token, passengerID, dateCreated, amount) VALUES (:token, :passengerID, NOW(), :amount)");
// لاحظ: استخدمنا passengerID هنا بدلاً من driverID بناء على الجدول، إذا كان الجدول موحداً استخدم العمود المناسب
// غالباً الجدول يحتوي user_id أو يتم استخدام driverID للكل.
// سأفترض هنا أن الجدول يقبل التوكن، وسأقوم بربطه بالراكب.
// إذا كان عمود driverID هو الوحيد الموجود، يمكن تمرير الراكب فيه أو تعديل الجدول.
// **للتوافق مع السائق:** سأستخدم الحقل العام أو أتجاوز الـ foreign key إذا وجد.
// لكن الأضمن:
$stmt->execute([':token' => $token, ':passengerID' => $userId, ':amount' => $amount]);
return $stmt->rowCount() > 0 ? $token : null;
}
}
// --- المدخلات ---
$transactionID = filterRequest('transactionID'); // يقابل order_ref
$otp = filterRequest('otp'); // كود التأكيد
$lang = filterRequest('lang'); // اختياري
mlog("Syriatel Confirm (Passenger): Start tx={$transactionID}");
if (!$transactionID || !$otp) {
printFailure($lang === 'ar' ? "رقم العملية أو رمز OTP مفقود." : "Missing transaction ID or OTP.");
exit;
}
// --- المتغيرات البيئية ---
$baseUrl = rtrim(getenv('SYRIATEL_API_BASE_URL'), '/');
$merchantMSISDN = getenv('SYRIATEL_MERCHANT_MSISDN');
if (!$baseUrl || !$merchantMSISDN) {
printFailure($lang === 'ar' ? "خطأ في إعدادات الخادم." : "Server configuration error.");
exit;
}
try {
// 1) توكن المصادقة من Syriatel
$token = getSyriatelToken();
if (!$token) {
printFailure($lang === 'ar' ? "تعذّر المصادقة مع مزوّد الدفع." : "Could not authenticate with the payment provider.");
exit;
}
// 2) تحضير وإرسال طلب التأكيد لشركة سيريتل
$body = [
"OTP" => $otp,
"merchantMSISDN" => $merchantMSISDN,
"transactionID" => $transactionID,
"token" => $token
];
$ch = curl_init("{$baseUrl}/ePaymentExternalModule/paymentConfirmation");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body, JSON_UNESCAPED_UNICODE),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
CURLOPT_TIMEOUT => 25,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$res = json_decode($response ?: '{}', true);
if (!is_array($res)) { $res = []; }
$errCode = isset($res['errorCode']) ? (string)$res['errorCode'] : null;
// التحقق من رد سيريتل
if ($httpCode !== 200 || $errCode !== "0") {
$errText = $res['errorDesc'] ?? $res['resultDescription'] ?? 'Payment failed';
mlog("Syriatel Confirm (Passenger): Failed - " . json_encode($res, JSON_UNESCAPED_UNICODE));
printFailure(['message' => $errText, 'syriatel' => $res]);
exit;
}
// ============================================================
// ✅ هنا يبدأ التعديل: التحديث المباشر لقاعدة البيانات (بدون cURL)
// ============================================================
global $con;
// بدء المعاملة أولاً (قبل SELECT للحماية من السباق)
$con->beginTransaction();
// 4) التحقق من السجل في قاعدة البيانات مع FOR UPDATE
$chk = $con->prepare("SELECT status, user_id, amount, payment_method FROM paymentsLogSyria WHERE order_ref = :ref LIMIT 1 FOR UPDATE");
$chk->execute([':ref' => $transactionID]);
$payment = $chk->fetch(PDO::FETCH_ASSOC);
if (!$payment) {
$con->rollBack();
printFailure($lang === 'ar' ? "لم يتم العثور على السجل." : "Payment row not found");
exit;
}
if ((int)$payment['status'] === 1) {
$con->rollBack();
printSuccess(['message' => 'Already confirmed', 'data' => ['order_ref' => $transactionID]]);
exit;
}
try {
// أ) تحديث حالة الدفع في السجل
$stmtUpdate = $con->prepare("UPDATE `paymentsLogSyria` SET status = 1, updated_at = NOW() WHERE order_ref = :ref");
$stmtUpdate->execute([':ref' => $transactionID]);
$passengerId = $payment['user_id'];
$originalAmount = floatval($payment['amount']);
$paymentMethod = $payment['payment_method'] ?? 'syriatel';
// ب) حساب المكافأة (نفس المنطق القديم)
$bonusAmount = match ((int)$originalAmount) {
500 => 530.0,
1000 => 1070.0,
2000 => 2180.0,
5000 => 5700.0,
default => $originalAmount,
};
// ج) إنشاء التوكنات مباشرة (بدون دالة خارجية)
// 1. توكن لمحفظة الراكب (بالمبلغ مع البونص)
$tokenPassenger = generateLocalToken($con, $passengerId, $bonusAmount);
if (!$tokenPassenger) throw new Exception('Failed to generate passenger token');
// 2. توكن لمحفظة السفر/الإيرادات (بالمبلغ الأصلي)
$tokenSiro = generateLocalToken($con, $passengerId, $originalAmount);
if (!$tokenSiro) throw new Exception('Failed to generate siro token');
// د) الإضافة إلى passengerWallet مباشرة
// ملاحظة: تأكد من أسماء الأعمدة في جدول passengerWallet
$insertPassWallet = $con->prepare("INSERT INTO passengerWallet (passenger_id, balance, token, created_at) VALUES (:pid, :amount, :token, NOW())");
$insertPassWallet->execute([
':pid' => $passengerId,
':amount' => $bonusAmount,
':token' => $tokenPassenger
]);
if ($insertPassWallet->rowCount() === 0) throw new Exception('Insert to passengerWallet failed');
// هـ) الإضافة إلى siroWallet مباشرة
// ملاحظة: في الراكب، يكون driverId عادة هو 'passenger' لتمييز أن الدفع جاء من تطبيق الراكب
$insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt)
VALUES (:did, :pid, :amount, :method, :token, NOW())");
$insertSiro->execute([
':did' => 'passenger', // كما في السكربت القديم
':pid' => $passengerId,
':amount' => $originalAmount,
':method' => $paymentMethod,
':token' => $tokenSiro
]);
if ($insertSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed');
// و) تحديث التوكنات لتصبح مستخدمة (isUsed = TRUE)
$updateToken = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token");
$updateToken->execute([':token' => $tokenPassenger]);
$updateToken->execute([':token' => $tokenSiro]);
// ز) تثبيت المعاملة
$con->commit();
mlog("Syriatel Confirm (Passenger): Success DB Transaction for user {$passengerId}");
// إرجاع رد النجاح
printSuccess([
'message' => 'Syriatel Confirm Success',
'data' => [
'order_ref' => $transactionID,
'finalAmount' => $bonusAmount,
'syriatel' => $res
]
]);
exit;
} catch (Throwable $e) {
// في حال حدوث خطأ، تراجع عن كل شيء
$con->rollBack();
mlog("Syriatel Confirm (Passenger): Transaction Error - " . $e->getMessage());
printFailure($lang === 'ar' ? "فشل تحديث المحفظة." : "Wallet update failed.");
exit;
}
} catch (Throwable $e) {
mlog("Syriatel Confirm (Passenger): General Exception - " . $e->getMessage());
printFailure($lang === 'ar' ? "خطأ في الخادم." : "Server error");
exit;
}
?>