Add /vehicles/search route for vehicle registration search
- Introduced a new route `/vehicles/search` to enable searching for vehicles by registration number across multiple categories (e.g., verified, known, booked, unknown). - Added validation for search parameters, including length and format checks. - Ensured proper classification of vehicles with clear prioritization and deduplication logic. - Implemented helper methods to retrieve matching registrations from various sources like bookings, orders, and scanned plates. - Enhanced response format to include vehicle status, customer details, and references for improved usability.
This commit is contained in:
@@ -9,6 +9,7 @@ use objects\customer_vehicles_o;
|
||||
use objects\departments_o;
|
||||
use objects\logs_o;
|
||||
use objects\orders_o;
|
||||
use objects\plate_scans_o;
|
||||
use objects\products_o;
|
||||
use objects\users_o;
|
||||
use traits\route_t;
|
||||
@@ -715,6 +716,227 @@ class vehiclesRoute
|
||||
'view_vehicle_status' => 'View vehicle status (Verified, Known, Unknown, Booked, Card payment required, etc.)',
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/vehicles/search', function () {
|
||||
global $response;
|
||||
$this->requirePermission('search_vehicles');
|
||||
/**
|
||||
* This endpoint allows searching for vehicles by registration number.
|
||||
* This includes:
|
||||
* - verified vehicles (in customer_vehicles)
|
||||
* - known vehicles (in orders).
|
||||
* - booked vehicles (in bookings).
|
||||
* - unknown vehicles (not in any of the above).
|
||||
*/
|
||||
self::requireParameters(['search']);
|
||||
self::requireType((string)self::getParameter('search'), self::type_string());
|
||||
$search = (string)self::getParameter('search');
|
||||
self::requireMinLength('search', 1);
|
||||
self::requireMaxLength('search', 12);
|
||||
// Strip the search term of whitespace
|
||||
$search = preg_replace('/\s+/', '', $search);
|
||||
/** Get the different lists of registration numbers */
|
||||
$options = ['limit' => 10];
|
||||
$verified_regs = self::getVerifiedRegs($search, $options);
|
||||
$known_regs = self::getKnownRegs($search, $options);
|
||||
$booked_regs = self::getBookedRegs($search, $options);
|
||||
$unknown_regs = array_filter(array_unique(array_merge([...self::getUnknownRegs($search, $options), $search]))); // Add the search term as the first item, to ensure it is included in the results
|
||||
/** Prevent overlaps between the lists
|
||||
* - Booked vehicles should not be in known, unknown or verified
|
||||
* - Verified vehicles should not be in known or booked
|
||||
* - Known vehicles should not be in unknown
|
||||
* - Unknown vehicles should not be in any other list
|
||||
*/
|
||||
$known_regs = array_filter($known_regs, function ($reg) use ($verified_regs, $booked_regs) {
|
||||
return !in_array($reg, $verified_regs) && !in_array($reg, $booked_regs);
|
||||
});
|
||||
$verified_regs = array_filter($verified_regs, function ($reg) use ($booked_regs) {
|
||||
return !in_array($reg, $booked_regs);
|
||||
});
|
||||
$unknown_regs = array_filter($unknown_regs, function ($reg) use ($verified_regs, $known_regs, $booked_regs) {
|
||||
return !in_array($reg, $verified_regs) && !in_array($reg, $known_regs) && !in_array($reg, $booked_regs);
|
||||
});
|
||||
// Sort the lists alphabetically
|
||||
sort($verified_regs);
|
||||
sort($known_regs);
|
||||
sort($booked_regs);
|
||||
sort($unknown_regs);
|
||||
// Define the custom relevance sorting function
|
||||
$relevant = [
|
||||
...array_values(array_unique($booked_regs)),
|
||||
...array_values(array_unique($verified_regs)),
|
||||
...array_values(array_unique($known_regs)),
|
||||
...array_values(array_unique($unknown_regs)),
|
||||
];
|
||||
// Limit the results to 10 items total, while keeping the relevance order
|
||||
$vehicles = array_slice($relevant, 0, 10);
|
||||
/** Format the relevance results */
|
||||
$vehicles = array_map(function ($reg) use ($verified_regs, $known_regs, $booked_regs, $unknown_regs) {
|
||||
// Determine the status of the vehicle
|
||||
$status = null;
|
||||
$isVerified = in_array($reg, $verified_regs);
|
||||
$isKnown = in_array($reg, $known_regs);
|
||||
$isBooked = in_array($reg, $booked_regs);
|
||||
$isUnknown = in_array($reg, $unknown_regs);
|
||||
// Initialize other variables
|
||||
$customer_number = null; // Will be populated for verified / booked vehicles
|
||||
$customer_name = null; // Will be populated for verified / booked vehicles
|
||||
$last_order_id = (new customer_vehicles_o())->getLastOrderByPlate($reg)?->id ?? null;
|
||||
// These variables are only for verified vehicles
|
||||
$type = null;
|
||||
$id = null;
|
||||
$reference = null;
|
||||
// Booking related variables
|
||||
$booking_id = null;
|
||||
$notes = null; // Booking notes
|
||||
|
||||
// Set the status based on priority: booked > verified > known > unknown
|
||||
if ($isBooked) {
|
||||
$status = 'booked';
|
||||
// Get the booking
|
||||
$booking = (new bookings_o())->getFieldsWhere([
|
||||
'regNrTraekker' => $reg,
|
||||
'status' => 'pending',
|
||||
], ['id', 'customer_number', 'reference_number', 'notes']);
|
||||
// If there is no booking with the tractor reg, check the trailer reg
|
||||
if (!$booking) {
|
||||
$booking = (new bookings_o())->getFieldsWhere([
|
||||
'regNrTrailer' => $reg,
|
||||
'status' => 'pending',
|
||||
], ['id', 'customer_number', 'reference_number', 'notes']);
|
||||
}
|
||||
// Populate other variables
|
||||
$booking_id = $booking ? (int)$booking[0]['id'] : null;
|
||||
$customer_number = $booking ? (int)$booking[0]['customer_number'] : null;
|
||||
$reference = $booking ? (string)$booking[0]['reference_number'] : null;
|
||||
$notes = $booking ? (string)$booking[0]['notes'] : null;
|
||||
// If the booking has a customer number, check if the customer is barred
|
||||
if ($customer_number && (new users_o())->isCustomerBarred((int)$customer_number)) {
|
||||
$status = 'card';
|
||||
}
|
||||
} elseif ($isVerified) {
|
||||
$status = 'verified';
|
||||
// Get the vehicle
|
||||
$customer_vehicles_o = new customer_vehicles_o();
|
||||
$vehicle = $customer_vehicles_o->getFieldsWhere(['reg' => $reg], ['customer_id', 'type', 'id', 'reference']);
|
||||
// Populate other variables
|
||||
$customer_number = $vehicle ? (int)$vehicle[0]['customer_id'] : null;
|
||||
$type = $vehicle ? (int)$vehicle[0]['type'] : null;
|
||||
$id = $vehicle ? (int)$vehicle[0]['id'] : null;
|
||||
$reference = $vehicle ? (string)$vehicle[0]['reference'] : null;
|
||||
// Check if the customer is barred (only if verified)
|
||||
if ($customer_number && (new users_o())->isCustomerBarred((int)$customer_number)) {
|
||||
$status = 'card';
|
||||
}
|
||||
} elseif ($isKnown) {
|
||||
$status = 'known';
|
||||
} elseif ($isUnknown) {
|
||||
$status = 'unknown';
|
||||
}
|
||||
// Get the customer name if we have a customer number
|
||||
if ($customer_number) {
|
||||
$customer = (new users_o())->getUserByCustomerNumber((int)$customer_number);
|
||||
if ($customer->exists()) {
|
||||
$customer_name = (string)$customer->getCustomerName((int)$customer_number);
|
||||
}
|
||||
}
|
||||
// Return the formatted vehicle
|
||||
return [
|
||||
'reg' => $reg,
|
||||
'status' => $status,
|
||||
'type' => $type,
|
||||
'customer_id' => $customer_number,
|
||||
'id' => $id,
|
||||
'last_order_id' => $last_order_id,
|
||||
'reference' => $reference,
|
||||
'booking_id' => $booking_id,
|
||||
'notes' => $notes,
|
||||
'customer_name' => $customer_name,
|
||||
'barred' => $status === 'card', // If the status is 'card', the customer is barred
|
||||
];
|
||||
}, $vehicles);
|
||||
// Return the results
|
||||
$response->success($vehicles);
|
||||
},
|
||||
[
|
||||
'search_vehicles' => 'Search vehicles by registration number',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private static function getVerifiedRegs(string $search, array $options = ['limit' => null]): array
|
||||
{
|
||||
$customer_vehicles_o = new customer_vehicles_o();
|
||||
$results = $customer_vehicles_o->getFieldsWhereContaining(
|
||||
[
|
||||
'reg' => $search
|
||||
],
|
||||
['reg'],
|
||||
$options
|
||||
);
|
||||
return array_map(function ($row) {
|
||||
return (string)$row['reg'];
|
||||
}, $results);
|
||||
}
|
||||
|
||||
private static function getKnownRegs(string $search, array $options = ['limit' => null]): array
|
||||
{
|
||||
$orders_o = new orders_o();
|
||||
$results = $orders_o->getFieldsWhereContaining(
|
||||
[
|
||||
'reg_1' => $search
|
||||
],
|
||||
['reg_1'],
|
||||
$options
|
||||
);
|
||||
return array_map(function ($row) {
|
||||
return (string)$row['reg_1'];
|
||||
}, $results);
|
||||
}
|
||||
|
||||
private static function getBookedRegs(string $search, array $options = ['limit' => null]): array
|
||||
{
|
||||
$bookings_o = new bookings_o();
|
||||
$results1 = $bookings_o->getFieldsWhereContaining(
|
||||
[
|
||||
'regNrTraekker' => $search,
|
||||
'status' => 'pending',
|
||||
],
|
||||
['regNrTraekker'],
|
||||
$options
|
||||
);
|
||||
$results2 = $bookings_o->getFieldsWhereContaining(
|
||||
[
|
||||
'regNrTrailer' => $search,
|
||||
'status' => 'pending',
|
||||
],
|
||||
['regNrTrailer'],
|
||||
$options
|
||||
);
|
||||
return array_unique(array_merge(
|
||||
array_map(function ($row) {
|
||||
return (string)$row['regNrTraekker'];
|
||||
}, $results1),
|
||||
array_map(function ($row) {
|
||||
return (string)$row['regNrTrailer'];
|
||||
}, $results2)
|
||||
));
|
||||
}
|
||||
|
||||
private static function getUnknownRegs(string $search, array $options = ['limit' => null]): array
|
||||
{
|
||||
// Unknown vehicles are vehicles that has been scanned by the LPR system, but are not in any of the other lists
|
||||
$plate_scans_o = new plate_scans_o();
|
||||
$results = $plate_scans_o->getFieldsWhereContaining(
|
||||
[
|
||||
'plate' => $search,
|
||||
],
|
||||
['plate'],
|
||||
$options
|
||||
);
|
||||
return array_map(function ($row) {
|
||||
return (string)$row['plate'];
|
||||
}, $results);
|
||||
}
|
||||
|
||||
private function getData(mixed $data, $response)
|
||||
|
||||
Reference in New Issue
Block a user