Sync Ride Lifecycle with V1: Added legacy array payload, DriverList, and driver_orders tracking

This commit is contained in:
Hamza-Ayed
2026-04-25 00:31:08 +03:00
parent 540c5cc7ab
commit fccd758e93

View File

@@ -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');