From b837f572af0df2f399a79fa9a7157cd3757d26d7 Mon Sep 17 00:00:00 2001 From: Jepp9350 <2jepp9350@gmail.com> Date: Thu, 22 May 2025 22:51:05 +0200 Subject: [PATCH] Add handling for forced prices, arrays, and improved type checks Introduced support for forced pricing in `addItemToOrder` and added stricter validation for array inputs in SQL queries. Enhanced JSON handling in type validation and improved code reuse with new objects. Added new endpoint `/modules/xlvask/related-orders` to fetch related orders by wash IDs. --- services/nginx/app/objects/order_items_o.php | 7 +++- .../nginx/app/routes/moduleXLVaskRoute.php | 35 +++++++++++++++++++ services/nginx/app/routes/orderItemsRoute.php | 14 +++++++- services/nginx/app/routes/ordersRoute.php | 17 ++++++--- services/nginx/app/traits/db_object_t.php | 14 ++++++++ services/nginx/app/traits/route_t.php | 7 +++- 6 files changed, 87 insertions(+), 7 deletions(-) diff --git a/services/nginx/app/objects/order_items_o.php b/services/nginx/app/objects/order_items_o.php index d33fb6f9..6db043a6 100644 --- a/services/nginx/app/objects/order_items_o.php +++ b/services/nginx/app/objects/order_items_o.php @@ -137,7 +137,7 @@ class order_items_o extends db } } - public function addItemToOrder(int $order_id, int $product_id, int $cashier_id, int $quantity, $related_item_id = null, $notes = null): void + public function addItemToOrder(int $order_id, int $product_id, int $cashier_id, int $quantity, $related_item_id = null, $notes = null, $forcePrice = null): void { global $db, $response; try { @@ -153,6 +153,11 @@ class order_items_o extends db $price = $price - ($price * $discount / 100); } + // If the price is forced, set the price to the forced price + if ($forcePrice) { + $price = (int)$forcePrice; + } + // Create a new record in the database $sql = "INSERT INTO $this->table (order_id, product_id, price, cashier_id, quantity) VALUES ($order_id, $product_id, $price, $cashier_id, $quantity)"; $db->query($sql); diff --git a/services/nginx/app/routes/moduleXLVaskRoute.php b/services/nginx/app/routes/moduleXLVaskRoute.php index 1c35916b..a9c41035 100644 --- a/services/nginx/app/routes/moduleXLVaskRoute.php +++ b/services/nginx/app/routes/moduleXLVaskRoute.php @@ -6,6 +6,7 @@ use classes\authentication; use classes\response; use classes\router; use classes\xlvask; +use objects\orders_o; use traits\route_t; class moduleXLVaskRoute @@ -116,5 +117,39 @@ class moduleXLVaskRoute 'modules_xlvask_internal_vehicle_types' => 'Get the vehicle types of the xlvask module' ] ); + + $this->get('/modules/xlvask/related-orders', function () { + global $response; + self::requirePermission('modules_xlvask_related_orders'); + self::requireParameters(['washIds']); + $washIds = self::getParameter('washIds'); + // Check if the washIds is an array + self::requireType($washIds, self::TYPE_ARRAY()); + // Require only strings in the array + foreach ( $washIds as $key => $value ) { + if (!is_string($value)) { + self::requireType($value, self::TYPE_STRING()); + } + } + // Get all the related orders + $orders_o = new orders_o(); + $mathing_orders = $orders_o->getFieldsWhere([ + 'wash_id' => $washIds, + 'deleted_at' => null, + ], [ + 'id', + 'wash_id', + ]); + + $formatted_matches = []; + foreach ( $mathing_orders as $order ) { + $formatted_matches[(string)$order['wash_id']][] = (int)$order['id']; + } + $response->success($formatted_matches, 200); + }, + [ + 'modules_xlvask_related_orders' => 'Get the related orders of the xlvask module' + ] + ); } } \ No newline at end of file diff --git a/services/nginx/app/routes/orderItemsRoute.php b/services/nginx/app/routes/orderItemsRoute.php index 046f6d61..ea6041b4 100644 --- a/services/nginx/app/routes/orderItemsRoute.php +++ b/services/nginx/app/routes/orderItemsRoute.php @@ -57,11 +57,23 @@ class orderItemsRoute $notes = (string)self::getParameter('notes'); } } + $price = null; + // Check if the price is set + if (self::isParametersSet(['price'])) { + // Check if the price is null, if so continue + if (self::getParameter('price') !== null) { + // Check if the price is a number + if (!is_numeric(self::getParameter('price'))) { + $response->error('Price must be a number', 400); + } + $price = (int)self::getParameter('price'); + } + } // Add the order item to the order This is done individually, to make the notes to the individual order items possible $order_items = (new order_items_o()); // Add the order item to the order - $order_items->addItemToOrder((int)$data['order_id'], (int)$data['product_id'], (int)$user->id, (int)$data['quantity'], $related_item_id, $notes); + $order_items->addItemToOrder((int)$data['order_id'], (int)$data['product_id'], (int)$user->id, (int)$data['quantity'], $related_item_id, $notes, $price); // Return the list of departments $response->success( $order_items->getItemAsArray() diff --git a/services/nginx/app/routes/ordersRoute.php b/services/nginx/app/routes/ordersRoute.php index 4c735d10..3e737e33 100644 --- a/services/nginx/app/routes/ordersRoute.php +++ b/services/nginx/app/routes/ordersRoute.php @@ -60,10 +60,13 @@ class ordersRoute $response->success( $orders->listObjectsWithPaginationIfSet( function ($order) { + $order_obj = new orders_o(); + // Get the order object + $order_obj->select((int)$order['id']); // Add the invoice status to the order $order['economic_invoice_module'] = (new economic_module_orders())->getByOrderId($order['id'])->asArray(); // Add the total amount to the order - $order['total_net_amount'] = (new orders_o())->select($order['id'])->getNetAmount(); + $order['total_net_amount'] = $order_obj->getNetAmount(); // Add the stripe status to the order $stripe_module_orders = (new stripe_module_orders_o())->select($order['id']); if ($stripe_module_orders->exists()) { @@ -71,11 +74,13 @@ class ordersRoute } // If the invoice collection is set, add it to the order if (!empty($order['invoice_collection_id'])) { + $collected_order_invoices_obj = new collected_order_invoices_o(); + $collected_order_invoices_obj->select((int)$order['invoice_collection_id']); $order['invoice_collection'] = [ 'id' => $order['invoice_collection_id'], - 'closed_at' => (new collected_order_invoices_o())->select($order['invoice_collection_id'])->closed_at->value(), - 'booked_invoice_id' => (new collected_order_invoices_o())->select($order['invoice_collection_id'])->booked_invoice_id->value() ?? null, - 'processor' => (int)(new collected_order_invoices_o())->select($order['invoice_collection_id'])->processor->value() ?? null, + 'closed_at' => $collected_order_invoices_obj->closed_at->value(), + 'booked_invoice_id' => $collected_order_invoices_obj->booked_invoice_id->value() ?? null, + 'processor' => (int)$collected_order_invoices_obj->processor->value() ?? null, ]; } // Get the customer @@ -207,6 +212,10 @@ class ordersRoute if (isset($data['wash_id'])) { $order->wash_id->set($data['wash_id']); } + // Check if the created_at is set + if (isset($data['created_at'])) { + $order->created_at->set($data['created_at']); + } // If the department ID is set, validate it // Log the incident (new logs_o())->add('orders', $order->department_id->value(), 1, $user->id, 'EDIT_ORDER', 'Successfully updated an order (ID: ' . $data['id'] . ')'); diff --git a/services/nginx/app/traits/db_object_t.php b/services/nginx/app/traits/db_object_t.php index 2c5f987e..8465bdc6 100644 --- a/services/nginx/app/traits/db_object_t.php +++ b/services/nginx/app/traits/db_object_t.php @@ -86,7 +86,21 @@ trait db_object_t // If the value is null, add a where clause to check if the field is null if ($value === null) { $where[] = "$field IS NULL"; + } elseif (is_array($value)) { + // If the value is an array, add a where clause to check if the field is in the array + $in = implode(',', array_map(function ($v) { + // Escape the value to prevent SQL injection + global $db; + return "'" . $db->escape_string($v) . "'"; + }, $value)); + $where[] = "$field IN ($in)"; + } elseif (is_numeric($value)) { + // If the value is numeric, add a where clause to check if the field is equal to the value + $where[] = "$field = $value"; } else { + // Escape the value to prevent SQL injection + global $db; + $value = $db->escape_string($value); $where[] = "$field = '$value'"; } } diff --git a/services/nginx/app/traits/route_t.php b/services/nginx/app/traits/route_t.php index ba6d8fd6..84cc7b67 100644 --- a/services/nginx/app/traits/route_t.php +++ b/services/nginx/app/traits/route_t.php @@ -34,6 +34,11 @@ trait route_t $value_type = gettype($value); // If the type is Array, or Object, json_decode the value to check if it is a valid JSON if ($type === 'array' || $type === 'object') { + if (is_array($value)) { + $value = json_encode($value); + } elseif (is_object($value)) { + $value = json_encode($value); + } $value = json_decode($value, true); if (json_last_error() !== JSON_ERROR_NONE) { global $response; @@ -44,7 +49,7 @@ trait route_t // Check if the value is of the required type if ($value_type !== $type) { global $response; - $response->error('Invalid type. Expected: ' . $type . ' Got: ' . $value_type . ' Value: ' . $value, 400); + $response->error('Invalid type. Expected: ' . $type . ' Got: ' . $value_type . ' Value: ' . (is_array($value) ? json_encode($value) : $value), 400); } return true; }