Update: 2026-06-11 18:22:57
This commit is contained in:
237
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/confirm_payment.php
Executable file
237
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/confirm_payment.php
Executable file
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
// /v1/main/ride/syriatel/driver/confirm_payment.php
|
||||
// يعتمد على connect.php و syriatel_token_handler.php فقط
|
||||
include_once "../../../connect.php";
|
||||
include_once "./syriatel_token_handler.php";
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// ================== Helpers (طباعة/لوج) ==================
|
||||
if (!function_exists('printSuccess')) {
|
||||
function printSuccess($data = null, $message = "success") {
|
||||
echo json_encode(["status" => "success", "message" => $message, "data" => $data], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
if (!function_exists('printFailure')) {
|
||||
function printFailure($message = "failure", $code = null) {
|
||||
$resp = ["status" => "failure", "message" => $message];
|
||||
if ($code !== null) $resp["code"] = $code;
|
||||
echo json_encode($resp, JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
define("WALLET_LOG", __DIR__ . "/../logs/payment_verification.log");
|
||||
function wlog($step, $msg, $data = null) {
|
||||
$dir = dirname(WALLET_LOG);
|
||||
if (!is_dir($dir)) { @mkdir($dir, 0755, true); }
|
||||
$line = "[".date('Y-m-d H:i:s')."] STEP {$step}: {$msg}";
|
||||
if ($data !== null) $line .= " | Data: ".json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
file_put_contents(WALLET_LOG, $line.PHP_EOL, FILE_APPEND);
|
||||
}
|
||||
|
||||
// ================== منطق التوكن/المعرف ==================
|
||||
function generateToken(PDO $con, string $driverId, float $amount): ?string {
|
||||
// secretKey يُفترض قادم من connect/env
|
||||
global $secretKey;
|
||||
$data = $driverId.$amount.time().($secretKey ?? 'default_secret');
|
||||
$hash = hash('sha256', $data);
|
||||
$rand = bin2hex(random_bytes(16));
|
||||
$token = substr($hash.$rand, 0, 64);
|
||||
|
||||
$stmt = $con->prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount)
|
||||
VALUES (:t, :d, NOW(), :a)");
|
||||
$stmt->execute([':t'=>$token, ':d'=>$driverId, ':a'=>$amount]);
|
||||
return $stmt->rowCount() ? $token : null;
|
||||
}
|
||||
|
||||
function generatePaymentID(PDO $con, string $driverId, float $amount, string $method): ?string {
|
||||
$stmt = $con->prepare("INSERT INTO paymentsDriverPoints (amount, payment_method, driverID)
|
||||
VALUES (:a, :m, :d)");
|
||||
$stmt->execute([':a'=>$amount, ':m'=>$method, ':d'=>$driverId]);
|
||||
return $stmt->rowCount() ? $con->lastInsertId() : null;
|
||||
}
|
||||
|
||||
// ================== منطق إنهاء الدفع (مضمَّن) ==================
|
||||
function finalizeWalletPaymentInline(PDO $con, string $orderRef): void {
|
||||
// نقفل الصف لمنع السباقات
|
||||
$stmt = $con->prepare("SELECT * FROM paymentsLogSyriaDriver
|
||||
WHERE order_ref = :r LIMIT 1 FOR UPDATE");
|
||||
$stmt->execute([':r'=>$orderRef]);
|
||||
$payment = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$payment) {
|
||||
wlog("FINALIZE", "Payment row not found", ['orderRef'=>$orderRef]);
|
||||
throw new RuntimeException("Payment not found.");
|
||||
}
|
||||
|
||||
// نتأكد من نجاح مزود الدفع
|
||||
if ((int)$payment['status'] !== 1) {
|
||||
wlog("FINALIZE", "Payment not completed yet", ['orderRef'=>$orderRef, 'status'=>$payment['status']]);
|
||||
throw new RuntimeException("Payment not completed.");
|
||||
}
|
||||
|
||||
// حارس التكرار: إذا تمّت معالجة المحفظة سابقاً لا نكرر
|
||||
if (!empty($payment['processed_wallet']) && (int)$payment['processed_wallet'] === 1) {
|
||||
wlog("FINALIZE", "Already processed_wallet=1, skip.", ['orderRef'=>$orderRef]);
|
||||
return; // لا نرمي استثناء؛ العملية سبق احتسابها
|
||||
}
|
||||
|
||||
$driverId = $payment['user_id']; // This is now correctly handled as a string
|
||||
$originalAmount = (float)$payment['amount'];
|
||||
$paymentMethod = $payment['payment_method'] ?: 'ecash';
|
||||
|
||||
// البونص
|
||||
$bonusAmount = match ((int)$originalAmount) {
|
||||
100 => 100.0,
|
||||
200 => 210.0,
|
||||
400 => 450.0,
|
||||
1000 => 1100.0,
|
||||
default => $originalAmount,
|
||||
};
|
||||
|
||||
// تنفيذ ككل داخل معاملة
|
||||
$con->beginTransaction();
|
||||
try {
|
||||
// توليد التوكنات/المعرف
|
||||
$tokenDriver = generateToken($con, $driverId, $bonusAmount);
|
||||
if (!$tokenDriver) throw new RuntimeException("Failed to generate driver token");
|
||||
|
||||
$tokenSefer = generateToken($con, $driverId, $originalAmount);
|
||||
if (!$tokenSefer) throw new RuntimeException("Failed to generate sefer token");
|
||||
|
||||
$paymentID = generatePaymentID($con, $driverId, $bonusAmount, $paymentMethod);
|
||||
if (!$paymentID) throw new RuntimeException("Failed to create payment ID");
|
||||
|
||||
// driverWallet
|
||||
$q = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod)
|
||||
VALUES (:d, :r, :a, :m)");
|
||||
$q->execute([
|
||||
':d'=>$driverId, ':a'=>$bonusAmount,
|
||||
':m'=>$paymentMethod, ':r'=>$orderRef
|
||||
]);
|
||||
if ($q->rowCount() === 0) throw new RuntimeException("Insert driverWallet failed");
|
||||
|
||||
// وسم التوكن كمستخدم
|
||||
$con->prepare("UPDATE payment_tokens SET isUsed = 1 WHERE token = :t")->execute([':t'=>$tokenDriver]);
|
||||
|
||||
// seferWallet
|
||||
$q2 = $con->prepare("INSERT INTO seferWallet (driverId, passengerId, amount, paymentMethod, token, createdAt)
|
||||
VALUES (:d, :p, :a, :m, :t, CURRENT_TIMESTAMP)");
|
||||
$q2->execute([
|
||||
':d'=>$driverId, ':p'=>'driver', ':a'=>$originalAmount,
|
||||
':m'=>$paymentMethod, ':t'=>$tokenSefer
|
||||
]);
|
||||
if ($q2->rowCount() === 0) throw new RuntimeException("Insert seferWallet failed");
|
||||
|
||||
$con->prepare("UPDATE payment_tokens SET isUsed = 1 WHERE token = :t")->execute([':t'=>$tokenSefer]);
|
||||
|
||||
// تأشير السجل كمنتهٍ للمحفظة
|
||||
$con->prepare("UPDATE paymentsLogSyriaDriver
|
||||
SET processed_wallet = 1, updated_at = NOW()
|
||||
WHERE order_ref = :r")->execute([':r'=>$orderRef]);
|
||||
|
||||
$con->commit();
|
||||
wlog("FINALIZE", "Wallets updated successfully", ['orderRef'=>$orderRef, 'driverId'=>$driverId]);
|
||||
} catch (Throwable $e) {
|
||||
$con->rollBack();
|
||||
wlog("FINALIZE", "Exception: ".$e->getMessage(), ['orderRef'=>$orderRef]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
// ================== مدخل تأكيد الدفع ==================
|
||||
$transactionID = filterRequest('transactionID');
|
||||
$otp = filterRequest('otp');
|
||||
|
||||
error_log("Syriatel Confirm: Request for transaction {$transactionID}");
|
||||
|
||||
if (!$transactionID || !$otp) {
|
||||
printFailure("Missing transaction ID or OTP.");
|
||||
}
|
||||
|
||||
// بيئة
|
||||
$baseUrl = rtrim((string)getenv('SYRIATEL_API_BASE_URL'), '/');
|
||||
$merchantMSISDN = (string)getenv('SYRIATEL_MERCHANT_MSISDN');
|
||||
if ($baseUrl === '' || $merchantMSISDN === '') {
|
||||
error_log("Syriatel Confirm: Missing SYRIATEL envs");
|
||||
printFailure("Server configuration error.");
|
||||
}
|
||||
|
||||
try {
|
||||
// 1) Auth token
|
||||
$token = function_exists('GetSerialToken') ? GetSerialToken() : getSyriatelToken();
|
||||
if (!$token) { printFailure("Could not authenticate with the payment provider."); }
|
||||
|
||||
// 2) Call provider
|
||||
$body = [
|
||||
"OTP" => $otp,
|
||||
"merchantMSISDN" => $merchantMSISDN,
|
||||
"transactionID" => $transactionID,
|
||||
"token" => $token
|
||||
];
|
||||
$url = "{$baseUrl}/ePaymentExternalModule/paymentConfirmation";
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($body, JSON_UNESCAPED_UNICODE),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
"Content-Type: application/json",
|
||||
"Accept: application/json",
|
||||
"User-Agent: Mozilla/5.0",
|
||||
],
|
||||
CURLOPT_CONNECTTIMEOUT => 8,
|
||||
CURLOPT_TIMEOUT => 40,
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
CURLOPT_SSL_VERIFYHOST => 2,
|
||||
]);
|
||||
$response = curl_exec($ch);
|
||||
$errno = curl_errno($ch);
|
||||
$httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
error_log("Syriatel Confirm: HTTP {$httpCode} - ".substr((string)$response, 0, 300));
|
||||
|
||||
if ($errno) { printFailure("Payment gateway communication error.", $errno); }
|
||||
if ($httpCode !== 200 || !$response) { printFailure("Payment gateway communication error (HTTP {$httpCode})."); }
|
||||
|
||||
$responseData = json_decode($response, true);
|
||||
if (!is_array($responseData)) { printFailure("Invalid provider response."); }
|
||||
|
||||
$ok = (isset($responseData['errorDesc']) && $responseData['errorDesc'] === "Success");
|
||||
|
||||
if ($ok) {
|
||||
// نحدّث حالة الدفع، ونُتم المحفظة بشكل آمن داخل نفس الطلب
|
||||
$con->prepare("UPDATE paymentsLogSyriaDriver
|
||||
SET status = 1, updated_at = NOW()
|
||||
WHERE order_ref = :r")->execute([':r'=>$transactionID]);
|
||||
|
||||
// إنهاء المحفظة (داخلية)
|
||||
$walletOk = true; $walletMsg = null;
|
||||
try {
|
||||
finalizeWalletPaymentInline($con, $transactionID);
|
||||
} catch (Throwable $ex) {
|
||||
$walletOk = false; $walletMsg = $ex->getMessage();
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'message' => 'Payment confirmed.',
|
||||
'transactionID' => $transactionID,
|
||||
'provider' => $responseData
|
||||
];
|
||||
if (!$walletOk && $walletMsg) {
|
||||
$payload['walletNotice'] = "Payment successful, but wallet update failed: ".$walletMsg;
|
||||
}
|
||||
|
||||
printSuccess($payload);
|
||||
}
|
||||
|
||||
$errorMessage = $responseData['errorDesc'] ?? 'Unknown provider error';
|
||||
printFailure($errorMessage);
|
||||
|
||||
} catch (Throwable $e) {
|
||||
error_log("Syriatel Confirm: Exception - ".$e->getMessage());
|
||||
printFailure("An unexpected server error occurred.");
|
||||
}
|
||||
Reference in New Issue
Block a user