Update: 2026-08-07 05:56:50
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
// ============================================================
|
||||
// ride/scheduled/add.php — إنشاء حجز مسبق
|
||||
//
|
||||
// لا يُنشئ رحلة. يسجّل نيّة سفر في وقت محدد، ويتولّى الكرون
|
||||
// (bot/cron_scheduled_rides.php) تحويلها لرحلة فعلية قبل الموعد بهامش.
|
||||
//
|
||||
// الفصل مقصود: رحلة تُنشأ الآن لموعد بعد ست ساعات ستدور في السوق ست
|
||||
// ساعات، وتُربك الإسناد والتسعير والخريطة الحرارية.
|
||||
// ============================================================
|
||||
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
// الهوية من الـJWT لا من الطلب.
|
||||
$passengerId = $user_id ?? '';
|
||||
if (empty($passengerId)) {
|
||||
jsonError('Unauthorized', 401);
|
||||
}
|
||||
|
||||
$startLocation = filterRequest('start_location');
|
||||
$endLocation = filterRequest('end_location');
|
||||
$startName = filterRequest('start_name');
|
||||
$endName = filterRequest('end_name');
|
||||
$carType = filterRequest('car_type') ?: 'Speed';
|
||||
$scheduledAt = filterRequest('scheduled_at'); // 'YYYY-MM-DD HH:MM:SS'
|
||||
$distance = (float) (filterRequest('distance', 'float') ?: 0);
|
||||
$duration = (int) (filterRequest('duration', 'int') ?: 0);
|
||||
$estimated = (float) (filterRequest('estimated_price', 'float') ?: 0);
|
||||
$note = filterRequest('note');
|
||||
|
||||
if (!$startLocation || !$endLocation || !$scheduledAt) {
|
||||
jsonError('start_location, end_location and scheduled_at are required');
|
||||
}
|
||||
|
||||
// قائمة بيضاء لنوع السيارة — نفس منطق findBestDrivers.
|
||||
$allowedCarTypes = ['Comfort', 'Mishwar Vip', 'Scooter', 'Pink Bike', 'Electric',
|
||||
'Lady', 'Van', 'Awfar Car', 'Fixed Price', 'Speed', 'Rayeh Gai'];
|
||||
if (!in_array($carType, $allowedCarTypes, true)) {
|
||||
$carType = 'Speed';
|
||||
}
|
||||
|
||||
$ts = strtotime($scheduledAt);
|
||||
if ($ts === false) {
|
||||
jsonError('Invalid scheduled_at format');
|
||||
}
|
||||
|
||||
// ── حدود زمنية ──────────────────────────────────────────────
|
||||
// الحد الأدنى: حجز لبعد عشر دقائق لا معنى له — اطلب رحلة عادية.
|
||||
// الحد الأعلى: يومان. قرار المالك — حجز لبعد أسبوعين كلام فاضٍ: الراكب
|
||||
// ينساه، وخطته تتغيّر، ويحتل مكاناً في التوقّع بلا قيمة. اليوم والغد
|
||||
// وبعده هي المدى الذي يلتزم به الناس فعلاً.
|
||||
const SCHEDULE_MIN_LEAD_MINUTES = 30;
|
||||
const SCHEDULE_MAX_DAYS_AHEAD = 2;
|
||||
|
||||
$minutesAhead = ($ts - time()) / 60;
|
||||
|
||||
if ($minutesAhead < SCHEDULE_MIN_LEAD_MINUTES) {
|
||||
jsonError('Scheduled time must be at least ' . SCHEDULE_MIN_LEAD_MINUTES . ' minutes from now');
|
||||
}
|
||||
if ($minutesAhead > SCHEDULE_MAX_DAYS_AHEAD * 24 * 60) {
|
||||
jsonError('يمكنك الحجز حتى ' . SCHEDULE_MAX_DAYS_AHEAD . ' يومين مقدماً فقط');
|
||||
}
|
||||
|
||||
// ── هامش البحث عن سائق ──────────────────────────────────────
|
||||
// نشتقّه من المسافة بدل أن نسأل الراكب: رحلة مطار بعيدة تحتاج وقتاً
|
||||
// أطول لإيجاد سائق وللوصول إليه من رحلة داخل الحي.
|
||||
$leadMinutes = 15;
|
||||
if ($distance > 25) {
|
||||
$leadMinutes = 40;
|
||||
} elseif ($distance > 10) {
|
||||
$leadMinutes = 25;
|
||||
}
|
||||
|
||||
try {
|
||||
// ── منع الحجز المزدوج ───────────────────────────────────
|
||||
// راكب له حجزان في نفس النصف ساعة غالباً ضغط مرتين. الحجز المكرر
|
||||
// ينتج رحلتين حقيقيتين ويُحمّله رسمَي إلغاء.
|
||||
$dup = $con->prepare("
|
||||
SELECT id FROM scheduled_rides
|
||||
WHERE passenger_id = ? AND status = 'scheduled'
|
||||
AND ABS(TIMESTAMPDIFF(MINUTE, scheduled_at, ?)) < 30
|
||||
LIMIT 1
|
||||
");
|
||||
$dup->execute([$passengerId, date('Y-m-d H:i:s', $ts)]);
|
||||
if ($dup->fetchColumn()) {
|
||||
jsonError('You already have a booking around this time', 409);
|
||||
}
|
||||
|
||||
$ins = $con->prepare("
|
||||
INSERT INTO scheduled_rides
|
||||
(passenger_id, start_location, end_location, start_name, end_name,
|
||||
car_type, distance, duration, estimated_price,
|
||||
scheduled_at, lead_minutes, note)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
");
|
||||
$ins->execute([
|
||||
$passengerId, $startLocation, $endLocation, $startName, $endName,
|
||||
$carType, $distance, $duration, $estimated,
|
||||
date('Y-m-d H:i:s', $ts), $leadMinutes,
|
||||
$note ? mb_substr($note, 0, 255) : null,
|
||||
]);
|
||||
|
||||
$id = (int) $con->lastInsertId();
|
||||
|
||||
error_log("[scheduled] حجز #$id للراكب $passengerId في "
|
||||
. date('Y-m-d H:i', $ts) . " (هامش {$leadMinutes}د)");
|
||||
|
||||
jsonSuccess([
|
||||
'id' => $id,
|
||||
'scheduled_at' => date('Y-m-d H:i:s', $ts),
|
||||
'lead_minutes' => $leadMinutes,
|
||||
// نصرّح بأن السعر تقديري: الراكب يجب أن يعرف أن الرقم قد يتغيّر.
|
||||
'price_is_estimate' => true,
|
||||
], 'Ride scheduled');
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log('[scheduled/add] ' . $e->getMessage());
|
||||
jsonError('DB Error', 500);
|
||||
}
|
||||
Reference in New Issue
Block a user