Files
Siro/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/confirm_payment.php
2026-06-16 22:44:11 +03:00

237 lines
9.7 KiB
PHP
Executable File

<?php
// /v1/main/ride/syriatel/driver/confirm_payment.php
// يعتمد على jwtconnect.php و syriatel_token_handler.php فقط
include_once "../../../jwtconnect.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");
$tokenSiro = generateToken($con, $driverId, $originalAmount);
if (!$tokenSiro) throw new RuntimeException("Failed to generate siro 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]);
// siroWallet
$q2 = $con->prepare("INSERT INTO siroWallet (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'=>$tokenSiro
]);
if ($q2->rowCount() === 0) throw new RuntimeException("Insert siroWallet failed");
$con->prepare("UPDATE payment_tokens SET isUsed = 1 WHERE token = :t")->execute([':t'=>$tokenSiro]);
// تأشير السجل كمنتهٍ للمحفظة
$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.");
}