Update: 2026-07-06 00:53:15
This commit is contained in:
@@ -85,9 +85,6 @@ foreach ($data as $row) {
|
||||
}
|
||||
|
||||
$distanceKm = (float)($resultData['distance_km'] ?? 1);
|
||||
if ($distanceKm <= 0) $distanceKm = 1; // Prevent division by zero
|
||||
$pricePerKm = $amount / $distanceKm;
|
||||
|
||||
$durationMin = isset($resultData['duration_min']) ? (int)$resultData['duration_min'] : null;
|
||||
|
||||
$startLat = $resultData['start_lat'] ?? null;
|
||||
@@ -95,6 +92,20 @@ foreach ($data as $row) {
|
||||
$endLat = $resultData['end_lat'] ?? null;
|
||||
$endLng = $resultData['end_lng'] ?? null;
|
||||
|
||||
// --- OSRM Integration (Dynamic Distance & Duration) ---
|
||||
require_once __DIR__ . '/../core/osrm_routing.php';
|
||||
if ($startLat && $endLat && (!$durationMin || $durationMin <= 0)) {
|
||||
$osrmResult = getOsrmRouteDetails($startLat, $startLng, $endLat, $endLng);
|
||||
if ($osrmResult) {
|
||||
$distanceKm = $osrmResult['distance_km']; // Override with accurate OSRM distance
|
||||
$durationMin = $osrmResult['duration_min'];
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------
|
||||
|
||||
if ($distanceKm <= 0) $distanceKm = 1; // Prevent division by zero
|
||||
$pricePerKm = $amount / $distanceKm;
|
||||
|
||||
$countryCode = $row['country_code'] ?? 'JO'; // Default
|
||||
|
||||
if ($stmt->execute([
|
||||
|
||||
+16
-3
@@ -131,15 +131,28 @@ if ($method === 'GET') {
|
||||
$pricePerKm = $distance_km > 0 ? ($price / $distance_km) : 0.0;
|
||||
$country_code = $result_data['country_code'] ?? 'SY';
|
||||
|
||||
// --- OSRM Integration (Dynamic Distance & Duration) ---
|
||||
require_once __DIR__ . '/../core/osrm_routing.php';
|
||||
$duration_min = 0;
|
||||
if ($start_lat != 0 && $end_lat != 0) {
|
||||
$osrmResult = getOsrmRouteDetails($start_lat, $start_lng, $end_lat, $end_lng);
|
||||
if ($osrmResult) {
|
||||
$distance_km = $osrmResult['distance_km']; // Override with accurate OSRM distance
|
||||
$duration_min = $osrmResult['duration_min'];
|
||||
$pricePerKm = $distance_km > 0 ? ($price / $distance_km) : 0.0; // Recalculate based on OSRM
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------
|
||||
|
||||
// 1. Save to MySQL
|
||||
$stmt = $con->prepare("
|
||||
INSERT INTO scraped_competitor_prices
|
||||
(task_id, app_name, competitor_name, start_location, end_location, start_lat, start_lng, end_lat, end_lng, price_amount, price_per_km, currency, country_code)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
(task_id, app_name, competitor_name, start_location, end_location, start_lat, start_lng, end_lat, end_lng, price_amount, price_per_km, distance_km, duration_min, currency, country_code)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
$start_loc = "Lat: $start_lat, Lng: $start_lng";
|
||||
$end_loc = "Lat: $end_lat, Lng: $end_lng";
|
||||
$stmt->execute([$task_id, $app_name, $app_name, $start_loc, $end_loc, (string)$start_lat, (string)$start_lng, (string)$end_lat, (string)$end_lng, $price, $pricePerKm, 'JOD', $country_code]);
|
||||
$stmt->execute([$task_id, $app_name, $app_name, $start_loc, $end_loc, (string)$start_lat, (string)$start_lng, (string)$end_lat, (string)$end_lng, $price, $pricePerKm, $distance_km, $duration_min, 'JOD', $country_code]);
|
||||
|
||||
// 2. Save to Redis (Calculate Price Per KM)
|
||||
if ($distance_km > 0 && $price > 0) {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
// ============================================================
|
||||
// osrm_routing.php
|
||||
// Helper functions for OpenStreetMap Routing Machine (OSRM)
|
||||
// Used to estimate accurate distance (km) and duration (mins)
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Get Distance and Duration between two coordinates using public OSRM server.
|
||||
* Note: If you host your own OSRM, replace the $osrmBaseUrl.
|
||||
*
|
||||
* @param float $startLat
|
||||
* @param float $startLng
|
||||
* @param float $endLat
|
||||
* @param float $endLng
|
||||
* @return array|null Returns ['distance_km' => float, 'duration_min' => float] or null on failure.
|
||||
*/
|
||||
function getOsrmRouteDetails($startLat, $startLng, $endLat, $endLng) {
|
||||
// Format: longitude,latitude
|
||||
$coordinates = "{$startLng},{$startLat};{$endLng},{$endLat}";
|
||||
|
||||
// Using public demo server. Note: Has rate limits.
|
||||
// For production, highly recommended to use: "http://your-own-osrm-server.com:5000"
|
||||
$osrmBaseUrl = "http://router.project-osrm.org";
|
||||
$url = "{$osrmBaseUrl}/route/v1/driving/{$coordinates}?overview=false";
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 5); // 5 seconds timeout
|
||||
|
||||
// Add a User-Agent to avoid being blocked by the public demo server
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, "SiroRideHailingApp/1.0");
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode === 200 && $response) {
|
||||
$data = json_decode($response, true);
|
||||
if (isset($data['code']) && $data['code'] === 'Ok' && isset($data['routes'][0])) {
|
||||
$route = $data['routes'][0];
|
||||
$distanceMeters = isset($route['distance']) ? (float)$route['distance'] : 0;
|
||||
$durationSeconds = isset($route['duration']) ? (float)$route['duration'] : 0;
|
||||
|
||||
return [
|
||||
'distance_km' => round($distanceMeters / 1000, 2),
|
||||
'duration_min' => round($durationSeconds / 60, 2)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -184,19 +184,12 @@ function calculateDynamicPrice($country, $minFare, $distance, $duration, $kazanR
|
||||
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);
|
||||
@@ -210,23 +203,15 @@ function calculateDynamicPrice($country, $minFare, $distance, $duration, $kazanR
|
||||
$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;
|
||||
|
||||
// Apply dynamic percentage discount instead of hardcoded currencies for long trips
|
||||
$perKmSpeed = $perKmSpeedBaseFromServer;
|
||||
if ($billableDistance > $longDistThresholdKm) {
|
||||
$perKmSpeed = $perKmSpeedBaseFromServer * 0.85; // 15% discount per km
|
||||
} else if ($billableDistance > $mediumDistThresholdKm) {
|
||||
$perKmSpeed = $perKmSpeedBaseFromServer * 0.90; // 10% discount per km
|
||||
}
|
||||
|
||||
date_default_timezone_set('Asia/Damascus');
|
||||
@@ -242,11 +227,10 @@ function calculateDynamicPrice($country, $minFare, $distance, $duration, $kazanR
|
||||
|
||||
$billableMinutes = $totalMinutes;
|
||||
if ($billableDistance > $longDistThresholdKm) {
|
||||
$effectivePerMin = $longTripPerMin;
|
||||
// Prevent absurd time billing for very long trips
|
||||
$capped = ($billableMinutes > $minuteCapLong) ? $minuteCapLong : $billableMinutes;
|
||||
$billableMinutes = max(0, $capped - $freeMinutesLong);
|
||||
} else if ($billableDistance > $mediumDistThresholdKm) {
|
||||
$effectivePerMin = $longTripPerMin;
|
||||
$billableMinutes = ($billableMinutes > $minuteCapMedium) ? $minuteCapMedium : $billableMinutes;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user