From fccd758e93e4bded2e4903d6a4503bc5a0b11adb Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sat, 25 Apr 2026 00:31:08 +0300 Subject: [PATCH] Sync Ride Lifecycle with V1: Added legacy array payload, DriverList, and driver_orders tracking --- app/Http/Controllers/RideController.php | 588 +++++++++++++----------- 1 file changed, 319 insertions(+), 269 deletions(-) diff --git a/app/Http/Controllers/RideController.php b/app/Http/Controllers/RideController.php index 3e3e817..4420eab 100644 --- a/app/Http/Controllers/RideController.php +++ b/app/Http/Controllers/RideController.php @@ -8,25 +8,13 @@ use App\Models\DriverToken; use App\Models\PassengerToken; use App\Models\DriverOrder; use App\Models\CarLocation; -use App\Helpers\LegacyEncryption; +use App\Services\LegacyEncryption; use App\Services\FcmService; use App\Services\SocketService; use Illuminate\Http\Request; use Illuminate\Http\JsonResponse; use Illuminate\Support\Facades\DB; -/** - * متحكم الرحلات (Ride Controller) - * - * الغرض من الملف: - * إدارة دورة حياة الرحلة بالكامل؛ بدءاً من طلب الراكب للرحلة حتى وصوله ودفعه للأجرة. - * - * كيفية العمل: - * 1. يستقبل طلبات الرحلات الجديدة ويحفظها في جدول (waitingRides). - * 2. يسمح للسائقين بقبول الرحلات المتاحة وتحديث حالتهم. - * 3. يدير حالات الرحلة المختلفة: (انتظار، قبول، وصول السائق، بدء الرحلة، انتهاء الرحلة). - * 4. يرسل إشعارات فورية للركاب والسائقين عند أي تغيير في حالة الرحلة. - */ class RideController extends Controller { private LegacyEncryption $encryption; @@ -40,12 +28,9 @@ class RideController extends Controller $this->socket = $socket; } - /** - * POST /v2/rides - * Replaces: ride/rides/add_ride.php - */ public function store(Request $request): JsonResponse { + // 1. Validation (Adding new required fields for the 33-item array) $request->validate([ 'start_location' => 'required|string', 'end_location' => 'required|string', @@ -55,23 +40,34 @@ class RideController extends Controller 'price_for_driver' => 'nullable|numeric|min:0', 'price_for_passenger' => 'nullable|numeric|min:0', 'status' => 'nullable|string', - // Socket specific fields - 'start_lat' => 'nullable|numeric', - 'start_lng' => 'nullable|numeric', - 'end_lat' => 'nullable|numeric', - 'end_lng' => 'nullable|numeric', + + // Socket / Legacy array specific fields + 'passenger_name' => 'nullable|string', + 'passenger_phone' => 'nullable|string', + 'passenger_token' => 'nullable|string', + 'passenger_email' => 'nullable|string', + 'passenger_wallet' => 'nullable|string', + 'passenger_rating' => 'nullable|string', + 'start_name' => 'nullable|string', 'end_name' => 'nullable|string', 'duration_text' => 'nullable|string', - 'passenger_rating' => 'nullable|numeric', + 'distance_text' => 'nullable|string', + 'is_wallet' => 'nullable|string', + 'has_steps' => 'nullable|string', + + 'step0' => 'nullable|string', + 'step1' => 'nullable|string', + 'step2' => 'nullable|string', + 'step3' => 'nullable|string', + 'step4' => 'nullable|string', ]); $passengerId = $request->attributes->get('_jwt_user_id'); - // Prevent duplicate active rides $activeRide = DB::connection('ride')->table('ride') ->where('passenger_id', $passengerId) - ->whereIn('status', ['waiting', 'going_to_passenger', 'arrived', 'started']) + ->whereIn('status', ['waiting', 'going_to_passenger', 'arrived', 'started', 'Begin']) ->first(); if ($activeRide) { @@ -81,7 +77,6 @@ class RideController extends Controller ], 409); } - // Data array as expected by V1 Database $rideData = [ 'start_location' => $request->input('start_location'), 'end_location' => $request->input('end_location'), @@ -90,7 +85,7 @@ class RideController extends Controller 'endtime' => '00:00:00', 'price' => $request->input('price'), 'passenger_id' => $passengerId, - 'driver_id' => '0', // 0 in V1 instead of 'none' + 'driver_id' => '0', 'status' => $request->input('status', 'waiting'), 'carType' => $request->input('car_type', 'Speed'), 'price_for_driver' => $request->input('price_for_driver', $request->input('price')), @@ -102,42 +97,80 @@ class RideController extends Controller DB::connection('ride')->beginTransaction(); try { - // 1. Insert into Primary DB (Main Server) $insertedId = DB::connection('primary')->table('ride')->insertGetId($rideData); - // 2. Insert into Ride DB (Tracking Server) - $rideData['id'] = $insertedId; // Keep IDs perfectly synced + $rideData['id'] = $insertedId; DB::connection('ride')->table('ride')->insert($rideData); DB::connection('primary')->commit(); DB::connection('ride')->commit(); - // 3. Broadcast to Marketplace (Location Socket) + // Prepare Legacy Array [0..33] + $partsStart = explode(',', $request->input('start_location')); + $startLat = trim($partsStart[0] ?? ""); + $startLng = trim($partsStart[1] ?? ""); + + $partsEnd = explode(',', $request->input('end_location')); + $endLat = trim($partsEnd[0] ?? ""); + $endLng = trim($partsEnd[1] ?? ""); + + $price = (float) $request->input('price'); + $priceForDriver = (float) $request->input('price_for_driver', $price); + $kazan = $price - $priceForDriver; + + $payloadTemplate = []; + $payloadTemplate[0] = (string)$startLat; + $payloadTemplate[1] = (string)$startLng; + $payloadTemplate[2] = (string)number_format($price, 2, '.', ''); + $payloadTemplate[3] = (string)$endLat; + $payloadTemplate[4] = (string)$endLng; + $payloadTemplate[5] = (string)$request->input('distance_text', ''); + $payloadTemplate[6] = ""; + $payloadTemplate[7] = (string)$passengerId; + $payloadTemplate[8] = (string)$request->input('passenger_name', ''); + $payloadTemplate[9] = (string)$request->input('passenger_token', ''); + $payloadTemplate[10] = (string)$request->input('passenger_phone', ''); + $payloadTemplate[11] = (string)$request->input('distance', '0'); + $payloadTemplate[12] = "1"; + $payloadTemplate[13] = (string)$request->input('is_wallet', '0'); + $payloadTemplate[14] = (string)$request->input('distance', '0'); + $payloadTemplate[15] = (string)$request->input('duration_text', ''); + $payloadTemplate[16] = (string)$insertedId; + $payloadTemplate[17] = ""; + $payloadTemplate[18] = ""; + $payloadTemplate[19] = (string)$request->input('duration_text', ''); + $payloadTemplate[20] = $request->input('has_steps') ?: 'false'; + $payloadTemplate[21] = (string)$request->input('step0', ''); + $payloadTemplate[22] = (string)$request->input('step1', ''); + $payloadTemplate[23] = (string)$request->input('step2', ''); + $payloadTemplate[24] = (string)$request->input('step3', ''); + $payloadTemplate[25] = (string)$request->input('step4', ''); + $payloadTemplate[26] = (string)number_format($priceForDriver, 2, '.', ''); + $payloadTemplate[27] = (string)$request->input('passenger_wallet', '0'); + $payloadTemplate[28] = (string)$request->input('passenger_email', ''); + $payloadTemplate[29] = (string)$request->input('start_name', ''); + $payloadTemplate[30] = (string)$request->input('end_name', ''); + $payloadTemplate[31] = (string)$request->input('car_type', 'Speed'); + $payloadTemplate[32] = (string)number_format($kazan, 2, '.', ''); + $payloadTemplate[33] = (string)$request->input('passenger_rating', '5.0'); + + ksort($payloadTemplate); + $payloadArray = array_values($payloadTemplate); + + // Send to Market exactly like V1 $this->socket->sendToLocationServer('market_new_ride', [ - 'id' => (string) $insertedId, - 'start_lat' => $request->input('start_lat'), - 'start_lng' => $request->input('start_lng'), - 'price' => (string) $request->input('price'), - 'carType' => $request->input('car_type'), - 'startName' => $request->input('start_name', ''), - 'endName' => $request->input('end_name', ''), - 'distance' => (string) $request->input('distance'), - 'duration' => $request->input('duration_text', ''), - 'passengerRate' => (string) $request->input('passenger_rating', '5.0'), + 'payload' => $payloadArray ]); return response()->json([ 'status' => 'success', - // Return exactly the inserted ID as success output (V1 App relies on this) 'data' => $insertedId, - ], 200); // 200 instead of 201 to match V1 expectation + ], 200); } catch (\Exception $e) { DB::connection('primary')->rollBack(); DB::connection('ride')->rollBack(); - \Log::error('AddRide Critical Error: ' . $e->getMessage()); - return response()->json([ 'status' => 'failure', 'message' => 'Failed to add ride', @@ -145,189 +178,216 @@ class RideController extends Controller } } - - /** - * POST /v2/rides/{id}/accept - * Replaces: ride/rides/acceptRide.php - */ public function accept(Request $request, int $rideId): JsonResponse { $driverId = $request->attributes->get('_jwt_user_id'); + $status = $request->input('status', 'Apply'); // Allow dynamic status but default to Apply DB::connection('ride')->beginTransaction(); try { - // Lock the ride row to prevent race conditions $ride = Ride::lockForUpdate()->find($rideId); - if (!$ride || !in_array($ride->status, ['waiting', 'wait', 'Apply'])) { + if (!$ride || !in_array($ride->status, ['waiting', 'wait'])) { DB::connection('ride')->rollBack(); return response()->json([ 'status' => 'failure', - 'message' => 'Ride not available', - ], 409); + 'message' => 'Ride not available (Already taken)', + ], 409); // Keep 409 for conflict but failure text from V1 } - // Update ride status atomically + // Remote DB Update $ride->update([ 'driver_id' => $driverId, - 'status' => 'Applied', + 'status' => $status, + 'rideTimeStart' => now(), // V1 acceptRide does this 'DriverIsGoingToPassenger' => now(), ]); - // Update driver order - DriverOrder::where('order_id', (string) $rideId) - ->where('driver_id', $driverId) - ->update(['status' => 'accepted']); - - // Remove from waiting rides - DB::connection('primary') - ->table('waitingRides') - ->where('id', (string) $rideId) - ->update(['status' => 'Applied']); - - // Sync to primary DB ride table + // Local DB Update DB::connection('primary') ->table('ride') ->where('id', $rideId) ->update([ 'driver_id' => $driverId, - 'status' => 'Applied', + 'status' => $status, + 'rideTimeStart' => now(), ]); + // Remove from waiting rides (legacy) + DB::connection('primary') + ->table('waitingRides') + ->where('id', (string) $rideId) + ->update(['status' => $status]); + + // Driver Orders + $checkOrder = DB::connection('primary')->table('driver_orders')->where('order_id', (string)$rideId)->first(); + if ($checkOrder) { + DB::connection('primary')->table('driver_orders')->where('order_id', (string)$rideId) + ->update(['driver_id' => $driverId, 'status' => $status, 'created_at' => now()]); + } else { + DB::connection('primary')->table('driver_orders') + ->insert(['driver_id' => $driverId, 'order_id' => (string)$rideId, 'status' => $status, 'created_at' => now()]); + } + DB::connection('ride')->commit(); - // Notify passenger via FCM - $passengerToken = PassengerToken::where('passengerID', $ride->passenger_id)->first(); - if ($passengerToken) { - $decryptedToken = $this->encryption->decrypt($passengerToken->token); - $this->fcm->sendLocalizedToDevice( - $decryptedToken, - 'ride_accepted_title', - 'ride_accepted_body', - ['ride_id' => (string) $rideId, 'status' => 'Applied'], - 'ride_accepted' - ); + // Fetch Driver Info for Passenger + $driverRaw = DB::connection('primary') + ->table('driver as d') + ->leftJoin('CarRegistration as c', 'c.driverID', '=', 'd.id') + ->leftJoin('driverToken as dt', 'dt.captain_id', '=', 'd.id') + ->leftJoin('ratingDriver as r', 'r.driver_id', '=', 'd.id') + ->select( + 'd.id as driver_id', 'd.first_name', 'd.last_name', 'd.gender', 'd.phone', + 'c.make', 'c.model', 'c.car_plate', 'c.year', 'c.color', 'c.color_hex', + 'dt.token', DB::raw('ROUND(AVG(r.rating), 2) as ratingDriver') + ) + ->where('d.id', $driverId) + ->groupBy('d.id', 'd.first_name', 'd.last_name', 'd.gender', 'd.phone', 'c.make', 'c.model', 'c.car_plate', 'c.year', 'c.color', 'c.color_hex', 'dt.token') + ->first(); + + $driverInfo = []; + if ($driverRaw) { + $fieldsToDecrypt = ['first_name', 'last_name', 'gender', 'phone', 'car_plate', 'token']; + foreach ((array)$driverRaw as $key => $value) { + if (in_array($key, $fieldsToDecrypt) && !empty($value)) { + $driverInfo[$key] = $this->encryption->decrypt($value); + } else { + $driverInfo[$key] = $value; + } + } + $driverInfo['driverName'] = trim(($driverInfo['first_name'] ?? '') . ' ' . ($driverInfo['last_name'] ?? '')); + if (empty($driverInfo['ratingDriver'])) { + $driverInfo['ratingDriver'] = "5.0"; + } } // Notify passenger via socket $this->socket->notifyPassenger($ride->passenger_id, [ 'ride_id' => $rideId, - 'status' => 'Applied', + 'status' => 'accepted', // App uses 'accepted' 'driver_id' => $driverId, + 'driver_info' => $driverInfo ]); - return response()->json(['status' => 'success']); + // Notify passenger via FCM + $passengerToken = PassengerToken::where('passengerID', $ride->passenger_id)->first(); + if ($passengerToken) { + $decryptedToken = $this->encryption->decrypt($passengerToken->token); + $this->fcm->sendToDevice( + $decryptedToken, + "Ride Accepted 🚖", + "Captain " . ($driverInfo['driverName'] ?? 'Driver') . " is coming to you.", + ['ride_id' => (string) $rideId, 'driver_info' => $driverInfo], + 'Accepted Ride' + ); + } + + // Cleanup Marketplace + $this->socket->sendToLocationServer('ride_taken_event', [ + 'ride_id' => $rideId, + 'taken_by_driver_id' => $driverId + ]); + + return response()->json([ + 'status' => 'success', + 'message' => 'Ride Accepted', + 'data' => $driverInfo + ]); } catch (\Exception $e) { DB::connection('ride')->rollBack(); - return response()->json([ - 'status' => 'failure', - 'message' => 'Failed to accept ride', - ], 500); + return response()->json(['status' => 'failure', 'message' => 'Error: ' . $e->getMessage()], 500); } } - /** - * POST /v2/rides/{id}/start - * Replaces: ride/rides/start_ride.php - */ - public function start(Request $request, int $rideId): JsonResponse - { - $driverId = $request->attributes->get('_jwt_user_id'); - - $ride = Ride::where('id', $rideId) - ->where('driver_id', $driverId) - ->whereIn('status', ['Applied', 'Arrived']) - ->first(); - - if (!$ride) { - return response()->json(['status' => 'failure', 'message' => 'Ride not found or not ready'], 404); - } - - $ride->update([ - 'status' => 'Begin', - 'rideTimeStart' => now(), - ]); - - // Sync to primary - DB::connection('primary')->table('ride') - ->where('id', $rideId) - ->update(['status' => 'Begin', 'rideTimeStart' => now()]); - - // Notify passenger - $passengerToken = PassengerToken::where('passengerID', $ride->passenger_id)->first(); - if ($passengerToken) { - $this->fcm->sendLocalizedToDevice( - $this->encryption->decrypt($passengerToken->token), - 'ride_started_title', - 'ride_started_body', - ['ride_id' => (string) $rideId, 'status' => 'Begin'], - 'ride_started' - ); - } - - $this->socket->notifyPassenger($ride->passenger_id, [ - 'ride_id' => $rideId, - 'status' => 'Begin', - ]); - - return response()->json(['status' => 'success']); - } - - /** - * POST /v2/rides/{id}/arrive - * Replaces: ride/rides/arrive_ride.php - */ public function arrive(Request $request, int $rideId): JsonResponse { $driverId = $request->attributes->get('_jwt_user_id'); - $ride = Ride::where('id', $rideId) - ->where('driver_id', $driverId) - ->where('status', 'Applied') - ->first(); + $ride = Ride::where('id', $rideId)->where('driver_id', $driverId)->whereIn('status', ['Apply', 'Applied'])->first(); if (!$ride) { return response()->json(['status' => 'failure', 'message' => 'Ride not found'], 404); } - $ride->update(['status' => 'Arrived']); + $ride->update(['status' => 'arrived']); // Matching V1 lowercase - DB::connection('primary')->table('ride') - ->where('id', $rideId)->update(['status' => 'Arrived']); + DB::connection('primary')->table('ride')->where('id', $rideId)->update(['status' => 'arrived', 'updated_at' => now()]); + // Socket + $this->socket->notifyPassenger($ride->passenger_id, [ + 'status' => 'arrived', + 'ride_id' => $rideId, + 'msg' => 'السائق وصل إلى موقعك 🚖' + ]); + + // FCM $passengerToken = PassengerToken::where('passengerID', $ride->passenger_id)->first(); if ($passengerToken) { - $this->fcm->sendLocalizedToDevice( + $this->fcm->sendToDevice( $this->encryption->decrypt($passengerToken->token), - 'driver_arrived_title', - 'driver_arrived_body', - ['ride_id' => (string) $rideId, 'status' => 'Arrived'], - 'driver_arrived' + "السائق وصل 📍", + "الكابتن ينتظرك في الموقع المحدد.", + ['ride_id' => (string) $rideId], + 'Arrive Ride' ); } - return response()->json(['status' => 'success']); + return response()->json(['status' => 'success', 'message' => 'Arrival notified successfully']); + } + + public function start(Request $request, int $rideId): JsonResponse + { + $driverId = $request->attributes->get('_jwt_user_id'); + $status = 'Begin'; + + $ride = Ride::where('id', $rideId)->where('driver_id', $driverId)->whereIn('status', ['Apply', 'Applied', 'arrived', 'Arrived'])->first(); + + if (!$ride) { + return response()->json(['status' => 'failure', 'message' => 'Ride not found or not ready'], 404); + } + + $ride->update(['status' => $status, 'rideTimeStart' => now()]); + DB::connection('primary')->table('ride')->where('id', $rideId)->update(['status' => $status, 'rideTimeStart' => now()]); + + // Driver Orders + $checkOrder = DB::connection('primary')->table('driver_orders')->where('order_id', (string)$rideId)->first(); + if ($checkOrder) { + DB::connection('primary')->table('driver_orders')->where('order_id', (string)$rideId)->update(['driver_id' => $driverId, 'status' => $status, 'created_at' => now()]); + } else { + DB::connection('primary')->table('driver_orders')->insert(['driver_id' => $driverId, 'order_id' => (string)$rideId, 'status' => $status, 'created_at' => now()]); + } + + // Socket + $this->socket->notifyPassenger($ride->passenger_id, [ + 'ride_id' => $rideId, + 'status' => 'started', + 'msg' => 'بدأت الرحلة، نتمنى لك سلامة الوصول 🚀' + ]); + + // FCM + $passengerToken = PassengerToken::where('passengerID', $ride->passenger_id)->first(); + if ($passengerToken) { + $this->fcm->sendToDevice( + $this->encryption->decrypt($passengerToken->token), + "بدأت الرحلة 🏁", + "نتمنى لك رحلة آمنة ومريحة.", + ['ride_id' => (string) $rideId], + 'Trip is Begin' + ); + } + + return response()->json(['status' => 'success', 'message' => 'Ride started successfully']); } - /** - * POST /v2/rides/{id}/finish - * Replaces: ride/rides/finish_ride_updates.php - */ public function finish(Request $request, int $rideId): JsonResponse { $driverId = $request->attributes->get('_jwt_user_id'); + $price = $request->input('price', 0); + $status = 'Finished'; - $request->validate([ - 'price_for_driver' => 'required|numeric', - 'price_for_passenger' => 'required|numeric', - 'distance' => 'required|numeric', - ]); - - $ride = Ride::where('id', $rideId) - ->where('driver_id', $driverId) - ->where('status', 'Begin') - ->first(); + $ride = Ride::where('id', $rideId)->where('driver_id', $driverId)->where('status', 'Begin')->first(); if (!$ride) { return response()->json(['status' => 'failure', 'message' => 'Ride not found'], 404); @@ -336,175 +396,173 @@ class RideController extends Controller DB::connection('ride')->beginTransaction(); try { $ride->update([ - 'status' => 'finish', + 'status' => $status, 'rideTimeFinish' => now(), 'endtime' => now()->toTimeString(), - 'price_for_driver' => $request->input('price_for_driver'), - 'price_for_passenger' => $request->input('price_for_passenger'), - 'distance' => $request->input('distance'), + 'price' => $price, ]); - // Sync to primary - DB::connection('primary')->table('ride') - ->where('id', $rideId) - ->update([ - 'status' => 'finish', - 'rideTimeFinish' => now(), - 'price_for_driver' => $request->input('price_for_driver'), - 'price_for_passenger' => $request->input('price_for_passenger'), - 'distance' => $request->input('distance'), - ]); - - // Create payment record - DB::connection('primary')->table('payments')->insert([ - 'id' => uniqid('pay_'), - 'amount' => $request->input('price_for_passenger'), - 'payment_method' => $ride->paymentMethod, - 'passengerID' => $ride->passenger_id, - 'rideId' => (string) $rideId, - 'driverID' => $driverId, + DB::connection('primary')->table('ride')->where('id', $rideId)->update([ + 'status' => $status, + 'rideTimeFinish' => now(), + 'price' => $price, ]); + // Driver Orders + $checkOrder = DB::connection('primary')->table('driver_orders')->where('order_id', (string)$rideId)->first(); + if ($checkOrder) { + DB::connection('primary')->table('driver_orders')->where('order_id', (string)$rideId)->update(['driver_id' => $driverId, 'status' => $status, 'created_at' => now()]); + } else { + DB::connection('primary')->table('driver_orders')->insert(['driver_id' => $driverId, 'order_id' => (string)$rideId, 'status' => $status, 'created_at' => now()]); + } + + // Get Driver Token for LegacyList + $driverTokenRaw = DB::connection('primary')->table('driverToken')->where('captain_id', $driverId)->value('token'); + $driverTokenDecrypted = $driverTokenRaw ? $this->encryption->decrypt($driverTokenRaw) : ''; + + $legacyList = [ + (string)$driverId, + (string)$rideId, + (string)$driverTokenDecrypted, + (string)$price + ]; + DB::connection('ride')->commit(); - // Notify passenger + // Socket + $this->socket->notifyPassenger($ride->passenger_id, [ + 'ride_id' => $rideId, + 'status' => 'finished', + 'price' => $price, + 'DriverList' => $legacyList + ]); + + // FCM $passengerToken = PassengerToken::where('passengerID', $ride->passenger_id)->first(); if ($passengerToken) { - $this->fcm->sendLocalizedToDevice( + $this->fcm->sendToDevice( $this->encryption->decrypt($passengerToken->token), - 'ride_finished_title', - 'ride_finished_body', - [ - 'ride_id' => (string) $rideId, - 'status' => 'finish', - 'price' => (string) $request->input('price_for_passenger'), - ], - 'ride_finished' + "تم إنهاء الرحلة 🏁", + "المبلغ المطلوب: " . $price . " ل.س", + ['ride_id' => (string) $rideId, 'price' => (string) $price, 'DriverList' => $legacyList], + 'Driver Finish Trip' ); } - return response()->json(['status' => 'success']); + return response()->json(['status' => 'success', 'message' => 'Ride finished successfully']); } catch (\Exception $e) { DB::connection('ride')->rollBack(); - return response()->json(['status' => 'failure', 'message' => 'Failed to finish ride'], 500); + return response()->json(['status' => 'failure', 'message' => 'DB Error: ' . $e->getMessage()], 500); } } - /** - * POST /v2/rides/{id}/cancel/passenger - * Replaces: ride/rides/cancel_ride_by_passenger.php - */ public function cancelByPassenger(Request $request, int $rideId): JsonResponse { $passengerId = $request->attributes->get('_jwt_user_id'); + $reason = $request->input('reason', 'No reason specified'); - $ride = Ride::where('id', $rideId) - ->where('passenger_id', $passengerId) - ->active() - ->first(); + $ride = Ride::where('id', $rideId)->where('passenger_id', $passengerId)->active()->first(); if (!$ride) { return response()->json(['status' => 'failure', 'message' => 'Ride not found'], 404); } - $ride->update(['status' => 'CancelByPassenger']); + if ($ride->status === 'Begin') { + return response()->json(['status' => 'failure', 'message' => 'Cannot cancel started ride'], 400); + } - DB::connection('primary')->table('ride') - ->where('id', $rideId)->update(['status' => 'CancelByPassenger']); + $driverId = $ride->driver_id; + + $ride->update(['status' => 'cancelled_by_passenger']); + DB::connection('primary')->table('ride')->where('id', $rideId)->update(['status' => 'cancelled_by_passenger', 'updated_at' => now()]); + DB::connection('primary')->table('waitingRides')->where('id', (string) $rideId)->update(['status' => 'cancelled_by_passenger']); - DB::connection('primary')->table('waitingRides') - ->where('id', (string) $rideId)->update(['status' => 'CancelByPassenger']); + // Driver Orders + if ($driverId !== 'none' && $driverId != 0) { + DB::connection('primary')->table('driver_orders')->where('order_id', (string)$rideId)->where('driver_id', $driverId)->update(['status' => 'cancelled_by_passenger', 'notes' => $reason]); + } // Log cancellation DB::connection('ride')->table('canecl')->insert([ - 'driverID' => $ride->driver_id ?? 'none', + 'driverID' => $driverId ?? 'none', 'passengerID' => $passengerId, 'rideID' => (string) $rideId, - 'note' => $request->input('reason', 'No reason specified'), + 'note' => $reason, ]); - // Notify driver if assigned - if ($ride->driver_id !== 'none') { - $driverToken = DriverToken::where('captain_id', $ride->driver_id)->first(); + if ($driverId !== 'none' && $driverId != 0) { + // Socket + $this->socket->sendToLocationServer('cancel_ride', [ + 'driver_id' => $driverId, + 'ride_id' => $rideId, + 'reason' => $reason + ]); + + // FCM + $driverToken = DriverToken::where('captain_id', $driverId)->first(); if ($driverToken) { - $this->fcm->sendLocalizedToDevice( + $this->fcm->sendToDevice( $this->encryption->decrypt($driverToken->token), - 'ride_cancelled_title', - 'ride_cancelled_body_passenger', - ['ride_id' => (string) $rideId, 'status' => 'CancelByPassenger'], - 'ride_cancelled' + "إلغاء الرحلة 🚫", + "قام الراكب بإلغاء الرحلة: $reason", + ['ride_id' => (string) $rideId, 'reason' => $reason], + 'Cancel Trip' ); } - - $this->socket->sendToLocationServer('cancel_ride', [ - 'driver_id' => $ride->driver_id, - 'ride_id' => $rideId, - ]); } - return response()->json(['status' => 'success']); + return response()->json(['status' => 'success', 'message' => 'Ride cancelled successfully']); } - /** - * POST /v2/rides/{id}/cancel/driver - * Replaces: ride/rides/cancel_ride_by_driver.php - */ public function cancelByDriver(Request $request, int $rideId): JsonResponse { $driverId = $request->attributes->get('_jwt_user_id'); + $reason = $request->input('reason', 'No reason specified'); - $ride = Ride::where('id', $rideId) - ->where('driver_id', $driverId) - ->active() - ->first(); + $ride = Ride::where('id', $rideId)->where('driver_id', $driverId)->active()->first(); if (!$ride) { return response()->json(['status' => 'failure', 'message' => 'Ride not found'], 404); } - $ride->update(['status' => 'CancelByDriver', 'driver_id' => 'none']); + $ride->update(['status' => 'cancelled_by_driver', 'driver_id' => 'none']); + DB::connection('primary')->table('ride')->where('id', $rideId)->update(['status' => 'cancelled_by_driver']); + DB::connection('primary')->table('waitingRides')->where('id', (string) $rideId)->update(['status' => 'waiting']); - DB::connection('primary')->table('ride') - ->where('id', $rideId)->update(['status' => 'CancelByDriver']); - - // Re-add to waiting rides for re-search - DB::connection('primary')->table('waitingRides') - ->where('id', (string) $rideId)->update(['status' => 'waiting']); + // Driver Orders + DB::connection('primary')->table('driver_orders')->where('order_id', (string)$rideId)->where('driver_id', $driverId)->update(['status' => 'cancelled_by_driver', 'notes' => $reason]); // Log cancellation DB::connection('ride')->table('canecl')->insert([ 'driverID' => $driverId, 'passengerID' => $ride->passenger_id, 'rideID' => (string) $rideId, - 'note' => $request->input('reason', 'No reason specified'), + 'note' => $reason, ]); - // Notify passenger via FCM + // Socket to passenger + $this->socket->notifyPassenger($ride->passenger_id, [ + 'ride_id' => $rideId, + 'status' => 'cancelled_by_driver', + 'reason' => $reason + ]); + + // FCM to passenger $passengerToken = PassengerToken::where('passengerID', $ride->passenger_id)->first(); if ($passengerToken) { - $this->fcm->sendLocalizedToDevice( + $this->fcm->sendToDevice( $this->encryption->decrypt($passengerToken->token), - 'ride_cancelled_title', - 'ride_cancelled_body_driver', - ['ride_id' => (string) $rideId, 'status' => 'CancelByDriver'], - 'ride_cancelled' + "إلغاء الرحلة 🚫", + "قام السائق بإلغاء الرحلة: $reason", + ['ride_id' => (string) $rideId, 'reason' => $reason], + 'Cancel Trip' ); } - // Notify passenger via Socket (Faster than FCM) - $this->socket->notifyPassenger($ride->passenger_id, [ - 'ride_id' => $rideId, - 'status' => 'CancelByDriver', - ]); - - return response()->json(['status' => 'success']); + return response()->json(['status' => 'success', 'message' => 'Ride cancelled successfully']); } - /** - * GET /v2/rides/{id} - * Replaces: ride/rides/getRideOrderID.php - */ public function show(Request $request, int $rideId): JsonResponse { $userId = $request->attributes->get('_jwt_user_id'); @@ -521,10 +579,6 @@ class RideController extends Controller return response()->json(['status' => 'success', 'data' => $ride]); } - /** - * GET /v2/rides/active - * Replaces: ride/rides/getRideStatusFromStartApp.php - */ public function active(Request $request): JsonResponse { $userId = $request->attributes->get('_jwt_user_id'); @@ -545,10 +599,6 @@ class RideController extends Controller ]); } - /** - * GET /v2/rides - * Replaces: ride/rides/get.php - */ public function index(Request $request): JsonResponse { $userId = $request->attributes->get('_jwt_user_id');