Files
Siro/backend/ride/pricing/get.php
2026-06-11 18:22:59 +03:00

270 lines
9.5 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;
}
$price = 0.0;
$price_for_driver = 0.0;
$withCommission = 0.0;
$kazan = 0.0;
$isNightFare = false;
// 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;
}
$result = calculateDynamicPrice($country, $minFare, $distance, $duration, $kazanRow, $startNameAddress, $endNameAddress, $destLat, $destLng, $passengerLat, $passengerLng);
$price = $result['price'];
$price_for_driver = $result['price_for_driver'];
$withCommission = $result['withCommission'];
$kazan = $result['kazan'];
$isNightFare = $result['isNightFare'];
// ----------------------------------------------------------------------
// Helper Functions for Countries
// ----------------------------------------------------------------------
function calculateDynamicPrice($country, $minFare, $distance, $duration, $kazanRow, $startNameAddress, $endNameAddress, $destLat, $destLng, $passengerLat, $passengerLng) {
$comfortPrice = (float) $kazanRow['comfortPrice'];
$speedPrice = (float) $kazanRow['speedPrice'];
$familyPrice = (float) $kazanRow['familyPrice'];
$deliveryPrice = (float) $kazanRow['deliveryPrice'];
$naturePrice = (float) $kazanRow['naturePrice'];
$heavyPrice = (float) $kazanRow['heavyPrice'];
$latePrice = (float) $kazanRow['latePrice'];
$kazanPercent = (float) $kazanRow['kazan'];
// === 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 = $speedPrice;
$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)
// Using Redis for ultra-fast reads, with a fallback to the Payment Server API.
$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;
} else {
// Fallback: If not in Redis, call the Payment Server Endpoint
// TODO: Replace with the actual Payment Server Endpoint URL and API Key
/*
$paymentApiUrl = "https://payment.siroapp.com/api/get_debt?passenger_id=" . urlencode($passenger_id);
$options = [
"http" => [
"header" => "Authorization: Bearer YOUR_API_KEY\r\n"
]
];
$context = stream_context_create($options);
$response = file_get_contents($paymentApiUrl, false, $context);
if ($response !== false) {
$data = json_decode($response, true);
if (isset($data['debt'])) {
$negativeBalance = (float) $data['debt'];
// Cache the result in Redis for future pricing calls (e.g. 1 hour)
$redis->setex($redisKey, 3600, $negativeBalance);
}
}
*/
}
} catch (Exception $e) {
// If Redis fails, gracefully default to 0 or fallback API
$negativeBalance = 0;
}
}
$prices = ['total' => $withCommission];
// 4. Apply Discount and Negative Balance
foreach ($prices as $key => $price) {
// Apply discount (Assuming percentage discount if amount <= 100, else fixed amount)
if ($discount > 0 && $discount <= 100) {
$prices[$key] = max(0, $price - ($price * ($discount / 100)));
} else {
$prices[$key] = max(0, $price - $discount);
}
// Add negative balance
$prices[$key] += $negativeBalance;
}
echo json_encode([
'status' => 'success',
'data' => $prices,
'applied_discount' => $discount,
'added_negative_balance' => $negativeBalance
]);
?>