Update: 2026-08-07 01:06:09
This commit is contained in:
@@ -67,6 +67,22 @@ try {
|
||||
// نوع السيارة تحت أي من الاسمين
|
||||
$rideCarType = (string) ($rideRow['carType'] ?? $rideRow['car_type'] ?? 'Speed');
|
||||
|
||||
// مدخلا التعويض عاشا في Redis طوال الرحلة ولم يلمسا MySQL. نقرأهما
|
||||
// هنا قراءةً واحدة يشترك فيها الحساب (القسم ٤٫١) والتوثيق (القسم ٣).
|
||||
$approachKm = 0.0;
|
||||
$arrivedTs = 0;
|
||||
try {
|
||||
if (isset($redisLocation) && $redisLocation) {
|
||||
$state = $redisLocation->hMGet("ride:$rideId:state",
|
||||
['pickup_approach_km', 'driver_arrived_at']) ?: [];
|
||||
$approachKm = (float) ($state['pickup_approach_km'] ?? 0);
|
||||
$arrivedTs = (int) ($state['driver_arrived_at'] ?? 0);
|
||||
}
|
||||
} catch (Throwable $eState) {
|
||||
error_log("[cancel_ride_by_driver] تعذّرت قراءة حالة الرحلة من Redis: "
|
||||
. $eState->getMessage());
|
||||
}
|
||||
|
||||
if ($assignedDriver === false) {
|
||||
$con->rollBack();
|
||||
jsonError("Ride not found");
|
||||
@@ -118,15 +134,32 @@ try {
|
||||
|
||||
// تثبيت الإيقاف على الخادم. كان يُكتب في تخزين تطبيق السائق وحده
|
||||
// (statusDriverLocation='blocked')، فيُفكّ بمسح البيانات أو إعادة
|
||||
// التثبيت. الآن acceptRide.php يرفض القبول ما دام blockedUntil مستقبلياً.
|
||||
// GREATEST يمنع إلغاءً جديداً من تقصير إيقاف سارٍ أطول.
|
||||
// التثبيت. الآن acceptRide.php يرفض القبول ما دام المفتاح حياً.
|
||||
//
|
||||
// Redis هو مسار الفحص (TTL ينهي الإيقاف تلقائياً بلا كرون تنظيف)،
|
||||
// وMySQL سجل دائم للمراجعة الإدارية لا يُقرأ في المسار الحار.
|
||||
// هذه الكتابة تحدث في الإلغاء الثالث فقط — لا على كل رحلة.
|
||||
try {
|
||||
if (isset($redisLocation) && $redisLocation) {
|
||||
$blockKey = "driver:$driverId:blocked";
|
||||
$remaining = $redisLocation->ttl($blockKey);
|
||||
// لا نُقصّر إيقافاً سارياً أطول بإلغاء جديد.
|
||||
if ($remaining < 4 * 3600) {
|
||||
$redisLocation->setex($blockKey, 4 * 3600, $blockUntil);
|
||||
}
|
||||
}
|
||||
} catch (Throwable $eRedisBlock) {
|
||||
error_log("[cancel_ride_by_driver] تعذّر تثبيت الإيقاف في Redis: "
|
||||
. $eRedisBlock->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$con->prepare("UPDATE driver
|
||||
SET blockedUntil = GREATEST(COALESCE(blockedUntil, ?), ?)
|
||||
WHERE id = ?")
|
||||
->execute([$blockUntil, $blockUntil, $driverId]);
|
||||
} catch (PDOException $eBlock) {
|
||||
error_log("[cancel_ride_by_driver] تعذّر تثبيت الإيقاف (شغّل"
|
||||
error_log("[cancel_ride_by_driver] تعذّر تسجيل الإيقاف في MySQL (شغّل"
|
||||
. " migrations/2026_08_07_driver_cancel_compensation.sql): " . $eBlock->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -134,14 +167,35 @@ try {
|
||||
// ---------------------------------------------------------
|
||||
// 3. تحديث حالة الرحلة في جدول ride
|
||||
// ---------------------------------------------------------
|
||||
$sqlRide = "UPDATE ride SET status = ?, driver_id = 0 WHERE id = ?";
|
||||
|
||||
// التوثيق النهائي: بيانات التعويض التي عاشت في Redis طوال الرحلة
|
||||
// تُثبَّت هنا داخل نفس جملة تحديث الحالة — لا كتابة إضافية.
|
||||
// تُقرأ من Redis قبل هذه النقطة (القسم ٤٫١ يقرأها للحساب)، لذا نقرأها
|
||||
// مرة واحدة هنا ونمرّرها للطرفين.
|
||||
$stampArrivedAt = $arrivedTs > 0 ? date('Y-m-d H:i:s', $arrivedTs) : null;
|
||||
|
||||
$sqlRide = "UPDATE ride SET status = ?, driver_id = 0,
|
||||
pickupApproachKm = ?, driverArrivedAt = ?
|
||||
WHERE id = ?";
|
||||
$sqlRideLegacy = "UPDATE ride SET status = ?, driver_id = 0 WHERE id = ?";
|
||||
$rideParams = [$statusText, $approachKm, $stampArrivedAt, $rideId];
|
||||
|
||||
// Local DB
|
||||
$con->prepare($sqlRide)->execute([$statusText, $rideId]);
|
||||
|
||||
try {
|
||||
$con->prepare($sqlRide)->execute($rideParams);
|
||||
} catch (PDOException $eCols) {
|
||||
// أعمدة التعويض غير مُرحَّلة بعد — الإلغاء نفسه لا يتوقف.
|
||||
error_log("[cancel_ride_by_driver] أعمدة التعويض غير موجودة (شغّل"
|
||||
. " migrations/2026_08_07_driver_cancel_compensation.sql): " . $eCols->getMessage());
|
||||
$con->prepare($sqlRideLegacy)->execute([$statusText, $rideId]);
|
||||
}
|
||||
|
||||
// Remote DB (إن وجد)
|
||||
if (isset($con_ride)) {
|
||||
$con_ride->prepare($sqlRide)->execute([$statusText, $rideId]);
|
||||
try {
|
||||
$con_ride->prepare($sqlRide)->execute($rideParams);
|
||||
} catch (PDOException $eCols) {
|
||||
$con_ride->prepare($sqlRideLegacy)->execute([$statusText, $rideId]);
|
||||
}
|
||||
}
|
||||
|
||||
// 🆕 تصفير التتابع لأن السائق ألغى الرحلة
|
||||
@@ -180,21 +234,20 @@ try {
|
||||
$compensationCap = (float) ($kazan['cancelCompensationCap'] ?? 0);
|
||||
$minWaitMinutes = (int) ($kazan['cancelMinWaitMinutes'] ?? 5);
|
||||
|
||||
$compensation = 0.0;
|
||||
// $approachKm و$arrivedTs قُرئا من Redis قراءةً واحدة في القسم صفر.
|
||||
$compensation = 0.0;
|
||||
$waitedMinutes = 0;
|
||||
$approachKm = (float) ($rideRow['pickupApproachKm'] ?? 0);
|
||||
$arrivedAt = $rideRow['driverArrivedAt'] ?? null;
|
||||
|
||||
if ($compensationCap <= 0) {
|
||||
// التعويض معطّل لهذه الدولة — الافتراضي حتى تضبطه الإدارة.
|
||||
error_log("[cancel_ride_by_driver] التعويض معطّل (cancelCompensationCap=0)"
|
||||
. " ride=$rideId");
|
||||
} elseif (empty($arrivedAt)) {
|
||||
// لا ختم وصول ⇒ السائق ألغى قبل أن يصل. لا انتظار، فلا تعويض.
|
||||
error_log("[cancel_ride_by_driver] إلغاء قبل تسجيل الوصول — بلا تعويض"
|
||||
} elseif ($arrivedTs <= 0) {
|
||||
// لا ختم وصول ⇒ السائق ألغى قبل أن يصل، أو تعذّر إثبات وصوله.
|
||||
error_log("[cancel_ride_by_driver] إلغاء بلا ختم وصول — بلا تعويض"
|
||||
. " ride=$rideId driver=$driverId");
|
||||
} else {
|
||||
$waitedMinutes = (int) floor((time() - strtotime($arrivedAt)) / 60);
|
||||
$waitedMinutes = (int) floor((time() - $arrivedTs) / 60);
|
||||
|
||||
if ($waitedMinutes < $minWaitMinutes) {
|
||||
error_log("[cancel_ride_by_driver] انتظار $waitedMinutes د < الحد"
|
||||
|
||||
Reference in New Issue
Block a user