Files
Siro/backend/ride/scheduled/add.php
T

120 lines
5.3 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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);
}