Files
api/services/nginx/app/routes/vehiclesRoute.php
T

1060 lines
49 KiB
PHP

<?php
namespace routes;
use classes\authentication;
use customers\economic_customer_mo;
use objects\bookings_o;
use objects\customer_vehicles_o;
use objects\departments_o;
use objects\logs_o;
use objects\order_bookings_o;
use objects\orders_o;
use objects\plate_scans_o;
use objects\products_o;
use objects\users_o;
use traits\route_t;
class vehiclesRoute
{
use route_t;
public function run(): void
{
$this->get('/vehicles', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('list_own_vehicles');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_OWN_VEHICLES', 'Successfully listed own vehicles');
// Check if the id parameter is set
if ($this->isParametersSet(['id'])) {
// Get the id parameter
$id = (int)$this->getParameter('id');
$this->requireType($id, self::type_int());
$this->requireMinValue($id, 1);
$this->requireMaxValue($id, 9999999999);
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_OWN_VEHICLES', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to list the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to list other users vehicles
if (!$user->hasPermission('list_vehicles_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_OWN_VEHICLES', 'User tried to list a vehicle from another user');
// Return an error
$response->error('You are not allowed to list vehicles from other users', 403);
}
}
// Return the vehicle as an array
$response->success(
[...$vehicle->asArray()]
);
}
// Return the list of the user's vehicles
$vehicles_o = new customer_vehicles_o();
// Check if the user is allowed to list other user's vehicles
if (!$user->hasPermission('list_vehicles_other')) {
$restrict = [
'customer_id' => (int)$user->customer_number->value(),
];
}
$response->success(
$vehicles_o->listObjectsWithPaginationIfSet(
function ($vehicle) use ($user) {
// Return the object as an array
return [
...(new customer_vehicles_o())->select($vehicle['id'])->asArray(),
];
},
$vehicles_o->forceRestrictFilters([
...$restrict ?? []
])
)
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'LIST_OWN_VEHICLES', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 400);
}
},
[
'list_own_vehicles' => 'List own vehicles',
'list_vehicles_other' => 'List other users vehicles',
]
);
$this->get('/department/vehicles/unknown-customer', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('list_unknown_customer_vehicles');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_UNKNOWN_CUSTOMER_VEHICLES', 'Successfully listed unknown customer vehicles');
// Return the list of the user's vehicles
$vehicles_o = new orders_o();
$vehicles_o->setView('unique_order_reg_1');
$response->success($vehicles_o
->setSearchableFields([
'reg_1'
])
->listObjectsWithPaginationIfSet()
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'LIST_UNKNOWN_CUSTOMER_VEHICLES', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 400);
}
},
[
'list_unknown_customer_vehicles' => 'List unknown customer vehicles',
]
);
$this->post('/vehicles', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('add_vehicle');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Require the parameters
self::requireParameters([
'type',
'reg',
'wash_subscription',
]);
// Set the customer_id to the one from the user
$target_user = $user;
// Check if customer_id is set
if (self::isParametersSet([
'customer_id',
])) {
// Check if the customer_id is the same as the current user
if ((int)$user->customer_number->value() !== (int)self::getParameter('customer_id')) {
// Check if the user has permission to add vehicles to other users
if (!$user->hasPermission('add_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'ADD_VEHICLE', 'User tried to add a vehicle to another user');
// Return an error
$response->error('You are not allowed to add vehicles to other users', 403);
} else {
// Set the customer_id to the one from the request
$target_user = (new users_o());
$target_user->getUserByCustomerNumber((int)self::getParameter('customer_id'));
}
}
}
$reference = null;
// Check if the reference is set
if (self::isParametersSet([
'reference',
])) {
// If the reference is not empty, check if it is valid
if (!empty(self::getParameter('reference'))) {
// Check if the reference is valid
$reference = (string)self::getParameter('reference');
self::requireType($reference, self::type_string());
self::requireMinLength('reference', 1);
self::requireMaxLength('reference', 255);
}
}
// Validate the parameters
self::requireType(
self::getParameter('reg'),
self::type_string()
);
self::requireType(
self::getParameter('type'),
self::type_int()
);
self::requireType(
self::getParameter('wash_subscription'),
self::type_bool()
);
// Get the parameters
$reg = (string)self::getParameter('reg');
$type = (int)self::getParameter('type');
$subscription = (bool)self::getParameter('wash_subscription');
// Create a new vehicle
$vehicle = new customer_vehicles_o();
$vehicle->add(
$target_user->customer_number->value(),
$type,
$reg,
$subscription ? 1 : 0,
$reference
);
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'ADD_VEHICLE', 'Successfully added vehicle');
// Return the new vehicle
$response->success(
$vehicle->asArray()
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'ADD_VEHICLE', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
}
},
[
'add_vehicle' => 'Add a vehicle to own vehicles',
'add_vehicle_other' => 'Add a vehicle to another users vehicles',
]
);
$this->put('/vehicles', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('edit_vehicle');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'EDIT_VEHICLE', 'User edited a vehicle');
// Get the request data
self::requireParameters([
'id'
]);
$id = (int)self::getParameter('id');
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'EDIT_VEHICLE', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to edit the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to edit other users vehicles
if (!$user->hasPermission('edit_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'EDIT_VEHICLE', 'User tried to edit a vehicle from another user');
// Return an error
$response->error('You are not allowed to edit vehicles from other users', 403);
}
}
// Check all the fields, and if they are set, validate and set them
if (self::isParametersSet(['type'])) {
$type = (int)self::getParameter('type');
// Make sure the type is an integer
self::requireType($type, self::type_int());
self::requireMinValue($type, 0);
// Make sure the type is a valid type (If it isn't 0)
if ($type === 0) {
// Set the type to null
$vehicle->type->set(0);
// Turn off the subscription
$vehicle->wash_subscription->set(0);
return;
} else {
$products_o = new products_o();
$products_o->select((int)$type);
if (!$products_o->exists() || !$products_o->subscription_allowed->value()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'EDIT_VEHICLE', 'Invalid type');
// Return an error
$response->error('Invalid type', 400);
}
// Set the type
$vehicle->type->set(
(int)$type
);
// TODO: Make the potential vehicleTypeId reflect the correct type.
// It's currently possible to set the vehicleTypeId to a type that is not allowed for the vehicle.
}
}
if (self::isParametersSet(['reg'])) {
$reg = (string)self::getParameter('reg');
self::requireType($reg, self::type_string());
self::requireMinLength('reg', 2);
self::requireMaxLength('reg', 12);
// Strip the registration number of whitespace
$reg = preg_replace('/\s+/', '', $reg);
// Set the registration number
$vehicle->reg->set($reg);
}
if (self::isParametersSet(['wash_subscription'])) {
$subscription = (bool)self::getParameter('wash_subscription');
self::requireType($subscription, self::type_bool());
// Check if the type is a valid type (If it isn't 0)
if ((int)$vehicle->type->value() === 0 && $subscription) {
// Set the subscription to null
$response->error('Unable to set subscription, type is not set', 400);
}
// Set the wash subscription
$vehicle->wash_subscription->set($subscription ? 1 : 0);
}
if (self::isParametersSet(['reference'])) {
// Check if the reference is set to null/empty
if (empty(self::getParameter('reference'))) {
// Set the reference to null
$vehicle->reference->nullify();
} else {
// Check if the reference is valid
$reference = (string)self::getParameter('reference');
self::requireType($reference, self::type_string());
self::requireMinLength('reference', 1);
self::requireMaxLength('reference', 255);
// Set the reference
$vehicle->reference->set($reference);
}
}
$vehicle->objectChanged();
// Return the vehicle
$response->success(
$vehicle->asArray()
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'EDIT_VEHICLE', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
}
},
[
'edit_vehicle' => 'Edit a vehicle',
'edit_vehicle_other' => 'Edit a vehicle from another user'
]
);
$this->delete('/vehicles', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('delete_vehicle');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'DELETE_VEHICLE', 'User deleted a vehicle');
// Get the request data
self::requireParameters([
'id'
]);
$id = (int)self::getParameter('id');
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'DELETE_VEHICLE', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to delete the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to delete other users vehicles
if (!$user->hasPermission('delete_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'DELETE_VEHICLE', 'User tried to delete a vehicle from another user');
// Return an error
$response->error('You are not allowed to delete vehicles from other users', 403);
}
}
// Delete the vehicle
$vehicle->delete();
// Return success
$response->success(
[
'success' => true,
'message' => 'Vehicle deleted successfully'
]
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'DELETE_VEHICLE', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
}
},
[
'delete_vehicle' => 'Delete a vehicle',
'delete_vehicle_other' => 'Remove (delete) a vehicle from another user'
]
);
$this->get('/department/vehicle/customer-suggestions', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('list_vehicle_customer_suggestions');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
self::requireParameters(['reg_1']);
self::requireType((string)self::getParameter('reg_1'), self::type_string());
$plate = (string)self::getParameter('reg_1');
self::requireMinLength('reg_1', 1);
self::requireMaxLength('reg_1', 12);
// Return the list of the user's vehicles
$orders_o = new orders_o();
// Check if the user is allowed to list other user's vehicles
// Get all the customer_ids that has orders with the same plate
$customer_ids = $orders_o->getFieldsWhere([
'reg_1' => $plate,
'deleted_at' => null,
], [
'customer_id',
]);
// Get all the customer_ids that has orders with the same plate
$customer_ids = array_map(function ($customer_id) {
return (int)$customer_id['customer_id'];
}, $customer_ids);
// Remove duplicates
$customer_ids = array_unique($customer_ids);
// Get all the customers that has orders with the same plate
$customers = [];
foreach ( $customer_ids as $customer_id ) {
$customers[] = (new users_o())->getUserByCustomerNumber($customer_id);
}
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_VEHICLE_CUSTOMER_SUGGESTIONS', 'Successfully listed customer suggestions for a vehicle');
// Format the response
$response->success(
array_map(function ($customer) {
/** @var users_o $customer */
$customer_number = (int)$customer->customer_number->value();
return [
'id' => (int)$customer->id,
'customer_name' => (string)$customer->getCustomerName((int)$customer_number),
'customer_number' => (int)$customer_number,
'barred' => (new economic_customer_mo())->getCustomerByCustomerNumber((int)$customer_number)->asArray()['barred'],
];
}, $customers)
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'LIST_VEHICLE_CUSTOMER_SUGGESTIONS', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 400);
}
},
[
'list_vehicle_customer_suggestions' => 'List customer suggestions for a vehicle',
]
);
$this->post('/vehicles/set-auto-start-on-lpr', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('set_auto_start_on_lpr');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_AUTO_START_ON_LPR', 'User set auto start on LPR');
// Get the request data
self::requireParameters([
'id',
'active',
]);
$id = (int)self::getParameter('id');
self::requireType($id, self::type_int());
self::requireMinValue($id, 1);
self::requireMaxValue($id, 9999999999);
// Validate the autoStartOnLpr (active) parameter
$autoStartOnLpr = (bool)self::getParameter('active');
self::requireType($autoStartOnLpr, self::type_bool());
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_AUTO_START_ON_LPR', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to edit the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to edit other users vehicles
if (!$user->hasPermission('edit_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_AUTO_START_ON_LPR', 'User tried to set auto start on LPR from another user');
// Return an error
$response->error('You are not allowed to edit vehicles from other users', 403);
}
}
// Set the auto start on LPR
$vehicle->setAutoStartOnLpr(
$autoStartOnLpr
);
// Return the vehicle as an array
$response->success(
[...$vehicle->asArray()]
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'SET_AUTO_START_ON_LPR', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
}
},
[
'set_auto_start_on_lpr' => 'Set auto start on LPR',
'set_auto_start_on_lpr_other' => 'Set auto start on LPR for another user\'s vehicle',
]
);
$this->post('/vehicles/set-vehicle-type-id', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('set_vehicle_type_id');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_VEHICLE_TYPE_ID', 'User set vehicle type ID');
// Get the request data
self::requireParameters([
'id',
'vehicleTypeId',
]);
$id = (int)self::getParameter('id');
self::requireType($id, self::type_int());
self::requireMinValue($id, 1);
self::requireMaxValue($id, 9999999999);
// Validate the vehicleTypeId
$vehicleTypeId = (string)self::getParameter('vehicleTypeId');
self::requireType($vehicleTypeId, self::type_string());
self::requireMinLength('vehicleTypeId', 1);
self::requireMaxLength('vehicleTypeId', 50);
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_VEHICLE_TYPE_ID', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to edit the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to edit other users vehicles
if (!$user->hasPermission('edit_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_VEHICLE_TYPE_ID', 'User tried to set vehicle type ID from another user');
// Return an error
$response->error('You are not allowed to edit vehicles from other users', 403);
}
}
// Get the customer object
$customer = (new users_o())->getUserByCustomerNumber((int)$vehicle->customer_id->value());
// Check if the vehicle is registered in the XL Vask system
if (!$vehicle->hasXLVask()) {
// Check if the customer has an XL Vask customer account
if (!$customer->hasXLVaskCustomerAccount()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_VEHICLE_TYPE_ID', 'User tried to set vehicle type ID on a vehicle that is not registered in the XL Vask system, without a customer account');
// Return an error
$response->error('Vehicle is not registered in the XL Vask system', 400);
} else {
$vehicle->createXLVaskVehicle($vehicleTypeId);
}
} else {
// Set the vehicle type ID
$vehicle->setVehicleTypeId(
$vehicleTypeId
);
}
// Return the vehicle as an array
$response->success(
[...$vehicle->asArray()]
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'SET_VEHICLE_TYPE_ID', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
}
},
[
'set_vehicle_type_id' => 'Set vehicle type ID',
'set_vehicle_type_id_other' => 'Set vehicle type ID for another user\'s vehicle',
]
);
$this->get('/superuser/users-with-vehicle-subscriptions', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('list_users_with_vehicle_subscriptions');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_USERS_WITH_VEHICLE_SUBSCRIPTIONS', 'Successfully listed users with vehicle subscriptions');
// Return the list of users with vehicle subscriptions
$vehicles_o = new customer_vehicles_o();
$customer_ids = $vehicles_o->getFieldsWhere(
[
'wash_subscription' => 1,
],
['customer_id']
);
// Get all the customer_ids that has vehicle subscriptions
$customer_ids = array_map(function ($customer_id) {
return (int)$customer_id['customer_id'];
}, $customer_ids);
// Remove duplicates
$customer_ids = array_unique($customer_ids);
$response->success(
$customer_ids ? array_map(function ($customer_id) {
$tmp_user = new users_o();
$tmp_user->getUserByCustomerNumber((int)$customer_id);
return [...$tmp_user->asArray()];
}, $customer_ids) : []
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'LIST_USERS_WITH_VEHICLE_SUBSCRIPTIONS', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 400);
}
},
[
'list_users_with_vehicle_subscriptions' => 'List users with vehicle subscriptions',
]
);
$this->get('/vehicles/status', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('view_vehicle_status');
/** Define parameters */
// "reg" - The registration number to check the status of
self::requireParameters([
'reg',
]);
self::requireType((string)self::getParameter('reg'), self::type_string());
$reg = (string)self::getParameter('reg');
self::requireMinLength('reg', 1);
self::requireMaxLength('reg', 12);
// "department" - The department to check the status of (optional)
if (self::isParametersSet(['department'])) {
self::requireType((int)self::getParameter('department'), self::type_int());
$department = (int)self::getParameter('department');
self::requireMinValue($department, 1);
self::requireMaxValue($department, 999999);
// Check if the department exists
$department_o = new departments_o();
$department_o->select($department);
if (!$department_o->exists()) {
$response->error('Department not found', 404);
}
} else {
$department = null;
}
// Validate the registration number
$this->validateRegistrationNumber($reg, $response);
$customer_vehicles_o = new customer_vehicles_o();
/** Determine the statuses of the vehicle */
$isVerified = $customer_vehicles_o->countRowsWhere(
[
'reg' => $reg,
]
) > 0;
$isKnown = (new orders_o())->countRowsWhere(
[
'reg_1' => $reg,
]
) > 1; // We need to go above one, as the current order will also be counted
$isBooked = (new bookings_o())->countRowsWhere(
[
'regNrTraekker' => $reg,
'status' => 'pending',
...($department ? ['department' => $department] : []), // Filter by department if set
]
) > 0;
// Check if the customer is barred (only if the vehicle is verified)
$customer_number = $isVerified ? ($customer_vehicles_o->getFieldsWhere(
[
'reg' => $reg,
],
['customer_id']
)) : null;
$customer_number = $customer_number ? (int)$customer_number[0]['customer_id'] : null;
$cardPaymentRequired = ($customer_number && (new users_o())->isCustomerBarred((int)$customer_number));
$last_order = $customer_vehicles_o->getLastOrderByPlate($reg);
$response->success([
'department' => $department,
'reg' => $reg,
'verified' => $isVerified,
'known' => $isKnown,
'booked' => $isBooked,
'card' => $cardPaymentRequired,
'unknown' => !$customer_number && !$isKnown && !$isBooked,
'last_order_id' => $last_order?->id ?? null,
]);
},
[
'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);
$department = null;
// If department is set, validate it
if (self::isParametersSet(['department'])) {
$department = (int)self::getParameter('department');
self::requireType($department, self::type_int());
self::requireMinValue($department, 1);
self::requireMaxValue($department, 999999);
// Check if the department exists
$department_o = new departments_o();
$department_o->select($department);
if (!$department_o->exists()) {
$response->error('Department not found', 404);
}
self::requireDepartmentAccess($department);
}
// Strip the search term of whitespace
$search = preg_replace('/\s+/', '', $search);
/** Get the different lists of registration numbers */
$options = ['limit' => 10];
$booked_filters = [...($department ? ['department' => $department] : [])];
$verified_regs = self::getVerifiedRegs($search, $options);
$known_regs = self::getKnownRegs($search, $options);
$booked_regs = self::getBookedRegs($search, $options, $booked_filters);
$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']);
* }
*/
// Get the booking
$booking = (new order_bookings_o())->getFieldsWhere([
'reg_1' => $reg,
'order_id' => null,
'deleted_at' => null,
], ['id', 'customer_number', 'reference', 'note']);
// If there is no booking with the tractor reg, check the trailer reg
if (!$booking) {
$booking = (new order_bookings_o())->getFieldsWhere([
'reg_2' => $reg,
'order_id' => null,
'deleted_at' => null,
], ['id', 'customer_number', 'reference', 'note']);
}
// 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'] : null;
$notes = $booking ? (string)$booking[0]['note'] : 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';
// Check if the vehicle previously only has been set to a specific customer, and if so, get the customer name
$orders_o = new orders_o();
$order = $orders_o->getFieldsWhere([
'reg_1' => $reg,
'deleted_at' => null, // Only consider non-deleted orders
], ['customer_id']);
$customer_ids = array_unique(array_map(function ($row) {
return (int)$row['customer_id'];
}, $order));
if (count($customer_ids) === 1) {
$customer_number = $customer_ids[0];
// Check if the customer is barred (only if known)
if ($customer_number && (new users_o())->isCustomerBarred((int)$customer_number)) {
$status = 'unknown'; // If the customer is barred, we set the status to unknown (as we don't need to know about barred known vehicles)
$customer_number = null; // Clear the customer number as well
}
} else {
// Set the customer name to multiple known customers
$customer_name = 'Multiple known customers';
}
} 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 $filters = []): array
{
$bookings_o = new order_bookings_o();
/**
* $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
* );
*/
$results1 = $bookings_o->getFieldsWhereContaining(
[
'reg_1' => $search,
'order_id' => null,
'deleted_at' => null,
...$filters
],
['reg_1'],
$options
);
$results2 = $bookings_o->getFieldsWhereContaining(
[
'reg_2' => $search,
'order_id' => null,
'deleted_at' => null,
...$filters
],
['reg_2'],
$options
);
return array_unique(array_merge(
array_map(function ($row) {
return (string)$row['reg_1'];
}, $results1),
array_map(function ($row) {
return (string)$row['reg_2'];
}, $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)
{
if (!isset($data['type'])) {
$response->error('Type is required', 400);
}
if (!isset($data['reg'])) {
$response->error('Registration number is required', 400);
}
if (!isset($data['notes'])) {
$response->error('Notes is required', 400);
}
return $data;
}
private function validateRegistrationNumber(mixed $reg, $response): void
{
if (!preg_match('/^[A-Z0-9]{4,10}$/', $reg)) {
$response->error('Invalid registration number, it must be 4-10 characters long, and only contain uppercase letters and numbers', 400);
}
}
private function validateType(mixed $type, $response): void
{
// Make sure the type is more than 2 characters
if (strlen($type) < 2) {
$response->error('Type is too short, it must be at least 2 characters', 400);
}
// Make sure the type is less than 50 characters
if (strlen($type) > 50) {
$response->error('Type is too long, it must be less than 50 characters', 400);
}
}
private function validateNotes(mixed $notes, $response): void
{
// If the notes are set, make sure they are less than 250 characters
if (isset($notes) && strlen($notes) > 250) {
$response->error('Notes are too long, they must be less than 250 characters', 400);
}
}
}