beginTransaction(); // 3a. Insert main payment record $finalPaymentMethod = ($walletChecked === 'true') ? $paymentMethod . "Ride" : $paymentMethod; $stmtPayment = $con->prepare( "INSERT INTO payments (id, amount, payment_method, passengerID, rideId, driverID) VALUES (UUID_SHORT(), :amount, :payment_method, :passengerID, :rideId, :driverID)" ); $stmtPayment->execute([ ':amount' => $paymentAmount, ':payment_method' => $finalPaymentMethod, ':passengerID' => $passengerId, ':rideId' => $rideId, ':driverID' => $driverId, ]); if ($stmtPayment->rowCount() <= 0) { throw new Exception("Failed to create payment record."); } // 3b. Deduct from passenger wallet (if wallet payment) if ($walletChecked === 'true') { // Check actual balance with row lock $stmtBalance = $con->prepare( "SELECT COALESCE(SUM(balance), 0) AS current_balance FROM passengerWallet WHERE passenger_id = :passenger_id FOR UPDATE" ); $stmtBalance->execute([':passenger_id' => $passengerId]); $balanceRow = $stmtBalance->fetch(PDO::FETCH_ASSOC); $currentBalance = floatval($balanceRow['current_balance']); $deductionAmount = floatval($paymentAmount); if ($currentBalance < $deductionAmount) { throw new Exception("Insufficient wallet balance. Required: $deductionAmount, Available: $currentBalance"); } $stmtPassengerWallet = $con->prepare( "INSERT INTO `passengerWallet` (`passenger_id`, `balance`) VALUES (:passenger_id, :balance)" ); $stmtPassengerWallet->execute([ ':passenger_id' => $passengerId, ':balance' => (-1) * $deductionAmount, ]); if ($stmtPassengerWallet->rowCount() <= 0) { throw new Exception("Failed to deduct from passenger wallet."); } // 3c. Settle existing debt (use actual balance after deduction) $stmtBalanceAfter = $con->prepare( "SELECT COALESCE(SUM(balance), 0) AS balance_after FROM passengerWallet WHERE passenger_id = :passenger_id FOR UPDATE" ); $stmtBalanceAfter->execute([':passenger_id' => $passengerId]); $balanceAfterRow = $stmtBalanceAfter->fetch(PDO::FETCH_ASSOC); $balanceAfter = floatval($balanceAfterRow['balance_after']); if ($balanceAfter < 0) { $stmtPassengerDebt = $con->prepare( "INSERT INTO `passengerWallet` (`passenger_id`, `balance`) VALUES (:passenger_id, :balance)" ); $stmtPassengerDebt->execute([ ':passenger_id' => $passengerId, ':balance' => (-1) * $balanceAfter, ]); if ($stmtPassengerDebt->rowCount() <= 0) { throw new Exception("Failed to settle passenger debt."); } } } // 3d. Deduct driver points (8% of payment amount) $pointsSubtraction = floatval($paymentAmount) * (-0.08); $stmtDriverPoints = $con->prepare( "INSERT INTO `driverWallet` (`driverID`, `paymentID`, `amount`, `paymentMethod`) VALUES (:driverID, :paymentID, :amount, :paymentMethod)" ); $stmtDriverPoints->execute([ ':driverID' => $driverId, ':paymentID' => 'rideId' . $rideId, ':amount' => number_format($pointsSubtraction, 0, '', ''), ':paymentMethod' => $paymentMethod, ]); if ($stmtDriverPoints->rowCount() <= 0) { throw new Exception("Failed to update driver wallet points."); } // --- All operations succeeded → Commit --- $con->commit(); printSuccess("Payment processed successfully for ride $rideId."); } catch (Exception $e) { // --- Any failure → Rollback all changes --- if (isset($con) && $con->inTransaction()) { $con->rollBack(); } error_log("[process_ride_payments] Transaction FAILED for ride $rideId: " . $e->getMessage()); printFailure("Transaction failed"); }