From 1b914b546e601ac24d8d2cca1006e8cc40dc8f84 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Mon, 8 Dec 2025 23:05:35 +0100 Subject: [PATCH] Add minute-based billing and lane management extensions to self-serve module - Introduced `selfserve_lane_command_arguments` class for managing lane command parameters (e.g., customer number, license plate). - Added traits for handling lane timer, invoice generation, license plate, and customer number management. - Implemented minute-based billing logic with `selfserve_minute_product_c` configuration. - Enhanced `selfserve_lane` with new behaviors: command arguments, invoicing, and time handling. - Added `/modules/self-serve/lane/command` route for executing lane commands (START, STOP, RESET). - Updated `/modules/self-serve/lane/status` route to include additional lane details (wash start, elapsed time, license plate, etc.). - Improved Shelly device relay control for port management. --- services/nginx/app/classes/response.php | 18 +++++ services/nginx/app/classes/selfserve.php | 5 ++ .../selfserve/classes/selfserve_lane.php | 18 ++++- .../selfserve_lane_command_arguments.php | 39 ++++++++++ .../config/selfserve_minute_product_c.php | 29 ++++++++ .../helpers/selfserve_lane_command.php | 10 +++ .../app/modules/selfserve/selfserve_c.php | 11 ++- .../traits/selfserve_lane_cache_t.php | 4 + .../traits/selfserve_lane_command_t.php | 33 +++++++-- .../selfserve_lane_customer_number_t.php | 40 ++++++++++ .../traits/selfserve_lane_invoice_t.php | 73 +++++++++++++++++++ .../traits/selfserve_lane_license_plate_t.php | 40 ++++++++++ .../selfserve_lane_port_controller_t.php | 45 +++++++++++- .../traits/selfserve_lane_timer_t.php | 53 ++++++++++++++ .../nginx/app/routes/moduleConfigRoute.php | 31 ++++++++ .../nginx/app/routes/moduleSelfServeRoute.php | 59 +++++++++++++-- services/nginx/app/tests/HTTP/self-serve.http | 32 ++++++++ services/nginx/app/traits/route_t.php | 10 +++ 18 files changed, 533 insertions(+), 17 deletions(-) create mode 100644 services/nginx/app/modules/selfserve/classes/selfserve_lane_command_arguments.php create mode 100644 services/nginx/app/modules/selfserve/config/selfserve_minute_product_c.php create mode 100644 services/nginx/app/modules/selfserve/traits/selfserve_lane_customer_number_t.php create mode 100644 services/nginx/app/modules/selfserve/traits/selfserve_lane_invoice_t.php create mode 100644 services/nginx/app/modules/selfserve/traits/selfserve_lane_license_plate_t.php create mode 100644 services/nginx/app/modules/selfserve/traits/selfserve_lane_timer_t.php create mode 100644 services/nginx/app/tests/HTTP/self-serve.http diff --git a/services/nginx/app/classes/response.php b/services/nginx/app/classes/response.php index c845f26d..04926526 100644 --- a/services/nginx/app/classes/response.php +++ b/services/nginx/app/classes/response.php @@ -160,6 +160,24 @@ class response implements response_i return $data[$key] ?? null; } + /** + * Get all request parameters + * @return array + */ + public function getAllRequestParameters(): array + { + $data = []; + // Get the request data if the method is POST, PUT or PATCH + if ($_SERVER['REQUEST_METHOD'] === 'POST' || $_SERVER['REQUEST_METHOD'] === 'PUT' || $_SERVER['REQUEST_METHOD'] === 'PATCH') { + $data = json_decode(file_get_contents('php://input'), true); + } + // Get the request data if the method is GET, DELETE or OPTIONS + if ($_SERVER['REQUEST_METHOD'] === 'GET' || $_SERVER['REQUEST_METHOD'] === 'DELETE' || $_SERVER['REQUEST_METHOD'] === 'OPTIONS') { + $data = $_GET; + } + return $data; + } + /** * This function checks if a request parameter is set. * This is different from getRequestParameter because this function allows for empty & null values. diff --git a/services/nginx/app/classes/selfserve.php b/services/nginx/app/classes/selfserve.php index aac0632e..1b86972e 100644 --- a/services/nginx/app/classes/selfserve.php +++ b/services/nginx/app/classes/selfserve.php @@ -29,6 +29,11 @@ class selfserve implements universal_module_i $this->config = new selfserve_c(); } + public static function getInstance(): self + { + return new self(); + } + public function lane(int $lane_id): selfserve_lane { return new selfserve_lane($lane_id); diff --git a/services/nginx/app/modules/selfserve/classes/selfserve_lane.php b/services/nginx/app/modules/selfserve/classes/selfserve_lane.php index 1b8df851..e5b96874 100644 --- a/services/nginx/app/modules/selfserve/classes/selfserve_lane.php +++ b/services/nginx/app/modules/selfserve/classes/selfserve_lane.php @@ -8,14 +8,22 @@ require_once WD . '/modules/selfserve/traits/selfserve_lane_state_t.php'; require_once WD . '/modules/selfserve/traits/selfserve_lane_status_t.php'; require_once WD . '/modules/selfserve/traits/selfserve_lane_port_controller_t.php'; require_once WD . '/modules/selfserve/traits/selfserve_lane_command_t.php'; +require_once WD . '/modules/selfserve/traits/selfserve_lane_timer_t.php'; +require_once WD . '/modules/selfserve/traits/selfserve_lane_license_plate_t.php'; +require_once WD . '/modules/selfserve/traits/selfserve_lane_customer_number_t.php'; +require_once WD . '/modules/selfserve/traits/selfserve_lane_invoice_t.php'; use modules\selfserve\interfaces\selfserve_lane_i; use modules\selfserve\traits\selfserve_lane_cache_t; use modules\selfserve\traits\selfserve_lane_command_t; +use modules\selfserve\traits\selfserve_lane_customer_number_t; +use modules\selfserve\traits\selfserve_lane_invoice_t; +use modules\selfserve\traits\selfserve_lane_license_plate_t; use modules\selfserve\traits\selfserve_lane_mode_t; use modules\selfserve\traits\selfserve_lane_port_controller_t; use modules\selfserve\traits\selfserve_lane_state_t; use modules\selfserve\traits\selfserve_lane_status_t; +use modules\selfserve\traits\selfserve_lane_timer_t; class selfserve_lane implements selfserve_lane_i { @@ -24,7 +32,11 @@ class selfserve_lane implements selfserve_lane_i selfserve_lane_state_t, selfserve_lane_cache_t, selfserve_lane_port_controller_t, - selfserve_lane_command_t; + selfserve_lane_command_t, + selfserve_lane_timer_t, + selfserve_lane_license_plate_t, + selfserve_lane_customer_number_t, + selfserve_lane_invoice_t; /** * @throws \Exception @@ -33,6 +45,10 @@ class selfserve_lane implements selfserve_lane_i { $this->id = $lane_id; $this->department_lane = (new \objects\department_lanes_o())->select($lane_id); + // Raise exception if department lane not found + if (!$this->department_lane->exists()) { + throw new \Exception("Department lane not found for lane ID {$lane_id}"); + } } /** diff --git a/services/nginx/app/modules/selfserve/classes/selfserve_lane_command_arguments.php b/services/nginx/app/modules/selfserve/classes/selfserve_lane_command_arguments.php new file mode 100644 index 00000000..0e41eb93 --- /dev/null +++ b/services/nginx/app/modules/selfserve/classes/selfserve_lane_command_arguments.php @@ -0,0 +1,39 @@ +license_plate = $license_plate ? strtoupper(trim($license_plate)) : null; + return $this; + } + + public function setCustomerNumber(?int $customer_number): self + { + $this->customer_number = $customer_number; + return $this; + } + + public function setParameters($params): self + { + if (is_array($params)) { + if (array_key_exists('license_plate', $params)) { + $this->setLicensePlate($params['license_plate']); + } + if (array_key_exists('customer_number', $params)) { + $this->setCustomerNumber($params['customer_number']); + } + } + return $this; + } +} \ No newline at end of file diff --git a/services/nginx/app/modules/selfserve/config/selfserve_minute_product_c.php b/services/nginx/app/modules/selfserve/config/selfserve_minute_product_c.php new file mode 100644 index 00000000..07d666ab --- /dev/null +++ b/services/nginx/app/modules/selfserve/config/selfserve_minute_product_c.php @@ -0,0 +1,29 @@ + selfserve_lane_command::START, + 'STOP' => selfserve_lane_command::STOP, + 'RESET' => selfserve_lane_command::RESET, + default => null, + }; + } + public function equals(selfserve_lane_command $command): bool { return $this === $command; diff --git a/services/nginx/app/modules/selfserve/selfserve_c.php b/services/nginx/app/modules/selfserve/selfserve_c.php index 14563dc3..cb12fbd5 100644 --- a/services/nginx/app/modules/selfserve/selfserve_c.php +++ b/services/nginx/app/modules/selfserve/selfserve_c.php @@ -2,8 +2,10 @@ namespace modules\selfserve; require_once WD . '/modules/selfserve/config/selfserve_enabled_c.php'; +require_once WD . '/modules/selfserve/config/selfserve_minute_product_c.php'; use modules\selfserve\config\selfserve_enabled_c; +use modules\selfserve\config\selfserve_minute_product_c; use traits\module_config_t; class selfserve_c @@ -15,13 +17,20 @@ class selfserve_c * @var selfserve_enabled_c $enabled */ public selfserve_enabled_c $enabled; + /** + * The product ID used for minute-based self-serve billing + * @var selfserve_minute_product_c $minute_product + */ + public selfserve_minute_product_c $minute_product; public function __construct() { $this->setupConfig('selfserve'); $this->allowUpdate([ - selfserve_enabled_c::class + selfserve_enabled_c::class, + selfserve_minute_product_c::class ]); $this->enabled = new selfserve_enabled_c(); + $this->minute_product = new selfserve_minute_product_c(); } } \ No newline at end of file diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_cache_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_cache_t.php index 41780fd3..385e6148 100644 --- a/services/nginx/app/modules/selfserve/traits/selfserve_lane_cache_t.php +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_cache_t.php @@ -11,6 +11,10 @@ trait selfserve_lane_cache_t const CACHE_SELFSERVE_LANE_KEY_STATUS = self::CACHE_SELFSERVE_PREFIX . 'status'; const CACHE_SELFSERVE_LANE_KEY_STATE = self::CACHE_SELFSERVE_PREFIX . 'state'; const CACHE_SELFSERVE_LANE_KEY_MODE = self::CACHE_SELFSERVE_PREFIX . 'mode'; + const CACHE_SELFSERVE_LANE_KEY_WASH_START_TIME = self::CACHE_SELFSERVE_PREFIX . 'wash_start_time'; + const CACHE_SELFSERVE_LANE_KEY_CUSTOMER_NUMBER = self::CACHE_SELFSERVE_PREFIX . 'customer_number'; + const CACHE_SELFSERVE_LANE_KEY_LICENSE_PLATE = self::CACHE_SELFSERVE_PREFIX . 'license_plate'; + /** * Get the cache key for the lane diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_command_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_command_t.php index 470137a1..a231fe73 100644 --- a/services/nginx/app/modules/selfserve/traits/selfserve_lane_command_t.php +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_command_t.php @@ -7,52 +7,71 @@ require_once WD . '/modules/selfserve/helpers/selfserve_lane_command.php'; require_once WD . '/modules/selfserve/helpers/selfserve_lane_mode.php'; require_once WD . '/modules/selfserve/helpers/selfserve_lane_port.php'; require_once WD . '/modules/selfserve/helpers/selfserve_lane_state.php'; +require_once WD . '/modules/selfserve/classes/selfserve_lane_command_arguments.php'; use Exception; use modules\selfserve\classes\selfserve_lane; +use modules\selfserve\classes\selfserve_lane_command_arguments; use modules\selfserve\helpers\selfserve_lane_command; use modules\selfserve\helpers\selfserve_lane_mode; use modules\selfserve\helpers\selfserve_lane_port; use modules\selfserve\helpers\selfserve_lane_state; use modules\selfserve\helpers\selfserve_lane_status; +use objects\users_o; trait selfserve_lane_command_t { /** * Execute a command on a self-serve lane * @param selfserve_lane_command $command The command to execute + * @param selfserve_lane_command_arguments $arguments The arguments for the command * @return selfserve_lane|selfserve_lane_command_t * @throws Exception If the command cannot be executed */ - public function execute(selfserve_lane_command $command): self + public function execute(selfserve_lane_command $command, selfserve_lane_command_arguments $arguments): self { // Handle the command switch ($command) { case selfserve_lane_command::START: // Require lane to be available before starting if (!$this->getLaneStatus()->equals(selfserve_lane_status::AVAILABLE)) throw new \RuntimeException("Cannot start lane: Lane is not available."); + // Require the customer number + if (empty($customer_number = $arguments->customer_number)) throw new \InvalidArgumentException("Customer number is required to start the lane."); + // Require the license plate + if (empty($license_plate = $arguments->license_plate)) throw new \InvalidArgumentException("License plate is required to start the lane."); + // Validate customer number + if (!is_numeric($customer_number) || (int)$customer_number <= 0) throw new \InvalidArgumentException("Invalid customer number: " . $customer_number); + if (!(new users_o())->getUserByCustomerNumber((int)$customer_number)->exists()) throw new \InvalidArgumentException("Customer number does not exist: " . $customer_number); + // Set the customer number and license plate + $this->setCustomerNumber($customer_number); + $this->setLicensePlate($license_plate); // Set the lane status to OCCUPIED when started $this->setLaneStatus(selfserve_lane_status::OCCUPIED); - // Open the entrance port - $this->open(selfserve_lane_port::ENTRANCE); // Set the lane state to IN_WASH $this->setLaneState(selfserve_lane_state::IN_WASH); + // Open the entrance port + $this->open(selfserve_lane_port::ENTRANCE); + // Start the wash timer + $this->setWashStartTime(time()); break; case selfserve_lane_command::STOP: // Require lane to be occupied before stopping if (!$this->getLaneStatus()->equals(selfserve_lane_status::OCCUPIED)) throw new \RuntimeException("Cannot stop lane: Lane is not occupied."); - // Set the lane status to AVAILABLE when stopped - $this->setLaneStatus(selfserve_lane_status::AVAILABLE); + // Invoice the customer + $this->invoice(); // Open the exit port $this->open(selfserve_lane_port::EXIT); - // Set the lane state to IDLE - $this->setLaneState(selfserve_lane_state::IDLE); + // Reset the lane + self::execute(selfserve_lane_command::RESET, new selfserve_lane_command_arguments()); break; case selfserve_lane_command::RESET: // Reset the lane to default states $this->setLaneStatus(selfserve_lane_status::AVAILABLE); $this->setLaneMode(selfserve_lane_mode::MANUAL); $this->setLaneState(selfserve_lane_state::IDLE); + $this->setWashStartTime(self::DEFAULT_WASH_START_TIME); + $this->setCustomerNumber(self::DEFAULT_CUSTOMER_NUMBER); + $this->setLicensePlate(self::DEFAULT_LICENSE_PLATE); break; default: throw new \InvalidArgumentException("Unknown command: " . $command->name); diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_customer_number_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_customer_number_t.php new file mode 100644 index 00000000..de21dd12 --- /dev/null +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_customer_number_t.php @@ -0,0 +1,40 @@ +getLaneCache($this->id, self::CACHE_SELFSERVE_LANE_KEY_CUSTOMER_NUMBER); + if (!empty($customer_number)) { + $this->customer_number = $customer_number; + } + return $this->customer_number; + } + /** + * Set the customer number associated with the current wash + * @param int|null $customer_number The customer number, or null to clear + * @return selfserve_lane_customer_number_t|selfserve_lane + */ + public function setCustomerNumber(?int $customer_number): self + { + $this->customer_number = $customer_number; + $this->setLaneCache($this->id, self::CACHE_SELFSERVE_LANE_KEY_CUSTOMER_NUMBER, $this->customer_number); + return $this; + } +} \ No newline at end of file diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_invoice_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_invoice_t.php new file mode 100644 index 00000000..956fbfd5 --- /dev/null +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_invoice_t.php @@ -0,0 +1,73 @@ +config + ->minute_product + ->getVariableValue(); + if (!empty($minute_billing_product_id)) { + $this->minute_billing_product_id = $minute_billing_product_id; + } + return $this->minute_billing_product_id; + } + + /** + * Invoice for minute-based billing + * @return bool True on success, false on failure + * @throws Exception if lane ID is not set, lane is not occupied, customer number or license plate is not set, or product ID is not set + */ + public function invoice(): bool + { + if (empty($this->id)) throw new \Exception("Lane ID is not set."); + if ($this->getLaneStatus() !== selfserve_lane_status::OCCUPIED) throw new \Exception("Lane ID {$this->id} is not occupied; cannot invoice."); + if (empty($this->getCustomerNumber())) throw new \Exception("Customer number is not set for lane ID {$this->id}."); + if (empty($this->getLicensePlate())) throw new \Exception("License plate is not set for lane ID {$this->id}."); + if (empty($product_id = $this->getMinuteBillingProductId())) throw new \Exception("Minute billing product ID is not set."); + // Calculate minutes used + $minutes = $this->getElapsedWashTime() / 60; // Convert seconds to minutes + $minutes = (int)ceil($minutes); // Round up to nearest whole minute + if ($minutes <= 0) throw new \Exception("No minutes to bill for lane ID {$this->id}."); + $amount = $minutes; // Assuming 1 unit per minute, adjust as needed + // Create invoice order + $order = (new orders_o())->add( + $this->getCustomerNumber(), + 2285, // System User ID + '', + '', + $this->department_lane->department->id, + $this->getLicensePlate() + ); + // Add product to order + $order_items = new order_items_o(); + $order_items->addItemToOrder( + $order->id, + $product_id, + 2285, // System User ID + $amount, + ); + return true; + } +} \ No newline at end of file diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_license_plate_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_license_plate_t.php new file mode 100644 index 00000000..719a1303 --- /dev/null +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_license_plate_t.php @@ -0,0 +1,40 @@ +getLaneCache($this->id, self::CACHE_SELFSERVE_LANE_KEY_LICENSE_PLATE); + if (!empty($license_plate)) { + $this->license_plate = $license_plate; + } + return $this->license_plate; + } + /** + * Set the license plate of the vehicle currently in the lane + * @param string|null $license_plate The license plate, or null to clear + * @return selfserve_lane_license_plate_t|selfserve_lane + */ + public function setLicensePlate(?string $license_plate): self + { + $this->license_plate = $license_plate; + $this->setLaneCache($this->id, self::CACHE_SELFSERVE_LANE_KEY_LICENSE_PLATE, $this->license_plate); + return $this; + } +} \ No newline at end of file diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_port_controller_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_port_controller_t.php index 636c8e64..23110899 100644 --- a/services/nginx/app/modules/selfserve/traits/selfserve_lane_port_controller_t.php +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_port_controller_t.php @@ -4,11 +4,12 @@ namespace modules\selfserve\traits; require_once WD . '/modules/selfserve/helpers/selfserve_lane_port.php'; require_once WD . '/modules/selfserve/classes/selfserve_lane.php'; -use modules\selfserve\helpers\selfserve_lane_mode; +use classes\shelly; use modules\selfserve\helpers\selfserve_lane_port; -use modules\selfserve\classes\selfserve_lane; use modules\selfserve\helpers\selfserve_lane_state; use modules\selfserve\helpers\selfserve_lane_status; +use modules\shelly\helpers\shelly_device_switch; +use modules\shelly\helpers\shelly_request_body_get_states; trait selfserve_lane_port_controller_t { @@ -43,8 +44,46 @@ trait selfserve_lane_port_controller_t default => throw new \Exception("Invalid port specified, must be ENTRANCE or EXIT"), }; $this->setLaneState($new_state); - // TODO: Open the relay here + // Open the relay + $this->shellyOpenPort($port); + return true; + } + /** + * Open the Shelly relay for the specified port + * @param selfserve_lane_port $port The port to open (ENTRANCE or EXIT) + * @return bool True if the relay was successfully opened + * @throws \Exception If an invalid port is specified or if the relay ID is invalid + */ + public function shellyOpenPort(selfserve_lane_port $port): bool + { + // Get the relay ID based on the port + $relay_id = match ($port) { + selfserve_lane_port::ENTRANCE => $this->department_lane->relay_out_id->value(), + selfserve_lane_port::EXIT => $this->department_lane->relay_in_id->value(), + default => throw new \Exception("Invalid port specified, must be ENTRANCE or EXIT"), + }; + // Make sure relay ID is valid + if (empty($relay_id)) { + throw new \Exception("Invalid relay ID for port {$port->name}"); + } + $shelly = new shelly(); + $shelly->requireModuleEnabled(); + $shelly->requireValidSecretKey(); + $parameters = new shelly_request_body_get_states(); + $parameters->ids = [$relay_id]; + $parameters->select = ['status']; + $result = $shelly->sendPostRequest('/v2/devices/api/get', (array)$parameters); + // Wait 1 second + sleep(1); + // Format the result + $result = array_map(function ($device) { + return (new shelly_device_switch())->populate($device); + }, $result); + // Open the switch + foreach ($result as $device) { + $device->switch(true); + } return true; } } \ No newline at end of file diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_timer_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_timer_t.php new file mode 100644 index 00000000..ce782e5f --- /dev/null +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_timer_t.php @@ -0,0 +1,53 @@ +getLaneCache($this->id, self::CACHE_SELFSERVE_LANE_KEY_WASH_START_TIME); + if (!empty($wash_start_time)) { + $this->wash_start_time = $wash_start_time; + } + return $this->wash_start_time; + } + /** + * Set the wash start time + * @param int|null $timestamp The timestamp of the start of the current wash cycle, or null to clear + * @return selfserve_lane_timer_t|selfserve_lane + */ + public function setWashStartTime(?int $timestamp): self + { + $this->wash_start_time = $timestamp; + $this->setLaneCache($this->id, self::CACHE_SELFSERVE_LANE_KEY_WASH_START_TIME, $this->wash_start_time); + return $this; + } + + /** + * Get the elapsed time since the wash started + * @return int|null The elapsed time in seconds since the wash started, or null if wash has not started + */ + public function getElapsedWashTime(): ?int + { + $wash_start_time = $this->getWashStartTime(); + if ($wash_start_time === null) { + return null; // Wash has not started + } + return time() - $wash_start_time; + } +} \ No newline at end of file diff --git a/services/nginx/app/routes/moduleConfigRoute.php b/services/nginx/app/routes/moduleConfigRoute.php index 3252628f..94936561 100644 --- a/services/nginx/app/routes/moduleConfigRoute.php +++ b/services/nginx/app/routes/moduleConfigRoute.php @@ -669,5 +669,36 @@ class moduleConfigRoute (new logs_o())->add('shelly_config', 'global', 1, 0, 'SHELLY_CONFIG', 'No user found, or invalid session'); } }); + /** Self-Serve config -> GET */ + $this->get('/selfserve/config', function () { + global $response; + $this->requirePermission('modules_selfserve_config'); + $user = (new authentication())->get_user(); + if ($user) { + (new logs_o())->add('selfserve_config', 'global', 1, $user->id, 'SELFSERVE_CONFIG', 'Successfully fetched self-serve config'); + $response->success( + (new \classes\selfserve())->config->getConfigRequest() + ); + } else { + (new logs_o())->add('selfserve_config', 'global', 1, 0, 'SELFSERVE_CONFIG', 'No user found, or invalid session'); + } + }, + [ + 'modules_selfserve_config' => 'Get self-serve config' + ] + ); + $this->post('/selfserve/config', function () { + global $response; + $this->requirePermission('modules_selfserve_config'); + $user = (new authentication())->get_user(); + if ($user) { + (new logs_o())->add('selfserve_config', 'global', 1, $user->id, 'SELFSERVE_CONFIG', 'Successfully updated self-serve config'); + $response->success( + (new \classes\selfserve())->config->postConfigRequest() + ); + } else { + (new logs_o())->add('selfserve_config', 'global', 1, 0, 'SELFSERVE_CONFIG', 'No user found, or invalid session'); + } + }); } } \ No newline at end of file diff --git a/services/nginx/app/routes/moduleSelfServeRoute.php b/services/nginx/app/routes/moduleSelfServeRoute.php index 42a187b3..164cc683 100644 --- a/services/nginx/app/routes/moduleSelfServeRoute.php +++ b/services/nginx/app/routes/moduleSelfServeRoute.php @@ -28,18 +28,67 @@ class moduleSelfServeRoute /** Modules > Self Serve > Lane > Status */ $this->get('/modules/self-serve/lane/status', function () { global $response; - //TODO: self::requirePermission('modules_selfserve_lane_status_view'); + self::requirePermission('modules_selfserve_lane_status_view'); $selfserve = new selfserve(); + $lane = $selfserve->lane(1); $response->success([ - 'id' => $selfserve->lane(1)->id, - 'status' => $selfserve->lane(1)->getLaneStatus()->name, - 'mode' => $selfserve->lane(1)->getLaneMode()->name, - 'state' => $selfserve->lane(1)->getLaneState()->name, + 'id' => $lane->id, + 'status' => $lane->getLaneStatus()->name, + 'mode' => $lane->getLaneMode()->name, + 'state' => $lane->getLaneState()->name, + 'wash_start_time' => $lane->getWashStartTime(), + 'elapsed_wash_time' => $lane->getElapsedWashTime(), + 'license_plate' => $lane->getLicensePlate(), + 'customer_number' => $lane->getCustomerNumber(), ]); }, [ 'modules_selfserve_lane_status_view' => 'View self-serve lane status', ] ); + + /** Modules > Self Serve > Lane > Command */ + $this->post('/modules/self-serve/lane/command', function () { + global $response; + self::requirePermission('modules_selfserve_lane_command_execute'); + $selfserve = new selfserve(); + $param_lane_id = 'lane_id'; + $param_command = 'command'; + // Validate parameters + self::requireParameters([$param_lane_id, $param_command]); + $lane_id = (int)$this->getParameter($param_lane_id); + self::requireType($lane_id, self::type_int()); + self::requireMinValue($lane_id, 1); + $commandParam = (string)$this->getParameter($param_command); + self::requireType($commandParam, self::type_string()); + // Get the lane and command + $lane = $selfserve->lane($lane_id); + $command = \modules\selfserve\helpers\selfserve_lane_command::tryFrom($commandParam); + if ($command === null) { + $response->error("Invalid command: " . $commandParam); + } + // Execute the command + try { + $args = new \modules\selfserve\classes\selfserve_lane_command_arguments(); + $args->setParameters($this->getParametersAsArray()); + $lane->execute($command, $args); + $response->success([ + 'id' => $lane->id, + 'status' => $lane->getLaneStatus()->name, + 'mode' => $lane->getLaneMode()->name, + 'state' => $lane->getLaneState()->name, + 'wash_start_time' => $lane->getWashStartTime(), + 'elapsed_wash_time' => $lane->getElapsedWashTime(), + 'license_plate' => $lane->getLicensePlate(), + 'customer_number' => $lane->getCustomerNumber(), + ]); + } catch (\Exception $e) { + $response->error("Failed to execute command: " . $e->getMessage()); + } + }, + [ + 'modules_selfserve_lane_command_execute' => 'Execute self-serve lane command', + ] + ); } } \ No newline at end of file diff --git a/services/nginx/app/tests/HTTP/self-serve.http b/services/nginx/app/tests/HTTP/self-serve.http new file mode 100644 index 00000000..a8015f5c --- /dev/null +++ b/services/nginx/app/tests/HTTP/self-serve.http @@ -0,0 +1,32 @@ +### POST /modules/self-serve/lane/command START +POST https://api.truckwash.dk:4433/modules/self-serve/lane/command +Accept: application/json +Content-Type: application/json + +{ + "command": "START", + "customer_number": 12345679, + "license_plate": "AB12345", + "lane_id": 1 +} + + +### POST /modules/self-serve/lane/command STOP +POST https://api.truckwash.dk:4433/modules/self-serve/lane/command +Accept: application/json +Content-Type: application/json + +{ + "command": "STOP", + "lane_id": 1 +} + +### POST /modules/self-serve/lane/command RESET +POST https://api.truckwash.dk:4433/modules/self-serve/lane/command +Accept: application/json +Content-Type: application/json + +{ + "command": "RESET", + "lane_id": 1 +} \ No newline at end of file diff --git a/services/nginx/app/traits/route_t.php b/services/nginx/app/traits/route_t.php index 2a897397..c714e578 100644 --- a/services/nginx/app/traits/route_t.php +++ b/services/nginx/app/traits/route_t.php @@ -249,6 +249,16 @@ trait route_t return self::hasPermission('department_access_' . $department . ($permission ? '_' . $permission : '')); } + /** + * Get parameters as an array from the request + * @return array + */ + public function getParametersAsArray(): array + { + global $response; + return $response->getAllRequestParameters(); + } + /** * Require permission * @param string $permission