253 lines
9.5 KiB
PHP
253 lines
9.5 KiB
PHP
<?php
|
|
/**
|
|
* Nabeh Integration — Unified Query API
|
|
*
|
|
* Called by Nabeh AI platform to query driver info, trips, stats, and trip details.
|
|
*/
|
|
|
|
require_once __DIR__ . '/../core/bootstrap.php';
|
|
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
|
header('Access-Control-Allow-Headers: Content-Type, X-API-Key');
|
|
|
|
$apiKey = $_SERVER['HTTP_X_API_KEY'] ?? '';
|
|
$expectedKey = getenv('NABEH_API_KEY') ?: '';
|
|
|
|
if (empty($apiKey) || $apiKey !== $expectedKey) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failure', 'message' => 'Unauthorized: invalid API key']);
|
|
exit;
|
|
}
|
|
|
|
$input = [];
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$raw = file_get_contents('php://input');
|
|
$input = json_decode($raw, true) ?: [];
|
|
} else {
|
|
$input = $_GET;
|
|
}
|
|
|
|
$queryType = $input['query_type'] ?? '';
|
|
$phone = preg_replace('/[^0-9]/', '', $input['phone'] ?? '');
|
|
$driverId = $input['driver_id'] ?? '';
|
|
$tripId = $input['trip_id'] ?? '';
|
|
$limit = min((int)($input['limit'] ?? 10), 50);
|
|
|
|
if (empty($queryType)) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'failure', 'message' => 'query_type is required. Options: driver_info, driver_trips, driver_stats, trip_detail']);
|
|
exit;
|
|
}
|
|
|
|
$validTypes = ['driver_info', 'driver_trips', 'driver_stats', 'trip_detail'];
|
|
if (!in_array($queryType, $validTypes, true)) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'failure', 'message' => 'Invalid query_type. Options: ' . implode(', ', $validTypes)]);
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
global $encryptionHelper;
|
|
$mainDb = Database::get('main');
|
|
$rideDb = Database::get('ride');
|
|
|
|
// ========================================================================
|
|
if ($queryType === 'driver_info') {
|
|
if (empty($phone)) {
|
|
jsonError('phone parameter is required');
|
|
}
|
|
|
|
$encryptedPhone = $encryptionHelper->encryptData($phone);
|
|
|
|
$stmt = $mainDb->prepare("
|
|
SELECT d.id, d.phone, d.first_name, d.last_name, d.name_arabic,
|
|
d.status, d.created_at, d.birthdate, d.gender, d.site,
|
|
cr.id as car_id, cr.make, cr.model, cr.year, cr.car_plate,
|
|
cr.color, cr.color_hex, cr.fuel, cr.vin,
|
|
cr.status as car_status, cr.expiration_date
|
|
FROM driver d
|
|
LEFT JOIN CarRegistration cr ON cr.driverID = d.id
|
|
WHERE d.phone = :phone OR d.email LIKE :phoneLike
|
|
LIMIT 1
|
|
");
|
|
$stmt->execute([
|
|
':phone' => $encryptedPhone,
|
|
':phoneLike' => $phone . '%',
|
|
]);
|
|
$driver = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$driver) {
|
|
echo json_encode(['status' => 'success', 'data' => null, 'message' => 'Driver not found']);
|
|
exit;
|
|
}
|
|
|
|
$decrypt = function($val) use ($encryptionHelper) {
|
|
return $val ? $encryptionHelper->decryptData($val) : $val;
|
|
};
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'data' => [
|
|
'driver_id' => $driver['id'],
|
|
'phone' => $decrypt($driver['phone']),
|
|
'first_name' => $decrypt($driver['first_name']),
|
|
'last_name' => $decrypt($driver['last_name']),
|
|
'name_arabic' => $decrypt($driver['name_arabic']),
|
|
'gender' => $decrypt($driver['gender']),
|
|
'birthdate' => $driver['birthdate'],
|
|
'status' => $driver['status'],
|
|
'site' => $decrypt($driver['site']),
|
|
'registered_at' => $driver['created_at'],
|
|
'car' => $driver['car_id'] ? [
|
|
'id' => $driver['car_id'],
|
|
'make' => $driver['make'],
|
|
'model' => $driver['model'],
|
|
'year' => $driver['year'],
|
|
'plate' => $driver['car_plate'],
|
|
'color' => $driver['color'],
|
|
'color_hex' => $driver['color_hex'],
|
|
'fuel' => $driver['fuel'],
|
|
'vin' => $decrypt($driver['vin']),
|
|
'status' => $driver['car_status'],
|
|
'expiration_date' => $driver['expiration_date'],
|
|
] : null,
|
|
],
|
|
], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
// ========================================================================
|
|
if ($queryType === 'driver_trips') {
|
|
if (empty($driverId) && empty($phone)) {
|
|
jsonError('driver_id or phone is required');
|
|
}
|
|
|
|
if (empty($driverId) && !empty($phone)) {
|
|
$encryptedPhone = $encryptionHelper->encryptData($phone);
|
|
$stmt = $mainDb->prepare("SELECT id FROM driver WHERE phone = :phone LIMIT 1");
|
|
$stmt->execute([':phone' => $encryptedPhone]);
|
|
$driverRow = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
if (!$driverRow) {
|
|
echo json_encode(['status' => 'success', 'data' => [], 'message' => 'Driver not found']);
|
|
exit;
|
|
}
|
|
$driverId = $driverRow['id'];
|
|
}
|
|
|
|
$stmt = $rideDb->prepare("
|
|
SELECT id, start_location, end_location, date, time, endtime,
|
|
price, price_for_driver, price_for_passenger,
|
|
status, paymentMethod, carType, distance, created_at
|
|
FROM ride
|
|
WHERE driver_id = :driver_id
|
|
ORDER BY created_at DESC
|
|
LIMIT :lim
|
|
");
|
|
$stmt->bindValue(':driver_id', $driverId, PDO::PARAM_STR);
|
|
$stmt->bindValue(':lim', $limit, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
$trips = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'data' => $trips,
|
|
'count' => count($trips),
|
|
], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
// ========================================================================
|
|
if ($queryType === 'driver_stats') {
|
|
if (empty($driverId) && empty($phone)) {
|
|
jsonError('driver_id or phone is required');
|
|
}
|
|
|
|
if (empty($driverId) && !empty($phone)) {
|
|
$encryptedPhone = $encryptionHelper->encryptData($phone);
|
|
$stmt = $mainDb->prepare("SELECT id FROM driver WHERE phone = :phone LIMIT 1");
|
|
$stmt->execute([':phone' => $encryptedPhone]);
|
|
$driverRow = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
if (!$driverRow) {
|
|
echo json_encode(['status' => 'success', 'data' => null, 'message' => 'Driver not found']);
|
|
exit;
|
|
}
|
|
$driverId = $driverRow['id'];
|
|
}
|
|
|
|
$stmt = $rideDb->prepare("
|
|
SELECT
|
|
COUNT(*) as total_trips,
|
|
COALESCE(SUM(price_for_driver), 0) as total_earnings,
|
|
COALESCE(SUM(price_for_passenger), 0) as total_collected,
|
|
COALESCE(AVG(price_for_driver), 0) as avg_earning_per_trip,
|
|
COALESCE(SUM(distance), 0) as total_distance,
|
|
COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed_trips,
|
|
COUNT(CASE WHEN status = 'cancelled' THEN 1 END) as cancelled_trips
|
|
FROM ride
|
|
WHERE driver_id = :driver_id
|
|
");
|
|
$stmt->execute([':driver_id' => $driverId]);
|
|
$stats = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
$driverStmt = $mainDb->prepare("SELECT status, created_at FROM driver WHERE id = :id LIMIT 1");
|
|
$driverStmt->execute([':id' => $driverId]);
|
|
$driverStatus = $driverStmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'data' => [
|
|
'driver_id' => $driverId,
|
|
'status' => $driverStatus['status'] ?? 'unknown',
|
|
'registered_at' => $driverStatus['created_at'] ?? null,
|
|
'stats' => [
|
|
'total_trips' => (int)$stats['total_trips'],
|
|
'completed_trips' => (int)$stats['completed_trips'],
|
|
'cancelled_trips' => (int)$stats['cancelled_trips'],
|
|
'total_earnings' => (float)$stats['total_earnings'],
|
|
'total_collected' => (float)$stats['total_collected'],
|
|
'avg_earning_per_trip' => (float)$stats['avg_earning_per_trip'],
|
|
'total_distance_km' => (float)$stats['total_distance'],
|
|
],
|
|
],
|
|
], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
// ========================================================================
|
|
if ($queryType === 'trip_detail') {
|
|
if (empty($tripId)) {
|
|
jsonError('trip_id is required');
|
|
}
|
|
|
|
$stmt = $rideDb->prepare("
|
|
SELECT r.*,
|
|
p.first_name as passenger_first_name,
|
|
p.last_name as passenger_last_name,
|
|
p.phone as passenger_phone
|
|
FROM ride r
|
|
LEFT JOIN driver p ON p.id = r.passenger_id
|
|
WHERE r.id = :id
|
|
LIMIT 1
|
|
");
|
|
$stmt->execute([':id' => $tripId]);
|
|
$trip = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$trip) {
|
|
echo json_encode(['status' => 'success', 'data' => null, 'message' => 'Trip not found']);
|
|
exit;
|
|
}
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'data' => $trip,
|
|
], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
} catch (\Exception $e) {
|
|
error_log("[Nabeh Query Error] " . $e->getMessage());
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'failure', 'message' => 'Internal server error']);
|
|
}
|