306 lines
10 KiB
PHP
306 lines
10 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../../connect.php';
|
|
|
|
$distance = (float) filterRequest("distance");
|
|
$duration = (float) filterRequest("durationToRide");
|
|
$promo_code = filterRequest("promo_code");
|
|
$passenger_id = filterRequest("passenger_id");
|
|
$promo_code_id = filterRequest("promo_code_id") ? filterRequest("promo_code_id") : 0;
|
|
$country = filterRequest("country");
|
|
|
|
$startNameAddress = filterRequest("startNameAddress");
|
|
$endNameAddress = filterRequest("endNameAddress");
|
|
$destLat = (float) filterRequest("destLat");
|
|
$destLng = (float) filterRequest("destLng");
|
|
$passengerLat = (float) filterRequest("passengerLat");
|
|
$passengerLng = (float) filterRequest("passengerLng");
|
|
$activeMenuWaypointCount = (int) filterRequest("activeMenuWaypointCount");
|
|
|
|
if (!$country) {
|
|
echo json_encode(["status" => "failure", "message" => "Country parameter is required"]);
|
|
exit;
|
|
}
|
|
|
|
$prices = [];
|
|
$pricesRaw = [];
|
|
|
|
$categories = [
|
|
'totalPassengerSpeed' => 'Speed',
|
|
'totalPassengerBalash' => 'Awfar Car',
|
|
'totalPassengerComfort' => 'Comfort',
|
|
'totalPassengerElectric' => 'Electric',
|
|
'totalPassengerLady' => 'Lady',
|
|
'totalPassengerScooter' => 'Delivery',
|
|
'totalPassengerVan' => 'Van',
|
|
'totalPassengerRayehGai' => 'Speed',
|
|
'totalPassengerRayehGaiComfort' => 'Comfort',
|
|
'totalPassengerRayehGaiBalash' => 'Awfar Car',
|
|
];
|
|
|
|
// Common variables
|
|
date_default_timezone_set('Asia/Damascus');
|
|
$currentTime = new DateTime();
|
|
$hour = (int)$currentTime->format('H');
|
|
|
|
switch ($country) {
|
|
case 'Syria':
|
|
$minFare = 150.0;
|
|
break;
|
|
case 'Egypt':
|
|
$minFare = 20.0;
|
|
break;
|
|
case 'Jordan':
|
|
$minFare = 1.0;
|
|
break;
|
|
default:
|
|
$minFare = 0.0;
|
|
break;
|
|
}
|
|
|
|
// Fetch kazan from DB for the specified country
|
|
$sql = "SELECT * FROM `kazan` WHERE country = :country LIMIT 1";
|
|
$stmt = $con->prepare($sql);
|
|
$stmt->execute([':country' => $country]);
|
|
$kazanRow = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$kazanRow) {
|
|
echo json_encode(["status" => "failure", "message" => "No pricing available for this country"]);
|
|
exit;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Helper Functions for Countries
|
|
// ----------------------------------------------------------------------
|
|
|
|
function getPerKmRate($carType, $kazanRow) {
|
|
$rateColumns = [
|
|
'Comfort' => 'comfortPrice',
|
|
'Speed' => 'speedPrice',
|
|
'Lady' => 'ladyPrice',
|
|
'Electric' => 'electricPrice',
|
|
'Van' => 'vanPrice',
|
|
'Delivery' => 'deliveryPrice',
|
|
'Mishwar Vip' => 'mishwarVipPrice',
|
|
'Fixed Price' => 'fixedPrice',
|
|
'Awfar Car' => 'awfarPrice',
|
|
];
|
|
|
|
$column = $rateColumns[$carType] ?? 'speedPrice';
|
|
$rate = floatval($kazanRow[$column] ?? 0);
|
|
|
|
if ($rate <= 0) {
|
|
$oldColumnMap = [
|
|
'Lady' => 'familyPrice',
|
|
'Mishwar Vip' => 'freePrice',
|
|
'Electric' => 'naturePrice',
|
|
'Van' => 'heavyPrice',
|
|
];
|
|
$oldColumn = $oldColumnMap[$carType] ?? null;
|
|
if ($oldColumn && isset($kazanRow[$oldColumn])) {
|
|
$rate = floatval($kazanRow[$oldColumn]);
|
|
}
|
|
}
|
|
|
|
if ($rate <= 0) {
|
|
$rate = floatval($kazanRow['speedPrice'] ?? 36);
|
|
}
|
|
|
|
return $rate;
|
|
}
|
|
|
|
function calculateDynamicPrice($country, $minFare, $distance, $duration, $kazanRow, $startNameAddress, $endNameAddress, $destLat, $destLng, $passengerLat, $passengerLng, $carType = 'Speed') {
|
|
$naturePrice = (float) ($kazanRow['naturePrice'] ?? 0);
|
|
$heavyPrice = (float) ($kazanRow['heavyPrice'] ?? 0);
|
|
$latePrice = (float) ($kazanRow['latePrice'] ?? 0);
|
|
$kazanPercent = (float) ($kazanRow['kazan'] ?? 10);
|
|
|
|
// === General Settings ===
|
|
$minBillableKm = 0.2;
|
|
$airportAddon = 0.0;
|
|
$damascusAirportBoundAddon = 0.0;
|
|
|
|
switch ($country) {
|
|
case 'Egypt':
|
|
$airportAddon = 35.0;
|
|
break;
|
|
case 'Jordan':
|
|
$airportAddon = 5.0;
|
|
break;
|
|
default: // Syria
|
|
$airportAddon = 200.0;
|
|
$damascusAirportBoundAddon = 1400.0;
|
|
break;
|
|
}
|
|
|
|
$longSpeedThresholdKm = 40.0;
|
|
$longSpeedPerKm = 26.0;
|
|
|
|
$mediumDistThresholdKm = 25.0;
|
|
$longDistThresholdKm = 35.0;
|
|
$longTripPerMin = 6.0;
|
|
$minuteCapMedium = 60;
|
|
$minuteCapLong = 80;
|
|
$freeMinutesLong = 10;
|
|
|
|
$extraReduction100 = 0.07;
|
|
$maxReductionCap = 0.35;
|
|
|
|
$totalMinutes = floor($duration / 60);
|
|
|
|
$airportCtx = (stripos($startNameAddress, 'airport') !== false || stripos($startNameAddress, 'مطار') !== false || stripos($endNameAddress, 'airport') !== false || stripos($endNameAddress, 'مطار') !== false);
|
|
$clubCtx = (stripos($startNameAddress, 'club') !== false || stripos($startNameAddress, 'ديسكو') !== false || stripos($endNameAddress, 'club') !== false || stripos($endNameAddress, 'ديسكو') !== false);
|
|
|
|
$northLat = 33.415313;
|
|
$southLat = 33.400265;
|
|
$eastLng = 36.531505;
|
|
$westLng = 36.499687;
|
|
$damascusAirportBoundCtx = ($destLat <= $northLat && $destLat >= $southLat && $destLng <= $eastLng && $destLng >= $westLng);
|
|
$isInDamascusAirportBoundCtx = ($passengerLat <= $northLat && $passengerLat >= $southLat && $passengerLng <= $eastLng && $passengerLng >= $westLng);
|
|
|
|
$billableDistance = ($distance < $minBillableKm) ? $minBillableKm : $distance;
|
|
$isLongSpeed = $billableDistance > $longSpeedThresholdKm;
|
|
|
|
$perKmSpeedBaseFromServer = getPerKmRate($carType, $kazanRow);
|
|
$perKmSpeed = $isLongSpeed ? $longSpeedPerKm : $perKmSpeedBaseFromServer;
|
|
|
|
$reductionPct40 = 0.0;
|
|
if ($perKmSpeedBaseFromServer > 0) {
|
|
$r = 1.0 - ($longSpeedPerKm / $perKmSpeedBaseFromServer);
|
|
$reductionPct40 = max(0.0, min($maxReductionCap, $r));
|
|
}
|
|
$reductionPct100 = max(0.0, min($maxReductionCap, $reductionPct40 + $extraReduction100));
|
|
|
|
$distanceReduction = 0.0;
|
|
if ($billableDistance > 100.0) {
|
|
$distanceReduction = $reductionPct100;
|
|
} else if ($billableDistance > 40.0) {
|
|
$distanceReduction = $reductionPct40;
|
|
}
|
|
|
|
date_default_timezone_set('Asia/Damascus');
|
|
$hour = (int)date('H');
|
|
$effectivePerMin = $naturePrice;
|
|
if ($hour >= 21 || $hour < 1) {
|
|
$effectivePerMin = $latePrice;
|
|
} else if ($hour >= 1 && $hour < 5) {
|
|
$effectivePerMin = $clubCtx ? ($latePrice * 2) : $latePrice;
|
|
} else if ($hour >= 14 && $hour <= 17) {
|
|
$effectivePerMin = $heavyPrice;
|
|
}
|
|
|
|
$billableMinutes = $totalMinutes;
|
|
if ($billableDistance > $longDistThresholdKm) {
|
|
$effectivePerMin = $longTripPerMin;
|
|
$capped = ($billableMinutes > $minuteCapLong) ? $minuteCapLong : $billableMinutes;
|
|
$billableMinutes = max(0, $capped - $freeMinutesLong);
|
|
} else if ($billableDistance > $mediumDistThresholdKm) {
|
|
$effectivePerMin = $longTripPerMin;
|
|
$billableMinutes = ($billableMinutes > $minuteCapMedium) ? $minuteCapMedium : $billableMinutes;
|
|
}
|
|
|
|
$fare = $billableDistance * $perKmSpeed;
|
|
$fare += $billableMinutes * $effectivePerMin;
|
|
if ($airportCtx) $fare += $airportAddon;
|
|
if ($damascusAirportBoundCtx || $isInDamascusAirportBoundCtx) {
|
|
$fare += $damascusAirportBoundAddon;
|
|
}
|
|
|
|
$price = max($fare, $minFare);
|
|
|
|
// Apply kazan (e.g. 11%)
|
|
$withCommission = ceil($price * (1 + $kazanPercent / 100));
|
|
$kazan = $withCommission - $price;
|
|
$price_for_driver = $price;
|
|
|
|
return [
|
|
'price' => $price,
|
|
'price_for_driver' => $price_for_driver,
|
|
'withCommission' => $withCommission,
|
|
'kazan' => $kazan,
|
|
'isNightFare' => false
|
|
];
|
|
}
|
|
|
|
// 2. Validate Promo Code
|
|
$discount = 0;
|
|
if (!empty($promo_code)) {
|
|
$sqlPromo = "SELECT amount FROM `promos`
|
|
WHERE promo_code = :promo_code
|
|
AND (passengerID = :passenger_id OR passengerID LIKE '%all%')
|
|
AND validity_start_date <= CURDATE()
|
|
AND validity_end_date >= CURDATE()";
|
|
$stmtPromo = $con->prepare($sqlPromo);
|
|
$stmtPromo->execute([
|
|
':promo_code' => $promo_code,
|
|
':passenger_id' => $passenger_id
|
|
]);
|
|
if ($stmtPromo->rowCount() > 0) {
|
|
$promoData = $stmtPromo->fetch(PDO::FETCH_ASSOC);
|
|
$discount = (float) $promoData['amount'];
|
|
}
|
|
}
|
|
|
|
// 3. Fetch Passenger Wallet (Negative Balance / Debt)
|
|
$negativeBalance = 0;
|
|
if (!empty($passenger_id)) {
|
|
try {
|
|
$redis = new Redis();
|
|
$redis->connect('127.0.0.1', 6379);
|
|
$redisKey = "passenger_debt_" . $passenger_id;
|
|
$redisDebt = $redis->get($redisKey);
|
|
|
|
if ($redisDebt !== false) {
|
|
$negativeBalance = (float) $redisDebt;
|
|
}
|
|
} catch (Exception $e) {
|
|
$negativeBalance = 0;
|
|
}
|
|
}
|
|
|
|
// Calculate prices for all categories
|
|
foreach ($categories as $key => $carType) {
|
|
$result = calculateDynamicPrice($country, $minFare, $distance, $duration, $kazanRow, $startNameAddress, $endNameAddress, $destLat, $destLng, $passengerLat, $passengerLng, $carType);
|
|
$withCommission = $result['withCommission'];
|
|
$price_for_driver = $result['price_for_driver'];
|
|
|
|
// Apply discount
|
|
if ($discount > 0 && $discount <= 100) {
|
|
$finalPrice = max(0, $withCommission - ($withCommission * ($discount / 100)));
|
|
} else {
|
|
$finalPrice = max(0, $withCommission - $discount);
|
|
}
|
|
|
|
// Add negative balance
|
|
$finalPrice += $negativeBalance;
|
|
|
|
$prices[$key] = $finalPrice;
|
|
|
|
// For the token, we map the clean database carType to the final price and driver price
|
|
$pricesRaw[$carType] = [
|
|
'price' => $finalPrice,
|
|
'driver_price' => $price_for_driver
|
|
];
|
|
}
|
|
|
|
// 4. Generate Cryptographically Signed Token
|
|
$priceToken = "";
|
|
if (isset($encryptionHelper)) {
|
|
$tokenPayload = [
|
|
'passenger_id' => $passenger_id,
|
|
'start_location' => $passengerLat . ',' . $passengerLng,
|
|
'end_location' => $destLat . ',' . $destLng,
|
|
'expires' => time() + 180, // Valid for 3 minutes
|
|
'prices' => $pricesRaw
|
|
];
|
|
$priceToken = $encryptionHelper->encryptData(json_encode($tokenPayload));
|
|
}
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'data' => $prices,
|
|
'price_token' => $priceToken,
|
|
'applied_discount' => $discount,
|
|
'added_negative_balance' => $negativeBalance
|
|
]);
|
|
?>
|