sub)) { $driverId = $decodedToken->sub; } else { printFailure("Unauthorized. Valid token required."); exit; } $amount_raw = filterRequest("amount"); $wallet_type = filterRequest("wallet_type") ?? 'Sham Cash'; $otp = filterRequest("otp"); $amount = is_numeric($amount_raw) ? (float)$amount_raw : 0.0; // تحقق أساسي if (empty($driverId) || $amount <= 0) { printFailure("driverId and a valid amount are required."); exit; } if (empty($otp)) { printFailure("OTP code is required for payout."); exit; } try { // --- 2. Fetch Driver info & Dynamic Fee (S3) --- $stmtDriver = $con->prepare("SELECT phone, site FROM driver WHERE id = :id"); $stmtDriver->execute([':id' => $driverId]); $driverInfo = $stmtDriver->fetch(PDO::FETCH_ASSOC); if (!$driverInfo) { printFailure("Driver not found."); exit; } $phone = $encryptionHelper->decryptData($driverInfo['phone']); $site = $encryptionHelper->decryptData($driverInfo['site']); $payout_fee = 0.0; if (strtolower($site) === 'syria') { $payout_fee = 35.00; } elseif (strtolower($site) === 'egypt') { $payout_fee = 10.00; } elseif (strtolower($site) === 'jordan') { $payout_fee = 0.00; } else { $payout_fee = 35.00; // Default fallback } $total_deduction = $amount + $payout_fee; // --- 3. OTP Verification (S6) --- $encryptedPhone = $encryptionHelper->encryptData($phone); $encryptedOtp = $encryptionHelper->encryptData($otp); $stmtOtp = $con->prepare("SELECT id FROM token_verification_driver WHERE phone_number = ? AND token = ? AND expiration_time > NOW() AND verified = 0 LIMIT 1"); $stmtOtp->execute([$encryptedPhone, $encryptedOtp]); $otpRow = $stmtOtp->fetch(PDO::FETCH_ASSOC); if (!$otpRow) { printFailure("Invalid or expired OTP. Please request a new one."); exit; } // --- 4. Atomic balance check + deduction + insert (S2, S4) --- $con->beginTransaction(); $stmt_balance = $con->prepare(" SELECT COALESCE(SUM(amount), 0) AS balance FROM driverWallet WHERE driverID = :id FOR UPDATE "); $stmt_balance->execute([':id' => $driverId]); $wallet = $stmt_balance->fetch(PDO::FETCH_ASSOC); if ($wallet['balance'] < $total_deduction) { $con->rollBack(); printFailure("Insufficient balance. Required: $total_deduction"); exit; } // S4 Fix: Deduct the balance IMMEDIATELY $insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, NULL, :amount, :paymentMethod)"); $insertDriver->execute([ ':driverID' => $driverId, ':amount' => -$total_deduction, ':paymentMethod' => 'payout_reserved' ]); $sql = " INSERT INTO payout_requests (driver_id, driver_phone, amount, wallet_type) VALUES (:did, :phone, :amount, :wallet) "; $stmt = $con->prepare($sql); $stmt->execute([ ':did' => $driverId, ':phone' => $phone, ':amount'=> $amount, ':wallet'=> $wallet_type ]); // Mark OTP as verified $con->prepare("UPDATE token_verification_driver SET verified = 1 WHERE id = ?")->execute([$otpRow['id']]); $con->commit(); if ($stmt->rowCount() > 0) { $customerServicePhone = getenv('CUSTOMER_SERVICE_PHONE'); $message = "⚠️ طلب دفع جديد:\n" . "ID السائق: {$driverId}\n" . "هاتف السائق: {$phone}\n" . "البلد: {$site}\n" . "نوع المحفظة: {$wallet_type}\n" . "المبلغ المطلوب: {$amount}\n" . "الرسوم المخصومة: {$payout_fee}\n\n" . "الرجاء من فريق خدمة العملاء تنفيذ عملية الدفع الآن."; sendWhatsAppFromServer($customerServicePhone, $message); error_log("[RequestPayout] Successfully created payout request for driver ID: $driverId"); printSuccess("Payout request created successfully. It will be processed shortly."); } else { printFailure("Failed to create payout request."); } } catch (PDOException $e) { if ($con->inTransaction()) { $con->rollBack(); } error_log("[RequestPayout] PDOException: " . $e->getMessage()); printFailure("A database error occurred."); } ?>