From 3645f2d9e8a145d637e889fcd15622c42b8a4ac1 Mon Sep 17 00:00:00 2001 From: Shreesh Arora Date: Sun, 5 Mar 2023 13:59:42 +0530 Subject: [PATCH 1/2] added max allowd quantity for service products --- .../controllers/normal_products/informations.tpl | 11 +++++++++++ classes/Product.php | 4 ++++ controllers/admin/AdminOrdersController.php | 2 ++ controllers/front/CartController.php | 2 ++ install/data/db_structure.sql | 2 ++ js/admin/normal_products.js | 8 ++++++++ .../_partials/cart_booking_demands.tpl | 2 +- .../_partials/service-products-list-row.tpl | 2 +- themes/hotel-reservation-theme/js/order-opc.js | 10 ++++++++-- themes/hotel-reservation-theme/js/product.js | 9 ++++++--- 10 files changed, 45 insertions(+), 7 deletions(-) diff --git a/admin/themes/default/template/controllers/normal_products/informations.tpl b/admin/themes/default/template/controllers/normal_products/informations.tpl index f95d974eb..acc85a424 100644 --- a/admin/themes/default/template/controllers/normal_products/informations.tpl +++ b/admin/themes/default/template/controllers/normal_products/informations.tpl @@ -412,6 +412,17 @@ +
available_for_order && $product->isAssociatedToShop()) || $product->auto_add_to_cart || !$product->allow_multiple_quantity}style="display:none;"{/if}> + +
+ +
+
diff --git a/classes/Product.php b/classes/Product.php index 33d169e23..911610672 100644 --- a/classes/Product.php +++ b/classes/Product.php @@ -77,6 +77,9 @@ class ProductCore extends ObjectModel /** @var bool allow order for multiple quantities */ public $allow_multiple_quantity; + /** @var bool max allowed quantities */ + public $max_quantity; + /** @var string available_now */ public $available_now; @@ -308,6 +311,7 @@ class ProductCore extends ObjectModel 'ecotax' => array('type' => self::TYPE_FLOAT, 'shop' => true, 'validate' => 'isPrice'), 'minimal_quantity' => array('type' => self::TYPE_INT, 'shop' => true, 'validate' => 'isUnsignedInt'), 'allow_multiple_quantity' => array('type' => self::TYPE_BOOL, 'shop' => true, 'validate' => 'isBool'), + 'max_quantity' => array('type' => self::TYPE_INT, 'shop' => true, 'validate' => 'isUnsignedInt'), 'price' => array('type' => self::TYPE_FLOAT, 'shop' => true, 'validate' => 'isPrice', 'required' => true), 'wholesale_price' => array('type' => self::TYPE_FLOAT, 'shop' => true, 'validate' => 'isPrice'), 'unity' => array('type' => self::TYPE_STRING, 'shop' => true, 'validate' => 'isString'), diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php index df4af2e8d..d6dc4524d 100644 --- a/controllers/admin/AdminOrdersController.php +++ b/controllers/admin/AdminOrdersController.php @@ -5264,6 +5264,8 @@ class AdminOrdersControllerCore extends AdminController if ($objProduct->allow_multiple_quantity) { if (!Validate::isUnsignedInt($qty)) { $this->errors[] = Tools::displayError('The quantity code you\'ve entered is invalid.'); + // } elseif ($objProduct->max_quantity && $qty > $objProduct->max_quantity) { + // $this->errors[] = Tools::displayError(sprintf('cannot add more than %d quantity.', $objProduct->max_quantity)); } } else { $qty = 1; diff --git a/controllers/front/CartController.php b/controllers/front/CartController.php index a2444c921..7736cc76f 100644 --- a/controllers/front/CartController.php +++ b/controllers/front/CartController.php @@ -621,6 +621,8 @@ class CartControllerCore extends FrontController if ($objProduct->allow_multiple_quantity) { if (!Validate::isUnsignedInt($qty)) { $this->errors[] = Tools::displayError('The quantity you\'ve entered is invalid.'); + } elseif ($objProduct->max_quantity && $qty > $objProduct->max_quantity) { + $this->errors[] = Tools::displayError(sprintf('cannot add more than %d quantity.', $objProduct->max_quantity)); } } else { $qty = 1; diff --git a/install/data/db_structure.sql b/install/data/db_structure.sql index 5bc961640..07a2b4097 100644 --- a/install/data/db_structure.sql +++ b/install/data/db_structure.sql @@ -1519,6 +1519,7 @@ CREATE TABLE `PREFIX_product` ( `quantity` int(10) NOT NULL DEFAULT '0', `minimal_quantity` int(10) unsigned NOT NULL DEFAULT '1', `allow_multiple_quantity` tinyint(1) unsigned NOT NULL DEFAULT '1', + `max_quantity` int(10) unsigned NOT NULL DEFAULT '1', `price` decimal(20,6) NOT NULL DEFAULT '0.000000', `wholesale_price` decimal(20,6) NOT NULL DEFAULT '0.000000', `unity` varchar(255) DEFAULT NULL, @@ -1578,6 +1579,7 @@ CREATE TABLE IF NOT EXISTS `PREFIX_product_shop` ( `ecotax` decimal(17,6) NOT NULL DEFAULT '0.000000', `minimal_quantity` int(10) unsigned NOT NULL DEFAULT '1', `allow_multiple_quantity` tinyint(1) unsigned NOT NULL DEFAULT '1', + `max_quantity` int(10) unsigned NOT NULL DEFAULT '1', `price` decimal(20,6) NOT NULL DEFAULT '0.000000', `wholesale_price` decimal(20,6) NOT NULL DEFAULT '0.000000', `unity` varchar(255) DEFAULT NULL, diff --git a/js/admin/normal_products.js b/js/admin/normal_products.js index abe3db07a..e15945f8b 100644 --- a/js/admin/normal_products.js +++ b/js/admin/normal_products.js @@ -449,6 +449,14 @@ product_tabs['Informations'] = new function(){ } }); + $('input[name=allow_multiple_quantity]').on('change', function(e) { + if ($(this).val() == 1) { + $('#max_quantity_container').show('fast'); + } else { + $('#max_quantity_container').hide('fast'); + } + }); + $('#related_product_autocomplete_input') .autocomplete('ajax_products_list.php?exclude_packs=0&excludeVirtuals=0&excludeIds='+id_product, { minChars: 1, diff --git a/themes/hotel-reservation-theme/_partials/cart_booking_demands.tpl b/themes/hotel-reservation-theme/_partials/cart_booking_demands.tpl index 788ef2cb0..077c3f9fb 100644 --- a/themes/hotel-reservation-theme/_partials/cart_booking_demands.tpl +++ b/themes/hotel-reservation-theme/_partials/cart_booking_demands.tpl @@ -118,7 +118,7 @@

{$product['name']|escape:'html':'UTF-8'}

{if $product.allow_multiple_quantity}
- +
diff --git a/themes/hotel-reservation-theme/_partials/service-products-list-row.tpl b/themes/hotel-reservation-theme/_partials/service-products-list-row.tpl index f700c7720..e2474c0d6 100644 --- a/themes/hotel-reservation-theme/_partials/service-products-list-row.tpl +++ b/themes/hotel-reservation-theme/_partials/service-products-list-row.tpl @@ -50,7 +50,7 @@ {/if} {if $product.allow_multiple_quantity && $product.available_for_order}
- +
{if isset($product.quantity_added) && $product.quantity_added}{$product.quantity_added|escape:'html':'UTF-8'}{else}1{/if}
diff --git a/themes/hotel-reservation-theme/js/order-opc.js b/themes/hotel-reservation-theme/js/order-opc.js index 7456edabe..7f59c444e 100644 --- a/themes/hotel-reservation-theme/js/order-opc.js +++ b/themes/hotel-reservation-theme/js/order-opc.js @@ -468,8 +468,11 @@ $(document).ready(function() $(document).on('click', '#rooms_extra_services .qty_up', function(e) { e.preventDefault(); qtyfield = $(this).closest('.qty_container').find('input.qty'); - var currentVal = parseInt(qtyfield.val()); - qtyfield.val(currentVal + 1).trigger('focusout'); + var newQuantity = parseInt(qtyfield.val()) + 1; + if (qtyfield.data('max_quantity') < newQuantity) { + newQuantity = qtyfield.data('max_quantity'); + } + qtyfield.val(newQuantity).trigger('focusout'); }); $(document).on('click', '#rooms_extra_services .qty_down', function(e) { @@ -487,6 +490,9 @@ $(document).ready(function() var qty_wntd = $(this).val(); if (qty_wntd == '' || !$.isNumeric(qty_wntd)) { $(this).val(1); + } + if ($(this).data('max_quantity') < qty_wntd) { + $(this).val(qtyfield.data('max_quantity')); } if ($(this).closest('.room_demand_block').find('.change_room_type_service_product').is(':checked')) { updateServiceProducts($(this).closest('.room_demand_block').find('.change_room_type_service_product')); diff --git a/themes/hotel-reservation-theme/js/product.js b/themes/hotel-reservation-theme/js/product.js index 96ae9a806..57a92afa3 100644 --- a/themes/hotel-reservation-theme/js/product.js +++ b/themes/hotel-reservation-theme/js/product.js @@ -1106,9 +1106,12 @@ $(document).ready(function() { $(document).on('click', '.service_product_qty_up', function(e) { e.preventDefault(); qtyfield = $(this).closest('.qty_container').find('input.service_product_qty'); - var currentVal = parseInt(qtyfield.val()); - $(this).closest('.qty_container').find('.qty_count span').text(currentVal + 1); - qtyfield.val(currentVal + 1); + var newQuantity = parseInt(qtyfield.val()) + 1; + if (qtyfield.data('max_quantity') < newQuantity) { + newQuantity = qtyfield.data('max_quantity'); + } + $(this).closest('.qty_container').find('.qty_count span').text(newQuantity); + qtyfield.val(newQuantity); }); // The button to decrement the product value From 2c4694ffe72e20da995580eaf767745d13131cb8 Mon Sep 17 00:00:00 2001 From: Shreesh Arora Date: Thu, 9 Mar 2023 16:59:26 +0530 Subject: [PATCH 2/2] php validation to limit service product quantity' --- controllers/front/CartController.php | 24 +++++++--- controllers/front/ProductController.php | 46 +++++++++++++++---- .../hotel-reservation-theme/js/order-opc.js | 4 +- themes/hotel-reservation-theme/js/product.js | 2 +- 4 files changed, 57 insertions(+), 19 deletions(-) diff --git a/controllers/front/CartController.php b/controllers/front/CartController.php index 7736cc76f..69ce2e3e8 100644 --- a/controllers/front/CartController.php +++ b/controllers/front/CartController.php @@ -395,16 +395,26 @@ class CartControllerCore extends FrontController if (Tools::getValue('op', 'up') == 'up') { if ($total_available_rooms < $req_rm) { die(json_encode(array('status' => 'unavailable_quantity', 'avail_rooms' => $total_available_rooms))); - } else { - // validate normal products if available - if ($serviceProducts) { - $objRoomTypeServiceProduct = new RoomTypeServiceProduct(); - foreach ($serviceProducts as $key => $standartProduct) { - if (!$objRoomTypeServiceProduct->isRoomTypeLinkedWithProduct($this->id_product, $standartProduct['id_product'])) { - unset($serviceProducts[$key]); + } else { + // validate service products if available + if ($serviceProducts) { + $objRoomTypeServiceProduct = new RoomTypeServiceProduct(); + foreach ($serviceProducts as $key => $serviceProduct) { + if (!$objRoomTypeServiceProduct->isRoomTypeLinkedWithProduct($this->id_product, $serviceProduct['id_product'])) { + unset($serviceProducts[$key]); + } else { + if (Validate::isLoadedObject($objServiceProduct = new Product($serviceProduct['id_product']))) { + if (!$objServiceProduct->allow_multiple_quantity && $serviceProduct['quantity'] > 1) { + $serviceProducts[$key]['quantity'] = 1; + } else if ($objServiceProduct->max_quantity && $objServiceProduct->max_quantity < $serviceProduct['quantity'] ) { + $serviceProducts[$key]['quantity'] = $objServiceProduct->max_quantity; + } + } else { + $response['error'] = Tools::displayError('Service not Found'); } } } + } } } } else { diff --git a/controllers/front/ProductController.php b/controllers/front/ProductController.php index 73808d9c9..74f8030fc 100644 --- a/controllers/front/ProductController.php +++ b/controllers/front/ProductController.php @@ -689,10 +689,22 @@ class ProductControllerCore extends FrontController $serviceProductsPrice = 0; if ($roomServiceProducts = json_decode($roomServiceProducts, true)) { $objRoomTypeServiceProductPrice = new RoomTypeServiceProductPrice(); + $objRoomTypeServiceProduct = new RoomTypeServiceProduct(); foreach ($roomServiceProducts as &$product) { - $objProduct = new ProductCore($product['id_product'], false, $this->context->language->id); - $product['name'] = $objProduct->name; - $product['allow_multiple_quantity'] = $objProduct->allow_multiple_quantity; + if (!$objRoomTypeServiceProduct->isRoomTypeLinkedWithProduct($idProduct, $product['id_product'])) { + unset($product); + continue; + } else { + $objServiceProduct = new ProductCore($product['id_product'], false, $this->context->language->id); + if (!$objServiceProduct->allow_multiple_quantity && $product['quantity'] > 1) { + $product['quantity'] = 1; + } else if ($objServiceProduct->max_quantity && $objServiceProduct->max_quantity < $product['quantity'] ) { + $product['quantity'] = $objServiceProduct->max_quantity; + } + + } + $product['name'] = $objServiceProduct->name; + $product['allow_multiple_quantity'] = $objServiceProduct->allow_multiple_quantity; $productPrice = $objRoomTypeServiceProductPrice->getProductPrice($product['id_product'], $idProduct, $product['quantity'], $useTax); $product['price'] = $productPrice; $serviceProductsPrice += $productPrice; @@ -1326,6 +1338,7 @@ class ProductControllerCore extends FrontController $idProduct = Tools::getValue('id_product'); $idServiceProduct = Tools::getValue('service_product'); $addedServiceProduct = Tools::getValue('added_service_product'); + $qty = Tools::getValue('qty'); if (Validate::isLoadedObject($objProduct = new Product($idProduct))) { if (!Product::isBookingProduct($idProduct)) { $response['error'] = Tools::displayError('Room Type info not Found'); @@ -1338,16 +1351,31 @@ class ProductControllerCore extends FrontController } else { if (Validate::isLoadedObject($objServiceProduct = new Product($idServiceProduct))) { $response['success'] = true; - if (!$objServiceProduct->allow_multiple_quantity && !empty($addedServiceProduct)) { - if (!in_array($idServiceProduct, array_column($addedServiceProduct, 'id_product'))) { + if (!$objServiceProduct->allow_multiple_quantity) { + if (!empty($addedServiceProduct)) { + if (!in_array($idServiceProduct, array_column($addedServiceProduct, 'id_product'))) { + $response['add'] = true; + $response['msg'] = 'Service is added to cart.'; + } else { + $response['msg'] = 'Service already added.'; + } + } else { $response['add'] = true; $response['msg'] = 'Service is added to cart.'; - } else { - $response['msg'] = 'Service already added.'; } } else { - $response['add'] = true; - $response['msg'] = 'Service is added to cart.'; + $totalQty = $qty; + if (!empty($addedServiceProduct)) { + if (($key = array_search($idServiceProduct, array_column($addedServiceProduct, 'id_product')))!== false) { + $totalQty += $addedServiceProduct[$key]['quantity']; + } + } + if ($objServiceProduct->max_quantity && $objServiceProduct->max_quantity < $totalQty ) { + $response['msg'] = Tools::displayError(sprintf('Cannot add more than %d quantity.', $objServiceProduct->max_quantity)); + } else { + $response['add'] = true; + $response['msg'] = Tools::displayError('Service is added to cart.'); + } } } else { $response['error'] = Tools::displayError('Service not Found'); diff --git a/themes/hotel-reservation-theme/js/order-opc.js b/themes/hotel-reservation-theme/js/order-opc.js index 7f59c444e..23d5f7e26 100644 --- a/themes/hotel-reservation-theme/js/order-opc.js +++ b/themes/hotel-reservation-theme/js/order-opc.js @@ -469,7 +469,7 @@ $(document).ready(function() e.preventDefault(); qtyfield = $(this).closest('.qty_container').find('input.qty'); var newQuantity = parseInt(qtyfield.val()) + 1; - if (qtyfield.data('max_quantity') < newQuantity) { + if (qtyfield.data('max_quantity') && qtyfield.data('max_quantity') < newQuantity) { newQuantity = qtyfield.data('max_quantity'); } qtyfield.val(newQuantity).trigger('focusout'); @@ -491,7 +491,7 @@ $(document).ready(function() if (qty_wntd == '' || !$.isNumeric(qty_wntd)) { $(this).val(1); } - if ($(this).data('max_quantity') < qty_wntd) { + if ($(this).data('max_quantity') && $(this).data('max_quantity') < qty_wntd) { $(this).val(qtyfield.data('max_quantity')); } if ($(this).closest('.room_demand_block').find('.change_room_type_service_product').is(':checked')) { diff --git a/themes/hotel-reservation-theme/js/product.js b/themes/hotel-reservation-theme/js/product.js index 01ee8641b..d2b8bb6fc 100644 --- a/themes/hotel-reservation-theme/js/product.js +++ b/themes/hotel-reservation-theme/js/product.js @@ -1109,7 +1109,7 @@ $(document).ready(function() { e.preventDefault(); qtyfield = $(this).closest('.qty_container').find('input.service_product_qty'); var newQuantity = parseInt(qtyfield.val()) + 1; - if (qtyfield.data('max_quantity') < newQuantity) { + if (qtyfield.data('max_quantity') && qtyfield.data('max_quantity') < newQuantity) { newQuantity = qtyfield.data('max_quantity'); } $(this).closest('.qty_container').find('.qty_count span').text(newQuantity);