From 59e906a6b6a334d424f6189c59ed5bafd9a446e0 Mon Sep 17 00:00:00 2001 From: amit sharma Date: Fri, 30 Oct 2026 16:09:47 +0530 Subject: [PATCH 01/15] Fixed: Added a configuration setting to control the display of hotel names and locations in the Our Rooms section and implemented the corresponding information display on the front office. --- .../classes/WkHotelRoomDisplay.php | 1 + .../AdminHotelRoomModuleSettingController.php | 7 +++++ .../views/css/WkHotelRoomBlockFront.css | 29 +++++++++++++++++++ .../views/js/WkHotelRoomBlockFront.js | 4 +-- .../templates/hook/hotelRoomDisplayBlock.tpl | 5 ++++ modules/wkhotelroom/wkhotelroom.php | 12 +++++++- 6 files changed, 55 insertions(+), 3 deletions(-) diff --git a/modules/wkhotelroom/classes/WkHotelRoomDisplay.php b/modules/wkhotelroom/classes/WkHotelRoomDisplay.php index 9ee4d3a0b..5f85abd58 100644 --- a/modules/wkhotelroom/classes/WkHotelRoomDisplay.php +++ b/modules/wkhotelroom/classes/WkHotelRoomDisplay.php @@ -188,6 +188,7 @@ class WkHotelRoomDisplay extends ObjectModel // update global configuration values in multilang Configuration::updateValue('HOTEL_ROOM_DISPLAY_HEADING', $HOTEL_ROOM_DISPLAY_HEADING); Configuration::updateValue('HOTEL_ROOM_DISPLAY_DESCRIPTION', $HOTEL_ROOM_DISPLAY_DESCRIPTION); + Configuration::updateValue('HOTEL_ROOM_DISPLAY_PROPERTY', 0); if ($roomTypes = HotelHelper::getPsProducts(Configuration::get('PS_LANG_DEFAULT'), 0, 5, 1)) { foreach ($roomTypes as $product) { if (Validate::isLoadedObject($objProduct = new Product($product['id_product']))) { diff --git a/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php b/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php index d295347fe..5c8261aac 100644 --- a/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php +++ b/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php @@ -64,6 +64,13 @@ class AdminHotelRoomModuleSettingController extends ModuleAdminController 'cols' => '2', 'hint' => $this->l('Enter a description for the property rooms block.'), ), + 'HOTEL_ROOM_DISPLAY_PROPERTY' => array( + 'title' => $this->l('Display property name and city'), + 'cast' => 'intval', + 'type' => 'bool', + 'default' => '0', + 'hint' => $this->l('Show the property name and the city under the room type name in the room cards.'), + ), ), 'submit' => array('title' => $this->l('Save')) ), diff --git a/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css b/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css index 3a8228f5d..69daea7e8 100644 --- a/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css +++ b/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css @@ -326,3 +326,32 @@ a.htlRoomTypeBookNow:hover { .htlRoomCardFeatured .htlRoomFeatureMore { margin-left: 5px; } + +/* property name and city under the room type name */ +.htlRoomCardBody .htlRoomCardProperty { + margin: 0px 0 12px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #777; + font-size: 14px; +} +.htlRoomCardProperty > span + span:before { + margin: 0 10px; + color: #CCC; +} +.htlRoomCardProperty i { + margin-right: 4px; + color: #999; +} + +/* with the property line, the features get a line above them */ +.htlRoomCardProperty + .htlRoomCardFeatured { + border-top: 1px solid #E5E5E5; +} + +/* the amenities keep their line under the property line */ +.htlRoomCardProperty + .htlRoomCardMeta { + border-top: 1px solid #E5E5E5; + padding-top: 12px; +} diff --git a/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js b/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js index d921dcbac..893f179a3 100644 --- a/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js +++ b/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js @@ -89,8 +89,8 @@ $(document).ready(function() { nav: true, navText: ['', ''], dots: false, - autoplay: true, - autoplaySpeed: 1000, + //autoplay: true, + // autoplaySpeed: 1000, margin: 24, items: 1, rtl: typeof language_is_rtl != 'undefined' && language_is_rtl, diff --git a/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl b/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl index b63d3bcd1..76a0ab8ca 100644 --- a/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl +++ b/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl @@ -54,6 +54,11 @@
{block name='hotel_room_block_room_type_description'}

{$roomDisplay.name|escape:'htmlall':'UTF-8'}

+ {if isset($roomDisplay.property_name) && $roomDisplay.property_name} +

+ {$roomDisplay.property_name|escape:'htmlall':'UTF-8'}{if isset($roomDisplay.property_city) && $roomDisplay.property_city}, {$roomDisplay.property_city|escape:'htmlall':'UTF-8'}{/if} +

+ {/if} {if $roomDisplay.feature}
{* one line: the row is cut with an ellipsis by the css when it is wider than the card *} diff --git a/modules/wkhotelroom/wkhotelroom.php b/modules/wkhotelroom/wkhotelroom.php index 67425eb78..9bdc1ec7a 100644 --- a/modules/wkhotelroom/wkhotelroom.php +++ b/modules/wkhotelroom/wkhotelroom.php @@ -51,6 +51,7 @@ class WkHotelRoom extends Module $dateFrom = date('Y-m-d'); $dateTo = date('Y-m-d', strtotime($dateFrom) + 86400); $useTax = HotelBookingDetail::useTax(); + $displayProperty = (bool) Configuration::get('HOTEL_ROOM_DISPLAY_PROPERTY'); $maxFeatures = (int) Configuration::get('WK_MAX_FEATURES_ROOM_SEARCH'); $maxFeatureValues = (int) Configuration::get('WK_MAX_ROOM_TYPE_FEATURE_VALUES'); foreach ($hotelRoomDisplay as &$htlRoom) { @@ -113,6 +114,14 @@ class WkHotelRoom extends Module ); $objRoomType = new HotelRoomType(); $roomTypeInfo = $objRoomType->getRoomTypeInfoByIdProduct($idProduct); + if ($displayProperty && $roomTypeInfo) { + $objHotelBranch = new HotelBranchInformation((int) $roomTypeInfo['id_hotel'], $idLang); + $htlRoom['property_name'] = $objHotelBranch->hotel_name; + // same format as the property location of the room type page + $addressInfo = HotelBranchInformation::getAddress((int) $roomTypeInfo['id_hotel'], $idLang); + $htlRoom['property_city'] = $addressInfo['city']. + ($addressInfo['id_state'] ? ', '.$addressInfo['state'] : '').', '.$addressInfo['country']; + } $htlRoom['max_adults'] = $roomTypeInfo ? (int) $roomTypeInfo['max_adults'] : 0; $htlRoom['max_children'] = $roomTypeInfo ? (int) $roomTypeInfo['max_children'] : 0; $features = array(); @@ -287,7 +296,8 @@ class WkHotelRoom extends Module { $configVars = array( 'HOTEL_ROOM_DISPLAY_HEADING', - 'HOTEL_ROOM_DISPLAY_DESCRIPTION' + 'HOTEL_ROOM_DISPLAY_DESCRIPTION', + 'HOTEL_ROOM_DISPLAY_PROPERTY' ); foreach ($configVars as $key) { if (!Configuration::deleteByName($key)) { From f4cf2a9d3e6cc1f57c4c14ccd59015bccedec1b8 Mon Sep 17 00:00:00 2001 From: amit sharma Date: Fri, 30 Oct 2026 17:15:49 +0530 Subject: [PATCH 02/15] Fixed: review changes --- modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js | 4 ++-- .../views/templates/hook/hotelRoomDisplayBlock.tpl | 4 ++-- modules/wkhotelroom/wkhotelroom.php | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js b/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js index 893f179a3..d921dcbac 100644 --- a/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js +++ b/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js @@ -89,8 +89,8 @@ $(document).ready(function() { nav: true, navText: ['', ''], dots: false, - //autoplay: true, - // autoplaySpeed: 1000, + autoplay: true, + autoplaySpeed: 1000, margin: 24, items: 1, rtl: typeof language_is_rtl != 'undefined' && language_is_rtl, diff --git a/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl b/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl index 76a0ab8ca..4871fc517 100644 --- a/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl +++ b/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl @@ -55,8 +55,8 @@ {block name='hotel_room_block_room_type_description'}

{$roomDisplay.name|escape:'htmlall':'UTF-8'}

{if isset($roomDisplay.property_name) && $roomDisplay.property_name} -

- {$roomDisplay.property_name|escape:'htmlall':'UTF-8'}{if isset($roomDisplay.property_city) && $roomDisplay.property_city}, {$roomDisplay.property_city|escape:'htmlall':'UTF-8'}{/if} +

+ {$roomDisplay.property_name|escape:'htmlall':'UTF-8'}{if isset($roomDisplay.property_location) && $roomDisplay.property_location}, {$roomDisplay.property_location|escape:'htmlall':'UTF-8'}{/if}

{/if} {if $roomDisplay.feature} diff --git a/modules/wkhotelroom/wkhotelroom.php b/modules/wkhotelroom/wkhotelroom.php index 9bdc1ec7a..1558a1ed0 100644 --- a/modules/wkhotelroom/wkhotelroom.php +++ b/modules/wkhotelroom/wkhotelroom.php @@ -117,10 +117,9 @@ class WkHotelRoom extends Module if ($displayProperty && $roomTypeInfo) { $objHotelBranch = new HotelBranchInformation((int) $roomTypeInfo['id_hotel'], $idLang); $htlRoom['property_name'] = $objHotelBranch->hotel_name; - // same format as the property location of the room type page $addressInfo = HotelBranchInformation::getAddress((int) $roomTypeInfo['id_hotel'], $idLang); - $htlRoom['property_city'] = $addressInfo['city']. - ($addressInfo['id_state'] ? ', '.$addressInfo['state'] : '').', '.$addressInfo['country']; + $htlRoom['property_location'] = $addressInfo['city']. + ($addressInfo['state'] ? ', '.$addressInfo['state'] : '').', '.$addressInfo['country']; } $htlRoom['max_adults'] = $roomTypeInfo ? (int) $roomTypeInfo['max_adults'] : 0; $htlRoom['max_children'] = $roomTypeInfo ? (int) $roomTypeInfo['max_children'] : 0; From addcced77b81e0d41806b1778e632a6588327c10 Mon Sep 17 00:00:00 2001 From: amit sharma Date: Fri, 30 Oct 2026 19:29:22 +0530 Subject: [PATCH 03/15] Fixed: add slider auto play setting in hotel room and about hotel module --- .../classes/WkHotelInteriorImage.php | 7 +++ .../AdminAboutHotelBlockSettingController.php | 45 ++++++++++++++++++- .../views/css/WkAboutHotelBlockFront.css | 32 +++++++++++++ .../views/js/WkAboutHotelBlockAdmin.js | 8 ++++ .../views/js/WkAboutHotelBlockFront.js | 13 +++--- .../wkabouthotelblock/wkabouthotelblock.php | 24 +++++++++- .../classes/WkHotelRoomDisplay.php | 7 +++ .../AdminHotelRoomModuleSettingController.php | 44 +++++++++++++++++- .../views/css/WkHotelRoomBlockFront.css | 21 ++++++++- .../views/js/WkHotelRoomBlockAdmin.js | 7 +++ .../views/js/WkHotelRoomBlockFront.js | 8 ++-- modules/wkhotelroom/wkhotelroom.php | 21 ++++++++- 12 files changed, 224 insertions(+), 13 deletions(-) diff --git a/modules/wkabouthotelblock/classes/WkHotelInteriorImage.php b/modules/wkabouthotelblock/classes/WkHotelInteriorImage.php index 6b7aa7fbe..6bdc9b12f 100644 --- a/modules/wkabouthotelblock/classes/WkHotelInteriorImage.php +++ b/modules/wkabouthotelblock/classes/WkHotelInteriorImage.php @@ -23,6 +23,10 @@ class WkHotelInteriorImage extends ObjectModel { + const NAV_TYPE_DOTS = 1; + const NAV_TYPE_ARROWS = 2; + const NAV_TYPE_BOTH = 3; + public $name; public $display_name; public $active; @@ -172,6 +176,9 @@ class WkHotelInteriorImage extends ObjectModel // update global configuration values in multilang Configuration::updateValue('HOTEL_INTERIOR_HEADING', $HOTEL_INTERIOR_HEADING); Configuration::updateValue('HOTEL_INTERIOR_DESCRIPTION', $HOTEL_INTERIOR_DESCRIPTION); + Configuration::updateValue('HOTEL_INTERIOR_NAV_TYPE', self::NAV_TYPE_DOTS); + Configuration::updateValue('HOTEL_INTERIOR_AUTOPLAY', 1); + Configuration::updateValue('HOTEL_INTERIOR_AUTOPLAY_INTERVAL', 5000); // Database Entry for ($i = 1; $i <= 12; $i++) { diff --git a/modules/wkabouthotelblock/controllers/admin/AdminAboutHotelBlockSettingController.php b/modules/wkabouthotelblock/controllers/admin/AdminAboutHotelBlockSettingController.php index 351d9fc48..8087744df 100644 --- a/modules/wkabouthotelblock/controllers/admin/AdminAboutHotelBlockSettingController.php +++ b/modules/wkabouthotelblock/controllers/admin/AdminAboutHotelBlockSettingController.php @@ -33,6 +33,7 @@ class AdminAboutHotelBlockSettingController extends ModuleAdminController $this->context = Context::getContext(); $this->identifier_name = 'display_name'; $this->identifier = 'id_interior_image'; + parent::__construct(); $this->fields_options = array( 'global' => array( @@ -57,6 +58,33 @@ class AdminAboutHotelBlockSettingController extends ModuleAdminController 'validation' => 'isGenericName', 'hint' => $this->l('Enter a description for the interior block.') ), + 'HOTEL_INTERIOR_NAV_TYPE' => array( + 'title' => $this->l('Navigation Type'), + 'type' => 'select', + 'identifier' => 'id', + 'list' => array( + array('id' => WkHotelInteriorImage::NAV_TYPE_DOTS, 'name' => $this->l('Dots')), + array('id' => WkHotelInteriorImage::NAV_TYPE_ARROWS, 'name' => $this->l('Arrows')), + array('id' => WkHotelInteriorImage::NAV_TYPE_BOTH, 'name' => $this->l('Arrows and dots')), + ), + 'hint' => $this->l('How the interior photos slider of the home page is navigated.'), + ), + 'HOTEL_INTERIOR_AUTOPLAY' => array( + 'title' => $this->l('Auto slide'), + 'cast' => 'intval', + 'type' => 'bool', + 'default' => '1', + 'hint' => $this->l('Slide the interior photos automatically on the home page.'), + ), + 'HOTEL_INTERIOR_AUTOPLAY_INTERVAL' => array( + 'title' => $this->l('Slide Interval'), + 'cast' => 'intval', + 'type' => 'text', + 'class' => 'fixed-width-sm', + 'suffix' => $this->l('ms'), + 'default' => '5000', + 'desc' => $this->l('Milliseconds between slides. Min: 500. Example: 5000 = 5 s.'), + ), ), 'submit' => array( 'title' => $this->l('Save'), @@ -124,7 +152,7 @@ class AdminAboutHotelBlockSettingController extends ModuleAdminController 'icon' => 'icon-power-off text-danger', ), ); - parent::__construct(); + } public function initContent() @@ -335,6 +363,21 @@ class AdminAboutHotelBlockSettingController extends ModuleAdminController } } } + if (!in_array((int) Tools::getValue('HOTEL_INTERIOR_NAV_TYPE'), array( + WkHotelInteriorImage::NAV_TYPE_DOTS, + WkHotelInteriorImage::NAV_TYPE_ARROWS, + WkHotelInteriorImage::NAV_TYPE_BOTH, + ))) { + $this->errors[] = $this->l('Invalid navigation type.'); + } + if (Tools::getValue('HOTEL_INTERIOR_AUTOPLAY')) { + $slideInterval = Tools::getValue('HOTEL_INTERIOR_AUTOPLAY_INTERVAL'); + if (!Validate::isUnsignedInt($slideInterval) || $slideInterval < 500) { + $this->errors[] = $this->l('Slide interval must be a whole number of at least 500 milliseconds.'); + } + } else { + $_POST['HOTEL_INTERIOR_AUTOPLAY_INTERVAL'] = Configuration::get('HOTEL_INTERIOR_AUTOPLAY_INTERVAL'); + } if (!count($this->errors)) { foreach ($languages as $lang) { // if lang fileds are at least in default language and not available in other languages then diff --git a/modules/wkabouthotelblock/views/css/WkAboutHotelBlockFront.css b/modules/wkabouthotelblock/views/css/WkAboutHotelBlockFront.css index 332b27df1..c751e7d64 100644 --- a/modules/wkabouthotelblock/views/css/WkAboutHotelBlockFront.css +++ b/modules/wkabouthotelblock/views/css/WkAboutHotelBlockFront.css @@ -174,3 +174,35 @@ html body .htl-light-fancybox .fancybox-nav:focus:not(:focus-visible), html body .htl-gallery-fancybox .fancybox-nav:focus:not(:focus-visible) { outline: 0; } + +/* arrows of the interior slider */ +.htlInterior-owlCarousel .owl-nav .owl-prev, +.htlInterior-owlCarousel .owl-nav .owl-next { + position: absolute; + top: 42%; + display: flex; + align-items: center; + justify-content: center; + width: 44px; + height: 44px; + border-radius: 50%; + background: #fff; + box-shadow: 0 2px 8px rgba(0, 0, 0, .2); + cursor: pointer; +} +.htlInterior-owlCarousel .owl-nav .owl-prev { + left: -17px; +} +.htlInterior-owlCarousel .owl-nav .owl-next { + right: -17px; +} +.htlInterior-owlCarousel .owl-nav .nav-direction-secondary, +.htlInterior-owlCarousel .owl-nav .owl-prev:hover .nav-direction-secondary, +.htlInterior-owlCarousel .owl-nav .owl-next:hover .nav-direction-secondary { + padding: 0; + background: none; + color: #333; +} +.htlInterior-owlCarousel .owl-nav .disabled { + display: none; +} diff --git a/modules/wkabouthotelblock/views/js/WkAboutHotelBlockAdmin.js b/modules/wkabouthotelblock/views/js/WkAboutHotelBlockAdmin.js index 2a32530f4..3b9d8ad9e 100644 --- a/modules/wkabouthotelblock/views/js/WkAboutHotelBlockAdmin.js +++ b/modules/wkabouthotelblock/views/js/WkAboutHotelBlockAdmin.js @@ -21,6 +21,14 @@ */ $(document).ready(function(){ + $(document).on('change', 'input[name="HOTEL_INTERIOR_AUTOPLAY"]', function () { + if ($(this).val() === '1') { + $('input[name="HOTEL_INTERIOR_AUTOPLAY_INTERVAL"]').closest('.form-group').show(200); + } else { + $('input[name="HOTEL_INTERIOR_AUTOPLAY_INTERVAL"]').closest('.form-group').hide(200); + } + }); + $("#interior_img").on("change", function(event) { if (typeof this.files[0] != 'undefined') { if (this.files[0].size > maxSizeAllowed) { diff --git a/modules/wkabouthotelblock/views/js/WkAboutHotelBlockFront.js b/modules/wkabouthotelblock/views/js/WkAboutHotelBlockFront.js index 40c2a1af8..d934449b0 100644 --- a/modules/wkabouthotelblock/views/js/WkAboutHotelBlockFront.js +++ b/modules/wkabouthotelblock/views/js/WkAboutHotelBlockFront.js @@ -23,16 +23,19 @@ $(document).ready(function(){ $('.htlInterior-owlCarousel .owl-carousel').owlCarousel({ loop:true, - nav:false, - dots:true, + nav: htlInteriorSliderArrows, + navText: [ + '', + '' + ], + dots: htlInteriorSliderDots, items: 1, margin: 8, - slideBy: 'page', responsive: {576: {items: 2}}, autoHeight:true, - autoplay:true, + autoplay: htlInteriorSliderAutoplay, autoplaySpeed:1000, - autoplayTimeout:5000, + autoplayTimeout: htlInteriorSliderInterval, autoplayHoverPause:true, responsiveClass:true, rtl: language_is_rtl diff --git a/modules/wkabouthotelblock/wkabouthotelblock.php b/modules/wkabouthotelblock/wkabouthotelblock.php index 05fd71933..062ff54f5 100644 --- a/modules/wkabouthotelblock/wkabouthotelblock.php +++ b/modules/wkabouthotelblock/wkabouthotelblock.php @@ -67,6 +67,22 @@ class WkAboutHotelBlock extends Module } } + $navType = (int) Configuration::get('HOTEL_INTERIOR_NAV_TYPE'); + if (!in_array($navType, array( + WkHotelInteriorImage::NAV_TYPE_DOTS, + WkHotelInteriorImage::NAV_TYPE_ARROWS, + WkHotelInteriorImage::NAV_TYPE_BOTH, + ))) { + $navType = WkHotelInteriorImage::NAV_TYPE_DOTS; + } + $autoplay = Configuration::get('HOTEL_INTERIOR_AUTOPLAY'); + Media::addJsDef(array( + 'htlInteriorSliderArrows' => $navType != WkHotelInteriorImage::NAV_TYPE_DOTS, + 'htlInteriorSliderDots' => $navType != WkHotelInteriorImage::NAV_TYPE_ARROWS, + 'htlInteriorSliderAutoplay' => $autoplay === false ? true : (bool) $autoplay, + 'htlInteriorSliderInterval' => max(500, (int) Configuration::get('HOTEL_INTERIOR_AUTOPLAY_INTERVAL') ?: 5000), + )); + $this->context->smarty->assign( array( 'HOTEL_INTERIOR_HEADING' => $HOTEL_INTERIOR_HEADING, @@ -204,7 +220,13 @@ class WkAboutHotelBlock extends Module public function deleteConfigKeys() { - $var = array('HOTEL_INTERIOR_HEADING', 'HOTEL_INTERIOR_DESCRIPTION'); + $var = array( + 'HOTEL_INTERIOR_HEADING', + 'HOTEL_INTERIOR_DESCRIPTION', + 'HOTEL_INTERIOR_NAV_TYPE', + 'HOTEL_INTERIOR_AUTOPLAY', + 'HOTEL_INTERIOR_AUTOPLAY_INTERVAL', + ); foreach ($var as $key) { if (!Configuration::deleteByName($key)) { return false; diff --git a/modules/wkhotelroom/classes/WkHotelRoomDisplay.php b/modules/wkhotelroom/classes/WkHotelRoomDisplay.php index 5f85abd58..6c86737be 100644 --- a/modules/wkhotelroom/classes/WkHotelRoomDisplay.php +++ b/modules/wkhotelroom/classes/WkHotelRoomDisplay.php @@ -23,6 +23,10 @@ class WkHotelRoomDisplay extends ObjectModel { + const NAV_TYPE_DOTS = 1; + const NAV_TYPE_ARROWS = 2; + const NAV_TYPE_BOTH = 3; + public $id_product; public $active; public $position; @@ -189,6 +193,9 @@ class WkHotelRoomDisplay extends ObjectModel Configuration::updateValue('HOTEL_ROOM_DISPLAY_HEADING', $HOTEL_ROOM_DISPLAY_HEADING); Configuration::updateValue('HOTEL_ROOM_DISPLAY_DESCRIPTION', $HOTEL_ROOM_DISPLAY_DESCRIPTION); Configuration::updateValue('HOTEL_ROOM_DISPLAY_PROPERTY', 0); + Configuration::updateValue('HOTEL_ROOM_DISPLAY_NAV_TYPE', self::NAV_TYPE_ARROWS); + Configuration::updateValue('HOTEL_ROOM_DISPLAY_AUTOPLAY', 1); + Configuration::updateValue('HOTEL_ROOM_DISPLAY_AUTOPLAY_INTERVAL', 5000); if ($roomTypes = HotelHelper::getPsProducts(Configuration::get('PS_LANG_DEFAULT'), 0, 5, 1)) { foreach ($roomTypes as $product) { if (Validate::isLoadedObject($objProduct = new Product($product['id_product']))) { diff --git a/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php b/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php index 5c8261aac..689d4d4aa 100644 --- a/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php +++ b/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php @@ -31,6 +31,7 @@ class AdminHotelRoomModuleSettingController extends ModuleAdminController $this->_defaultOrderBy = 'position'; $this->bootstrap = true; $this->context = Context::getContext(); + parent::__construct(); $this->_select = ' pl.`name`, hbil.`hotel_name` '; @@ -71,6 +72,33 @@ class AdminHotelRoomModuleSettingController extends ModuleAdminController 'default' => '0', 'hint' => $this->l('Show the property name and the city under the room type name in the room cards.'), ), + 'HOTEL_ROOM_DISPLAY_NAV_TYPE' => array( + 'title' => $this->l('Navigation Type'), + 'type' => 'select', + 'identifier' => 'id', + 'list' => array( + array('id' => WkHotelRoomDisplay::NAV_TYPE_ARROWS, 'name' => $this->l('Arrows')), + array('id' => WkHotelRoomDisplay::NAV_TYPE_DOTS, 'name' => $this->l('Dots')), + array('id' => WkHotelRoomDisplay::NAV_TYPE_BOTH, 'name' => $this->l('Arrows and dots')), + ), + 'hint' => $this->l('How the room cards slider of the home page is navigated.'), + ), + 'HOTEL_ROOM_DISPLAY_AUTOPLAY' => array( + 'title' => $this->l('Auto slide'), + 'cast' => 'intval', + 'type' => 'bool', + 'default' => '1', + 'hint' => $this->l('Slide the room cards automatically on the home page.'), + ), + 'HOTEL_ROOM_DISPLAY_AUTOPLAY_INTERVAL' => array( + 'title' => $this->l('Slide Interval'), + 'cast' => 'intval', + 'type' => 'text', + 'class' => 'fixed-width-sm', + 'suffix' => $this->l('ms'), + 'default' => '5000', + 'desc' => $this->l('Milliseconds between slides. Min: 500. Example: 5000 = 5 s.'), + ), ), 'submit' => array('title' => $this->l('Save')) ), @@ -138,7 +166,6 @@ class AdminHotelRoomModuleSettingController extends ModuleAdminController ); $this->identifier = 'id_room_block'; - parent::__construct(); if ($this->hotelList = HotelBranchInformation::getProfileAccessedHotels($this->context->employee->id_profile, 1)) { $objHotelRoomType = new HotelRoomType(); if ($this->loadObject(true) @@ -365,6 +392,21 @@ class AdminHotelRoomModuleSettingController extends ModuleAdminController } } } + if (!in_array((int) Tools::getValue('HOTEL_ROOM_DISPLAY_NAV_TYPE'), array( + WkHotelRoomDisplay::NAV_TYPE_DOTS, + WkHotelRoomDisplay::NAV_TYPE_ARROWS, + WkHotelRoomDisplay::NAV_TYPE_BOTH, + ))) { + $this->errors[] = $this->l('Invalid navigation type.'); + } + if (Tools::getValue('HOTEL_ROOM_DISPLAY_AUTOPLAY')) { + $slideInterval = Tools::getValue('HOTEL_ROOM_DISPLAY_AUTOPLAY_INTERVAL'); + if (!Validate::isUnsignedInt($slideInterval) || $slideInterval < 500) { + $this->errors[] = $this->l('Slide interval must be a whole number of at least 500 milliseconds.'); + } + } else { + $_POST['HOTEL_ROOM_DISPLAY_AUTOPLAY_INTERVAL'] = Configuration::get('HOTEL_ROOM_DISPLAY_AUTOPLAY_INTERVAL'); + } if (!count($this->errors)) { foreach ($languages as $lang) { // if lang fileds are at least in default language and not available in other languages then diff --git a/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css b/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css index 69daea7e8..7942dea92 100644 --- a/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css +++ b/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css @@ -334,7 +334,7 @@ a.htlRoomTypeBookNow:hover { text-overflow: ellipsis; white-space: nowrap; color: #777; - font-size: 14px; + font-size: 13px; } .htlRoomCardProperty > span + span:before { margin: 0 10px; @@ -355,3 +355,22 @@ a.htlRoomTypeBookNow:hover { border-top: 1px solid #E5E5E5; padding-top: 12px; } + +/* dots under the room cards */ +.htlRoom-owlCarousel .owl-dots { + display: flex; + justify-content: center; + gap: 6px; + margin-top: 20px; +} +.htlRoom-owlCarousel .owl-dots .owl-dot span { + display: block; + width: 7px; + height: 7px; + margin: 0; + border-radius: 50%; + background: #C4C4C4; +} +.htlRoom-owlCarousel .owl-dots .owl-dot.active span { + background: #333; +} diff --git a/modules/wkhotelroom/views/js/WkHotelRoomBlockAdmin.js b/modules/wkhotelroom/views/js/WkHotelRoomBlockAdmin.js index 481e7bbcf..d5f941221 100644 --- a/modules/wkhotelroom/views/js/WkHotelRoomBlockAdmin.js +++ b/modules/wkhotelroom/views/js/WkHotelRoomBlockAdmin.js @@ -21,6 +21,13 @@ */ $(document).ready(function() { + $(document).on('change', 'input[name="HOTEL_ROOM_DISPLAY_AUTOPLAY"]', function () { + if ($(this).val() === '1') { + $('input[name="HOTEL_ROOM_DISPLAY_AUTOPLAY_INTERVAL"]').closest('.form-group').show(200); + } else { + $('input[name="HOTEL_ROOM_DISPLAY_AUTOPLAY_INTERVAL"]').closest('.form-group').hide(200); + } + }); var trigger_ajax = ''; $('#productName').on('keyup', function(event) { var suggestion_ul = $(this).siblings("ul.prod_suggest_ul"); diff --git a/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js b/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js index d921dcbac..91fca4bdb 100644 --- a/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js +++ b/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js @@ -86,11 +86,13 @@ $(document).ready(function() { fitRoomCards($(this)); }).owlCarousel({ loop: true, - nav: true, + nav: htlRoomSliderArrows, navText: ['', ''], - dots: false, - autoplay: true, + dots: htlRoomSliderDots, + autoplay: htlRoomSliderAutoplay, + autoplayTimeout: htlRoomSliderInterval, autoplaySpeed: 1000, + autoplayHoverPause: true, margin: 24, items: 1, rtl: typeof language_is_rtl != 'undefined' && language_is_rtl, diff --git a/modules/wkhotelroom/wkhotelroom.php b/modules/wkhotelroom/wkhotelroom.php index 1558a1ed0..24706de8f 100644 --- a/modules/wkhotelroom/wkhotelroom.php +++ b/modules/wkhotelroom/wkhotelroom.php @@ -155,6 +155,22 @@ class WkHotelRoom extends Module ) ); + $autoplay = Configuration::get('HOTEL_ROOM_DISPLAY_AUTOPLAY'); + $navType = (int) Configuration::get('HOTEL_ROOM_DISPLAY_NAV_TYPE'); + if (!in_array($navType, array( + WkHotelRoomDisplay::NAV_TYPE_DOTS, + WkHotelRoomDisplay::NAV_TYPE_ARROWS, + WkHotelRoomDisplay::NAV_TYPE_BOTH, + ))) { + $navType = WkHotelRoomDisplay::NAV_TYPE_ARROWS; + } + Media::addJsDef(array( + 'htlRoomSliderArrows' => $navType != WkHotelRoomDisplay::NAV_TYPE_DOTS, + 'htlRoomSliderDots' => $navType != WkHotelRoomDisplay::NAV_TYPE_ARROWS, + 'htlRoomSliderAutoplay' => $autoplay === false ? true : (bool) $autoplay, + 'htlRoomSliderInterval' => max(500, (int) Configuration::get('HOTEL_ROOM_DISPLAY_AUTOPLAY_INTERVAL') ?: 5000), + )); + $this->context->controller->addCSS(_PS_JS_DIR_.'owl-carousel/assets/owl.carousel.min.css'); $this->context->controller->addCSS(_PS_JS_DIR_.'owl-carousel/assets/owl.theme.default.min.css'); $this->context->controller->addJS(_PS_JS_DIR_.'owl-carousel/owl.carousel.min.js'); @@ -296,7 +312,10 @@ class WkHotelRoom extends Module $configVars = array( 'HOTEL_ROOM_DISPLAY_HEADING', 'HOTEL_ROOM_DISPLAY_DESCRIPTION', - 'HOTEL_ROOM_DISPLAY_PROPERTY' + 'HOTEL_ROOM_DISPLAY_PROPERTY', + 'HOTEL_ROOM_DISPLAY_NAV_TYPE', + 'HOTEL_ROOM_DISPLAY_AUTOPLAY', + 'HOTEL_ROOM_DISPLAY_AUTOPLAY_INTERVAL', ); foreach ($configVars as $key) { if (!Configuration::deleteByName($key)) { From f5c3c3e74d2408e81143c749b12004e719c0aa1d Mon Sep 17 00:00:00 2001 From: amit sharma Date: Mon, 2 Nov 2026 16:34:46 +0530 Subject: [PATCH 04/15] Added: Price application design for service product popup --- .../_add_order_extra_services_tab_content.tpl | 18 +----- ..._services_service_products_tab_content.tpl | 51 +++-------------- .../template/helpers/service-applied-days.tpl | 56 +++++++++++++++++++ classes/Product.php | 30 ++++++++++ controllers/admin/AdminOrdersController.php | 4 ++ controllers/front/ProductController.php | 55 +++++++++++++++--- .../classes/RoomTypeServiceProduct.php | 18 +++++- .../_partials/booking-form.tpl | 9 +++ .../_partials/cart_booking_services.tpl | 35 +++++++----- .../_partials/order-extra-services.tpl | 18 ++---- .../_partials/service-applied-days.tpl | 56 +++++++++++++++++++ .../_partials/service-products-list-row.tpl | 15 +---- themes/hotel-reservation-theme/css/global.css | 12 ++++ themes/hotel-reservation-theme/js/product.js | 24 +++++++- 14 files changed, 288 insertions(+), 113 deletions(-) create mode 100644 admin-dev/themes/default/template/helpers/service-applied-days.tpl create mode 100644 themes/hotel-reservation-theme/_partials/service-applied-days.tpl diff --git a/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl b/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl index 138d27e3b..e0576ca6c 100644 --- a/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl +++ b/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl @@ -47,6 +47,7 @@ {foreach $serviceProducts as $product} + {if !empty($selectedRoomServiceProduct['date_from']) && !(isset($selectedRoomServiceProduct['selected_service'][$product['id_product']])) && $product['price_calculation_method'] != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING && !(Product::getServicePriceApplicableDates($product['price_calculation_method'], $selectedRoomServiceProduct['date_from'], $selectedRoomServiceProduct['date_to'])|@array_filter)}{continue}{/if} {if isset($selectedRoomServiceProduct['selected_service']) && $selectedRoomServiceProduct['selected_service'] && ($product['id_product']|array_key_exists:$selectedRoomServiceProduct['selected_service'])} {assign var='serviceSelected' value=true} {$product.price_tax_incl = $selectedRoomServiceProduct['selected_service'][$product['id_product']]['unit_price_tax_incl']} @@ -63,21 +64,7 @@
{$product['name']|escape:'html':'UTF-8'} - {capture name='room_type_service_tooltip_content'} - {assign var="priceCalcMethod" value=$product['price_calculation_method']|default:0} -
-
{l s='Applied on:'}
-
-
-
    - {foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'} -
  • {$pcmDayLabel}
  • - {/foreach} -
-
- {/capture} - - {include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.room_type_service_tooltip_content allow_html=true} + {include file='helpers/service-applied-days.tpl' price_calculation_method=$product['price_calculation_method'] date_from=$selectedRoomServiceProduct['date_from']|default:'' date_to=$selectedRoomServiceProduct['date_to']|default:''}
@@ -108,6 +95,7 @@ {$cartCurrency->sign} + {if ($product['price_calculation_method']) != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING}{l s='/ Night'}{/if}
{/if} diff --git a/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl b/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl index 2196ec084..25a65d039 100644 --- a/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl +++ b/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl @@ -56,21 +56,7 @@
{$service['name']|escape:'html':'UTF-8'} - {capture name='room_type_service_tooltip_content'} - {assign var="priceCalcMethod" value=$service['price_calculation_method']|default:0} -
-
{l s='Applied on:'}
-
-
-
    - {foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'} -
  • {$pcmDayLabel}
  • - {/foreach} -
-
- {/capture} - - {include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.room_type_service_tooltip_content allow_html=true} + {include file='helpers/service-applied-days.tpl' price_calculation_method=$service['price_calculation_method']|default:0 date_from=$additionalServices['date_from'] date_to=$additionalServices['date_to']}
@@ -101,6 +87,7 @@
{$currencySign} + {if ($service['price_calculation_method']|default:0) != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING}{l s='/ Night'}{/if}
{displayPrice price=$service['total_price_tax_excl']|escape:'html':'UTF-8' currency=$orderCurrency} @@ -142,26 +129,15 @@ {foreach $serviceProducts as $product} + {* services applied on selected days only are not listed when none of those days exist in the stay *} + {if !empty($date_from) && $product['price_calculation_method'] != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING && !(Product::getServicePriceApplicableDates($product['price_calculation_method'], $date_from, $date_to)|@array_filter)}{continue}{/if} {$product['name']|escape:'html':'UTF-8'} - {capture name='adm_pcm_tooltip_content'} - {assign var="priceCalcMethod" value=$product['price_calculation_method']|default:0} -
-
{l s='Applied on:'}
-
-
- -
- {/capture} - {include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.adm_pcm_tooltip_content allow_html=true} + {include file='helpers/service-applied-days.tpl' price_calculation_method=$product['price_calculation_method'] date_from=$date_from|default:'' date_to=$date_to|default:''} {if $product['auto_add_to_cart'] && $product['price_addition_type'] == Product::PRICE_ADDITION_TYPE_WITH_ROOM} @@ -184,6 +160,7 @@
{$currencySign} + {if ($product['price_calculation_method']) != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING}{l s='/ Night'}{/if}
{hook h="displayAdminOrderAvailableServicesData" id_service_product=$product['id_product'] id_htl_booking_detail=$id_booking_detail} @@ -328,20 +305,8 @@ {$service['name']|escape:'html':'UTF-8'} - {capture name='room_type_service_pcm_tooltip_content'} - {assign var="priceCalcMethod" value=$service['price_calculation_method']|default:0} -
-
{l s='Applied on:'}
-
-
- -
- {/capture} - {include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.room_type_service_pcm_tooltip_content allow_html=true} + {include file='helpers/service-applied-days.tpl' price_calculation_method=$service['price_calculation_method']|default:0 date_from=$additionalServices['date_from'] date_to=$additionalServices['date_to']} + {if $service['product_auto_add'] && $service['product_price_addition_type'] == Product::PRICE_ADDITION_TYPE_INDEPENDENT} {l s='Convenience fee'} diff --git a/admin-dev/themes/default/template/helpers/service-applied-days.tpl b/admin-dev/themes/default/template/helpers/service-applied-days.tpl new file mode 100644 index 000000000..2e8e4d5e1 --- /dev/null +++ b/admin-dev/themes/default/template/helpers/service-applied-days.tpl @@ -0,0 +1,56 @@ +{** +* NOTICE OF LICENSE +* +* This source file is subject to the Open Software License version 3.0 +* that is bundled with this package in the file LICENSE.md +* It is also available through the world-wide-web at this URL: +* https://opensource.org/license/osl-3-0-php +* If you did not receive a copy of the license and are unable to +* obtain it through the world-wide-web, please send an email +* to support@qloapps.com so we can send you a copy immediately. +* +* DISCLAIMER +* +* Do not edit or add to this file if you wish to upgrade this module to a newer +* versions in the future. If you wish to customize this module for your needs +* please refer to https://store.webkul.com/customisation-guidelines for more information. +* +* @author Webkul IN +* @copyright Since 2010 Webkul +* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0 +*} + +{if isset($price_calculation_method) && (int) $price_calculation_method != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING && !empty($date_from) && !empty($date_to)} + {assign var='serviceAppliedDates' value=Product::getServicePriceApplicableDates($price_calculation_method, $date_from, $date_to)} + {assign var='serviceAppliedDays' value=0} + {foreach from=$serviceAppliedDates item='serviceAppliedGroupDates'} + {assign var='serviceAppliedDays' value=$serviceAppliedDays + count($serviceAppliedGroupDates)} + {/foreach} + {if $serviceAppliedDays} + {capture name='adm_applied_days_tooltip'} +
+
{l s='Applied on:'}
+
+
+ +
+ {/capture} + {capture name='adm_applied_days_badge'}{if $serviceAppliedDays == 1}{l s='Applied for 1 Day'}{else}{l s='Applied for %s Days' sprintf=$serviceAppliedDays}{/if}{/capture} +
+ {include file='helpers/ui-tooltip.tpl' tooltip_title=$smarty.capture.adm_applied_days_badge tooltip_content=$smarty.capture.adm_applied_days_tooltip allow_html=true} +
+ {/if} +{/if} diff --git a/classes/Product.php b/classes/Product.php index 27f9704bd..2a5b3e29e 100644 --- a/classes/Product.php +++ b/classes/Product.php @@ -6973,6 +6973,36 @@ class ProductCore extends ObjectModel } } + public static function getServicePriceApplicableDates($priceCalculationMethod, $dateFrom, $dateTo) + { + $priceCalculationMethod = (int) $priceCalculationMethod; + $dates = array(); + if (empty($dateFrom) || empty($dateTo)) { + return $dates; + } + + $checkinDate = new DateTime(date('Y-m-d', strtotime($dateFrom))); + $checkoutDate = new DateTime(date('Y-m-d', strtotime($dateTo))); + + if ($priceCalculationMethod & self::PRICE_CALCULATION_METHOD_ON_CHECKIN_DAY) { + $dates['checkin'] = array($checkinDate->format('Y-m-d')); + } + if ($priceCalculationMethod & self::PRICE_CALCULATION_METHOD_ON_DURING_STAY) { + $dates['stay'] = array(); + $stayDate = clone $checkinDate; + $stayDate->modify('+1 day'); + while ($stayDate < $checkoutDate) { + $dates['stay'][] = $stayDate->format('Y-m-d'); + $stayDate->modify('+1 day'); + } + } + if ($priceCalculationMethod & self::PRICE_CALCULATION_METHOD_ON_CHECKOUT_DAY) { + $dates['checkout'] = array($checkoutDate->format('Y-m-d')); + } + + return $dates; + } + public static function getPriceCalculationMethodDaysLabel($priceCalculationMethod) { $priceCalculationMethod = (int) $priceCalculationMethod; diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php index bbed3db59..e0086c652 100644 --- a/controllers/admin/AdminOrdersController.php +++ b/controllers/admin/AdminOrdersController.php @@ -1051,6 +1051,8 @@ class AdminOrdersControllerCore extends AdminController $smartyVars['link'] = $this->context->link; $smartyVars['id_booking_detail'] = $productLineData['id']; + $smartyVars['date_from'] = $dateFrom; + $smartyVars['date_to'] = $dateTo; // set context currency So that we can get prices in the order currency $this->context->currency = $objCurrency; @@ -7867,6 +7869,8 @@ class AdminOrdersControllerCore extends AdminController $smartyVars['link'] = $this->context->link; $smartyVars['id_booking_detail'] = $idHtlBookingDetail; + $smartyVars['date_from'] = $dateFrom; + $smartyVars['date_to'] = $dateTo; $objServiceProductOrderDetail = new ServiceProductOrderDetail(); if ($additionalServices = $objServiceProductOrderDetail->getRoomTypeServiceProducts( 0, diff --git a/controllers/front/ProductController.php b/controllers/front/ProductController.php index e4d3a0389..233b64e65 100644 --- a/controllers/front/ProductController.php +++ b/controllers/front/ProductController.php @@ -491,7 +491,7 @@ class ProductControllerCore extends FrontController } } $this->assignBookingFormVars($this->product->id, $date_from, $date_to, $occupancy_value); - $this->assignRoomServiceProductVars(); + $this->assignRoomServiceProductVars($date_from, $date_to); // product price after imposing feature prices... if ($useTax) { @@ -614,7 +614,7 @@ class ProductControllerCore extends FrontController $this->setTemplate(_PS_THEME_DIR_.'product.tpl'); } - public function assignRoomServiceProductVars() + public function assignRoomServiceProductVars($dateFrom = null, $dateTo = null) { // get service products for room type $p = 1; @@ -626,7 +626,12 @@ class ProductControllerCore extends FrontController $this->product->id, $p, $n, - true + true, + 2, + 0, + false, + $dateFrom, + $dateTo ); if ($serviceProductsByCategory) { $smartyVars['service_products_exists'] = 1; @@ -637,7 +642,13 @@ class ProductControllerCore extends FrontController $this->product->id, $p, $n, - true + true, + 2, + 0, + false, + false, + $dateFrom, + $dateTo ); $numTotalServiceProducts = $this->product->getProductServiceProducts( $this->context->language->id, @@ -839,10 +850,16 @@ class ProductControllerCore extends FrontController $serviceNumAdults = isset($serviceOccupancy['adults']) ? (int) $serviceOccupancy['adults'] : 1; $serviceChildAges = !empty($serviceOccupancy['child_ages']) ? (array) $serviceOccupancy['child_ages'] : array(); - foreach ($roomServiceProducts as &$product) { + foreach ($roomServiceProducts as $keyServiceProduct => &$product) { + $priceCalcMethod = Product::getProductPriceCalculation((int) $product['id_product']); if (!$objRoomTypeServiceProduct->isRoomTypeLinkedWithProduct($idProduct, $product['id_product'])) { unset($product); continue; + } elseif ($priceCalcMethod != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING && !array_filter(Product::getServicePriceApplicableDates($priceCalcMethod, $dateFrom, $dateTo))) { + // service is applied on selected days only and none of those days exist in the stay + unset($product); + unset($roomServiceProducts[$keyServiceProduct]); + continue; } else { $objServiceProduct = new ProductCore($product['id_product'], false, $this->context->language->id); if (!$objServiceProduct->allow_multiple_quantity && $product['quantity'] > 1) { @@ -854,6 +871,7 @@ class ProductControllerCore extends FrontController } $product['name'] = $objServiceProduct->name; $product['allow_multiple_quantity'] = $objServiceProduct->allow_multiple_quantity; + $product['price_calculation_method'] = $objServiceProduct->price_calculation_method; $productPrice = Product::getServiceProductPrice( $product['id_product'], @@ -1506,7 +1524,7 @@ class ProductControllerCore extends FrontController $roomServiceProducts = Tools::getValue('room_service_products'); $dateFrom = date('Y-m-d H:i:s', strtotime($dateFrom)); $dateTo = date('Y-m-d H:i:s', strtotime($dateTo)); - $this->assignRoomServiceProductVars(); + $this->assignRoomServiceProductVars($dateFrom, $dateTo); if ($this->assignBookingFormVars( $idProduct, $dateFrom, @@ -1514,6 +1532,9 @@ class ProductControllerCore extends FrontController $occupancy, $roomServiceProducts )) { + if (Tools::getValue('refresh_services')) { + $response['html_service_products'] = $this->getRefreshedServiceProductsHtml(); + } } } else { $idHotel = Tools::getValue('service_id_hotel'); @@ -1536,6 +1557,21 @@ class ProductControllerCore extends FrontController $this->ajaxDie(json_encode($response)); } + /** + * Render the service products block using the service products already assigned to smarty. + * + * @return string + */ + protected function getRefreshedServiceProductsHtml() + { + $this->context->smarty->assign(array( + 'product' => $this->product, + 'PS_SERVICE_PRODUCT_CATEGORY_FILTER' => Configuration::get('PS_SERVICE_PRODUCT_CATEGORY_FILTER'), + )); + + return $this->context->smarty->fetch(_PS_THEME_DIR_.'_partials/service-products.tpl'); + } + public function displayAjaxGetHotelImages() { $response = array('status' => false); @@ -1582,6 +1618,8 @@ class ProductControllerCore extends FrontController $p = Tools::getValue('p'); $id_product = Tools::getValue('id_product'); $id_category = Tools::getValue('id_category'); + $date_from = Tools::getValue('date_from'); + $date_to = Tools::getValue('date_to'); if ($this->isTokenValid()) { if ($p && $id_product) { @@ -1600,7 +1638,10 @@ class ProductControllerCore extends FrontController true, 2, 0, - $id_category + $id_category, + false, + $date_from, + $date_to )) { $this->context->smarty->assign('service_products', $roomTypeServiceProducts); if (Configuration::get('PS_SERVICE_PRODUCT_CATEGORY_FILTER')) { diff --git a/modules/hotelreservationsystem/classes/RoomTypeServiceProduct.php b/modules/hotelreservationsystem/classes/RoomTypeServiceProduct.php index 409a7696e..84dc017ec 100644 --- a/modules/hotelreservationsystem/classes/RoomTypeServiceProduct.php +++ b/modules/hotelreservationsystem/classes/RoomTypeServiceProduct.php @@ -184,7 +184,7 @@ class RoomTypeServiceProduct extends ObjectModel return false; } - public function getServiceProductsData($idProductRoomType, $p = 1, $n = 0, $front = false, $available_for_order = 2, $auto_add_to_cart = 0, $subCategory = false, $idLang = false) + public function getServiceProductsData($idProductRoomType, $p = 1, $n = 0, $front = false, $available_for_order = 2, $auto_add_to_cart = 0, $subCategory = false, $idLang = false, $dateFrom = null, $dateTo = null) { $context = Context::getContext(); if (!$idLang) { @@ -209,6 +209,18 @@ class RoomTypeServiceProduct extends ObjectModel continue; } + if ($dateFrom && $dateTo) { + $priceCalcMethod = (int) $serviceProduct['price_calculation_method']; + if ($priceCalcMethod != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING && !array_filter(Product::getServicePriceApplicableDates($priceCalcMethod, $dateFrom, $dateTo))) { + unset($serviceProducts[$key]); + continue; + } + + $serviceProduct['price_calculation_method'] = $priceCalcMethod; + $serviceProduct['stay_date_from'] = $dateFrom; + $serviceProduct['stay_date_to'] = $dateTo; + } + $serviceProduct['price_tax_exc'] = Product::getServiceProductPrice( (int)$serviceProduct['id_product'], 0, @@ -352,7 +364,7 @@ class RoomTypeServiceProduct extends ObjectModel return $pricingByBookingAndProduct; } - public function getServiceProductsGroupByCategory($idProduct, $p = 1, $n = 0, $front = false, $available_for_order = 2, $auto_add_to_cart = 0, $idLang = false) + public function getServiceProductsGroupByCategory($idProduct, $p = 1, $n = 0, $front = false, $available_for_order = 2, $auto_add_to_cart = 0, $idLang = false, $dateFrom = null, $dateTo = null) { if (!$idLang) { $idLang = Context::getContext()->language->id; @@ -361,7 +373,7 @@ class RoomTypeServiceProduct extends ObjectModel $objProduct = new Product($idProduct); if ($serviceProductsCategories = $objProduct->getAvailableServiceProductsCategories($idLang, 1)) { foreach ($serviceProductsCategories as $key => $category) { - if ($products = $this->getServiceProductsData($idProduct, $p, $n, $front, $available_for_order, $auto_add_to_cart, $category['id_category'], $idLang)) { + if ($products = $this->getServiceProductsData($idProduct, $p, $n, $front, $available_for_order, $auto_add_to_cart, $category['id_category'], $idLang, $dateFrom, $dateTo)) { $serviceProductsCategories[$key]['products'] = $products; } else { unset($serviceProductsCategories[$key]); diff --git a/themes/hotel-reservation-theme/_partials/booking-form.tpl b/themes/hotel-reservation-theme/_partials/booking-form.tpl index c0109f278..179ad07a7 100644 --- a/themes/hotel-reservation-theme/_partials/booking-form.tpl +++ b/themes/hotel-reservation-theme/_partials/booking-form.tpl @@ -99,6 +99,15 @@
{$product['name']} + {assign var='appliedDays' value=0} + {if $product['price_calculation_method'] != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING} + {foreach Product::getServicePriceApplicableDates($product['price_calculation_method'], $date_from, $date_to) as $appliedGroupDates} + {assign var='appliedDays' value=$appliedDays + count($appliedGroupDates)} + {/foreach} + {/if} + {if $appliedDays} +

{if $appliedDays == 1}{l s='Applied for 1 Day'}{else}{l s='Applied for %s Days' sprintf=$appliedDays}{/if}

+ {/if} {if $product['allow_multiple_quantity']}

{l s='qty'}: {$product['quantity']}

{/if} diff --git a/themes/hotel-reservation-theme/_partials/cart_booking_services.tpl b/themes/hotel-reservation-theme/_partials/cart_booking_services.tpl index f9f437596..22cf53395 100644 --- a/themes/hotel-reservation-theme/_partials/cart_booking_services.tpl +++ b/themes/hotel-reservation-theme/_partials/cart_booking_services.tpl @@ -56,6 +56,8 @@ {else} {assign var='serviceSelected' value=false} {/if} + {* services applied on selected days only are not shown when none of those days exist in the stay *} + {if $serviceSelected || $product['price_calculation_method'] == Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING || (Product::getServicePriceApplicableDates($product['price_calculation_method'], $cartRoom['date_from'], $cartRoom['date_to'])|@array_filter)}
@@ -68,20 +70,8 @@
{$product['name']|escape:'html':'UTF-8'} - {assign var='priceCalcMethod' value=$product.price_calculation_method|default:0} - {capture name='htl_pcm_tooltip'} -
-
{l s='Applied on:'}
-
-
-
    - {foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'} -
  • {$pcmDayLabel}
  • - {/foreach} -
-
- {/capture} - {include file='_partials/ui-tooltip.tpl' tooltip_content=$smarty.capture.htl_pcm_tooltip allow_html=true} {if $product.allow_multiple_quantity} + {include file='_partials/service-applied-days.tpl' price_calculation_method=$product.price_calculation_method|default:0 date_from=$cartRoom['date_from'] date_to=$cartRoom['date_to']} + {if $product.allow_multiple_quantity}
@@ -96,10 +86,25 @@
{if ($product.show_price && !isset($restricted_country_mode)) || isset($groups)} - {if !$priceDisplay}{convertPrice price=$product.price_tax_incl}{else}{convertPrice price=$product.price_tax_exc}{/if} + {assign var='serviceDayBased' value=(($product.price_calculation_method|default:0) != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING)} + {assign var='serviceTotal' value=false} + {if $serviceSelected} + {assign var='serviceTotal' value=$cartRoom['selected_service'][$product['id_product']]} + {elseif isset($cartRoom['available_service_pricing'][$product['id_product']])} + {assign var='serviceTotal' value=$cartRoom['available_service_pricing'][$product['id_product']]} + {/if} +
+ {if $serviceDayBased && $serviceTotal} + {if !$priceDisplay}{convertPrice price=$serviceTotal.total_price_tax_incl}{else}{convertPrice price=$serviceTotal.total_price_tax_excl}{/if} +
{if !$priceDisplay}{convertPrice price=$product.price_tax_incl}{else}{convertPrice price=$product.price_tax_exc}{/if} {l s='/Night'} + {else} + {if !$priceDisplay}{convertPrice price=$product.price_tax_incl}{else}{convertPrice price=$product.price_tax_exc}{/if} + {/if} +
{/if}
+ {/if} {/foreach} {/if}
diff --git a/themes/hotel-reservation-theme/_partials/order-extra-services.tpl b/themes/hotel-reservation-theme/_partials/order-extra-services.tpl index 8d4bfe473..cc818bb05 100644 --- a/themes/hotel-reservation-theme/_partials/order-extra-services.tpl +++ b/themes/hotel-reservation-theme/_partials/order-extra-services.tpl @@ -53,20 +53,7 @@ {if $additionalService['allow_multiple_quantity']} {l s='(Quantity: %s)' sprintf=[$additionalService['quantity']|string_format:'%02d']} {/if} - {assign var='priceCalcMethod' value=$additionalService.price_calculation_method|default:0} - {capture name='htl_pcm_tooltip'} -
-
{l s='Applied on:'}
-
-
-
    - {foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'} -
  • {$pcmDayLabel}
  • - {/foreach} -
-
- {/capture} - {include file='_partials/ui-tooltip.tpl' tooltip_content=$smarty.capture.htl_pcm_tooltip allow_html=true} + {include file='_partials/service-applied-days.tpl' price_calculation_method=$additionalService.price_calculation_method|default:0 date_from=$roomAdditionalService['date_from'] date_to=$roomAdditionalService['date_to']}
{hook h='displayOrderDetailServiceProductNameBlockAfter' product_order_detail=$additionalService}
@@ -78,6 +65,9 @@ {displayPrice price=$additionalService['total_price_tax_excl']|escape:'html':'UTF-8' currency=$objOrder->id_currency} {/if} + {if ($additionalService.price_calculation_method|default:0) != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING} +
{if $useTax}{displayPrice price=$additionalService['unit_price_tax_incl']|escape:'html':'UTF-8' currency=$objOrder->id_currency}{else}{displayPrice price=$additionalService['unit_price_tax_excl']|escape:'html':'UTF-8' currency=$objOrder->id_currency}{/if} {l s='/Night'} + {/if}
{/foreach} diff --git a/themes/hotel-reservation-theme/_partials/service-applied-days.tpl b/themes/hotel-reservation-theme/_partials/service-applied-days.tpl new file mode 100644 index 000000000..304a8a330 --- /dev/null +++ b/themes/hotel-reservation-theme/_partials/service-applied-days.tpl @@ -0,0 +1,56 @@ +{** +* NOTICE OF LICENSE +* +* This source file is subject to the Open Software License version 3.0 +* that is bundled with this package in the file LICENSE.md +* It is also available through the world-wide-web at this URL: +* https://opensource.org/license/osl-3-0-php +* If you did not receive a copy of the license and are unable to +* obtain it through the world-wide-web, please send an email +* to support@qloapps.com so we can send you a copy immediately. +* +* DISCLAIMER +* +* Do not edit or add to this file if you wish to upgrade this module to a newer +* versions in the future. If you wish to customize this module for your needs +* please refer to https://store.webkul.com/customisation-guidelines for more information. +* +* @author Webkul IN +* @copyright Since 2010 Webkul +* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0 +*} + +{if isset($price_calculation_method) && (int) $price_calculation_method != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING && !empty($date_from) && !empty($date_to)} + {assign var='serviceAppliedDates' value=Product::getServicePriceApplicableDates($price_calculation_method, $date_from, $date_to)} + {assign var='serviceAppliedDays' value=0} + {foreach from=$serviceAppliedDates item='serviceAppliedGroupDates'} + {assign var='serviceAppliedDays' value=$serviceAppliedDays + count($serviceAppliedGroupDates)} + {/foreach} + {if $serviceAppliedDays} + {capture name='htl_applied_days_tooltip'} +
+
{l s='Applied on:'}
+
+
+ +
+ {/capture} + {capture name='htl_applied_days_badge'}{if $serviceAppliedDays == 1}{l s='Applied for 1 Day'}{else}{l s='Applied for %s Days' sprintf=$serviceAppliedDays}{/if}{/capture} +
+ {include file='_partials/ui-tooltip.tpl' tooltip_title=$smarty.capture.htl_applied_days_badge tooltip_content=$smarty.capture.htl_applied_days_tooltip allow_html=true} +
+ {/if} +{/if} 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 f82b7c8b4..4afef90b0 100644 --- a/themes/hotel-reservation-theme/_partials/service-products-list-row.tpl +++ b/themes/hotel-reservation-theme/_partials/service-products-list-row.tpl @@ -39,19 +39,6 @@
{$service_product['name']} {assign var='priceCalcMethod' value=$service_product.price_calculation_method|default:0} - {capture name='htl_pcm_tooltip'} -
-
{l s='Applied on:'}
-
-
-
    - {foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'} -
  • {$pcmDayLabel}
  • - {/foreach} -
-
- {/capture} - {include file='_partials/ui-tooltip.tpl' tooltip_content=$smarty.capture.htl_pcm_tooltip allow_html=true}
{/block} {block name='service_product_description'} @@ -68,7 +55,9 @@
{block name='service_product_price'} {if !$priceDisplay}{convertPrice price=$service_product.price_tax_incl}{else}{convertPrice price=$service_product.price_tax_exc}{/if} + {if $priceCalcMethod != Product::PRICE_CALCULATION_METHOD_ONCE_FOR_BOOKING}{l s='/Night'}{/if} {/block} + {include file='_partials/service-applied-days.tpl' price_calculation_method=$priceCalcMethod date_from=$service_product.stay_date_from|default:'' date_to=$service_product.stay_date_to|default:''} {if $service_product.allow_multiple_quantity && $service_product.available_for_order && $service_product.max_quantity > 0}
{l s='Maximum'} {$service_product.max_quantity} {l s='quantity can be added'}. diff --git a/themes/hotel-reservation-theme/css/global.css b/themes/hotel-reservation-theme/css/global.css index d70e202d5..677cbe9ee 100644 --- a/themes/hotel-reservation-theme/css/global.css +++ b/themes/hotel-reservation-theme/css/global.css @@ -9503,3 +9503,15 @@ div a.our_properties_link{ text-align: right; white-space: nowrap; } + +.service-applied-days { + display: inline-block; + font-size: 11px; + font-weight: 600; + line-height: 1.3; + background-color: #72c279; + color: #fff; + border-radius: 4px; + padding: 3px 9px; + vertical-align: text-top; +} \ No newline at end of file diff --git a/themes/hotel-reservation-theme/js/product.js b/themes/hotel-reservation-theme/js/product.js index 6b4505b41..d7261f66a 100644 --- a/themes/hotel-reservation-theme/js/product.js +++ b/themes/hotel-reservation-theme/js/product.js @@ -1114,7 +1114,7 @@ $(document).ready(function() { var ajax_check_var = ''; - $('#service_products_cont .get-service-products').on('click', function(e) { + $('#service_products_cont').on('click', '.get-service-products', function(e) { var triggerElement = $(this); var p = $(this).data('page'); var id_category = $(this).data('id_category'); @@ -1131,6 +1131,8 @@ $(document).ready(function() { id_category: id_category, p: p, id_product: $('#product_page_product_id').val(), + date_from: $('#room_check_in').val(), + date_to: $('#room_check_out').val(), action: 'getServiceProducts', ajax: true, token: static_token @@ -1393,7 +1395,7 @@ var BookingForm = { }).on('datepicker-change', function(event,obj){ $('#room_check_in').val($.datepicker.formatDate('yy-mm-dd', obj.date1)); $('#room_check_out').val($.datepicker.formatDate('yy-mm-dd', obj.date2)); - BookingForm.refresh(); + BookingForm.refresh(false, true); }); $('body button').on('click', '', function() { @@ -1413,9 +1415,12 @@ var BookingForm = { formData.append('room_service_products', JSON.stringify(getRoomsServiceProducts())); return formData; }, - refresh: function(resetOccupancy = false) { + refresh: function(resetOccupancy = false, refreshServices = false) { return new Promise((resolve, reject) => { let formData = BookingForm.getFormData(); + if (refreshServices) { + formData.append('refresh_services', 1); + } formData.append('ajax', true); formData.append('action', 'refreshBookingForm'); BookingForm.currentRequest = $.ajax({ @@ -1438,6 +1443,19 @@ var BookingForm = { $('.booking-form').replaceWith(response.html_booking_form); BookingForm.init(); + if (typeof response.html_service_products !== 'undefined') { + $('#service_products_cont').html(response.html_service_products); + initUITooltip(); + $('#additional_products input.service_product').each(function () { + let id = $(this).data('id_product'); + $('#room_service_product_qty_' + id).val($(this).val()).closest('.qty_container').find('.qty_count span').text($(this).val()); + $('.select_room_service_' + id).text(unselect_txt).removeClass('btn-success add_roomtype_product').addClass('btn-danger remove_roomtype_product'); + }); + if (!$('.max_avail_type_qty').length || $('.max_avail_type_qty').val() < 1) { + disableRoomTypeServices(1); + } + } + if (resetOccupancy) { BookingForm.resetOccupancy(); } From 793ed6fee2474366daaf39cf6924ac24dec84d90 Mon Sep 17 00:00:00 2001 From: amit sharma Date: Mon, 2 Nov 2026 18:44:10 +0530 Subject: [PATCH 05/15] Added: Support for plural names in MP themes --- .../classes/HotelHelper.php | 85 +++++++++++++++---- .../classes/HotelPropertyType.php | 5 +- .../classes/HotelReservationSystemDb.php | 1 + .../AdminHotelPropertyTypesController.php | 24 ++++++ 4 files changed, 96 insertions(+), 19 deletions(-) diff --git a/modules/hotelreservationsystem/classes/HotelHelper.php b/modules/hotelreservationsystem/classes/HotelHelper.php index d8f9b10d2..db3e44d19 100644 --- a/modules/hotelreservationsystem/classes/HotelHelper.php +++ b/modules/hotelreservationsystem/classes/HotelHelper.php @@ -1312,30 +1312,79 @@ class HotelHelper public function createHotelDefaultPropertyTypes() { $propertyTypes = array( - 'Hotel', - 'Motel', - 'Resort', - 'Hostel', - 'Guest House', - 'Bed & Breakfast', - 'Lodge', - 'Apartment', - 'Vacation Rental', - 'Homestay', - 'Co-Living', - 'Camping', - 'Glamping', - 'Farm Stay', - 'Houseboat', - 'Boat Stay', + array( + 'name' => 'Hotel', + 'plural_name' => 'Hotels', + ), + array( + 'name' => 'Motel', + 'plural_name' => 'Motels', + ), + array( + 'name' => 'Resort', + 'plural_name' => 'Resorts', + ), + array( + 'name' => 'Hostel', + 'plural_name' => 'Hostels', + ), + array( + 'name' => 'Guest House', + 'plural_name' => 'Guest Houses', + ), + array( + 'name' => 'Bed & Breakfast', + 'plural_name' => 'Bed & Breakfasts', + ), + array( + 'name' => 'Lodge', + 'plural_name' => 'Lodges', + ), + array( + 'name' => 'Apartment', + 'plural_name' => 'Apartments', + ), + array( + 'name' => 'Vacation Rental', + 'plural_name' => 'Vacation Rentals', + ), + array( + 'name' => 'Homestay', + 'plural_name' => 'Homestays', + ), + array( + 'name' => 'Co-Living', + 'plural_name' => 'Co-Livings', + ), + array( + 'name' => 'Camping', + 'plural_name' => 'Campings', + ), + array( + 'name' => 'Glamping', + 'plural_name' => 'Glampings', + ), + array( + 'name' => 'Farm Stay', + 'plural_name' => 'Farm Stays', + ), + array( + 'name' => 'Houseboat', + 'plural_name' => 'Houseboats', + ), + array( + 'name' => 'Boat Stay', + 'plural_name' => 'Boat Stays', + ), ); $languages = Language::getLanguages(true); - foreach ($propertyTypes as $typeName) { + foreach ($propertyTypes as $propertyType) { $objType = new HotelPropertyType(); $objType->active = 1; foreach ($languages as $lang) { - $objType->name[$lang['id_lang']] = $typeName; + $objType->name[$lang['id_lang']] = $propertyType['name']; + $objType->plural_name[$lang['id_lang']] = $propertyType['plural_name']; } $objType->save(); } diff --git a/modules/hotelreservationsystem/classes/HotelPropertyType.php b/modules/hotelreservationsystem/classes/HotelPropertyType.php index 14dde5724..c1486e8af 100644 --- a/modules/hotelreservationsystem/classes/HotelPropertyType.php +++ b/modules/hotelreservationsystem/classes/HotelPropertyType.php @@ -27,6 +27,7 @@ class HotelPropertyType extends ObjectModel public $date_add; public $date_upd; public $name; + public $plural_name; public static $definition = array( 'table' => 'htl_property_type', @@ -37,6 +38,7 @@ class HotelPropertyType extends ObjectModel 'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false), 'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false), 'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 255), + 'plural_name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 255), ), ); @@ -46,6 +48,7 @@ class HotelPropertyType extends ObjectModel 'objectMethods' => array('update' => 'updateWs', 'delete' => 'deleteWs'), 'fields' => array( 'name' => array('required' => true), + 'plural_name' => array('required' => true), 'active' => array('required' => false), ), ); @@ -121,7 +124,7 @@ class HotelPropertyType extends ObjectModel $cacheKey = 'HotelPropertyType::getPropertyTypes'.$idLang.'_'.(int) $active; if (!Cache::isStored($cacheKey)) { - $sql = 'SELECT hpt.`id_htl_property_type` AS `id_property_type`, hptl.`name` + $sql = 'SELECT hpt.`id_htl_property_type` AS `id_property_type`, hptl.`name`, hptl.`plural_name` FROM `'._DB_PREFIX_.'htl_property_type` hpt LEFT JOIN `'._DB_PREFIX_.'htl_property_type_lang` hptl ON (hpt.`id_htl_property_type` = hptl.`id_htl_property_type` diff --git a/modules/hotelreservationsystem/classes/HotelReservationSystemDb.php b/modules/hotelreservationsystem/classes/HotelReservationSystemDb.php index 32542bc30..d2fca3b04 100644 --- a/modules/hotelreservationsystem/classes/HotelReservationSystemDb.php +++ b/modules/hotelreservationsystem/classes/HotelReservationSystemDb.php @@ -142,6 +142,7 @@ class HotelReservationSystemDb `id_htl_property_type` int(10) unsigned NOT NULL, `id_lang` int(10) unsigned NOT NULL, `name` varchar(255) NOT NULL, + `plural_name` varchar(255) NOT NULL, PRIMARY KEY (`id_htl_property_type`, `id_lang`) ) ENGINE="._MYSQL_ENGINE_." DEFAULT CHARSET=utf8;", "CREATE TABLE IF NOT EXISTS `"._DB_PREFIX_."htl_branch_amenity` ( diff --git a/modules/hotelreservationsystem/controllers/admin/AdminHotelPropertyTypesController.php b/modules/hotelreservationsystem/controllers/admin/AdminHotelPropertyTypesController.php index d3485a680..e59a8e6be 100644 --- a/modules/hotelreservationsystem/controllers/admin/AdminHotelPropertyTypesController.php +++ b/modules/hotelreservationsystem/controllers/admin/AdminHotelPropertyTypesController.php @@ -45,6 +45,10 @@ class AdminHotelPropertyTypesController extends ModuleAdminController 'title' => $this->l('Name'), 'align' => 'left', ), + 'plural_name' => array( + 'title' => $this->l('Plural Name'), + 'align' => 'left', + ), 'active' => array( 'title' => $this->l('Status'), 'align' => 'center', @@ -109,6 +113,14 @@ class AdminHotelPropertyTypesController extends ModuleAdminController 'required' => true, 'hint' => $this->l('Displayed name for this property type.'), ), + array( + 'type' => 'text', + 'label' => $this->l('Plural Name'), + 'name' => 'plural_name', + 'lang' => true, + 'required' => true, + 'hint' => $this->l('Displayed name when referring to more than one property of this type.'), + ), array( 'type' => 'switch', 'label' => $this->l('Enabled'), @@ -166,6 +178,18 @@ class AdminHotelPropertyTypesController extends ModuleAdminController } } + if (!trim(Tools::getValue('plural_name_'.$defaultLangId))) { + $this->errors[] = $this->l('Plural Name is required at least in ').$objDefaultLanguage['name']; + } else { + foreach ($languages as $lang) { + if (trim(Tools::getValue('plural_name_'.$lang['id_lang']))) { + if (!Validate::isGenericName(Tools::getValue('plural_name_'.$lang['id_lang']))) { + $this->errors[] = $this->l('Invalid Plural Name in ').$lang['name']; + } + } + } + } + $this->display = $idPropertyType ? 'edit' : 'add'; if (!$this->errors && !Tools::getValue('active') && $idPropertyType) { From 01aed22bfeb9041e0b403203e601f9d5e5d85200 Mon Sep 17 00:00:00 2001 From: shazar rahman Date: Mon, 2 Nov 2026 19:03:57 +0530 Subject: [PATCH 06/15] Fixed: admin order, cart, email, receipt and cart rule issues on back office Co-authored-by: Name --- .../helpers/list/_hotel_names_tooltip.tpl | 2 +- classes/order/Order.php | 21 +++++++++++++++++++ .../admin/AdminCartRulesController.php | 4 ++-- controllers/admin/AdminCartsController.php | 2 +- controllers/admin/AdminEmailsController.php | 4 ++-- controllers/admin/AdminOrdersController.php | 16 +++++++++++++- .../admin/AdminPaymentReceiptsController.php | 2 +- install-dev/data/xml/configuration.xml | 2 +- install-dev/langs/en/data/configuration.xml | 2 +- js/admin/orders.js | 6 ++++++ .../classes/HotelHelper.php | 4 ++-- 11 files changed, 53 insertions(+), 12 deletions(-) diff --git a/admin-dev/themes/default/template/controllers/cart_rules/helpers/list/_hotel_names_tooltip.tpl b/admin-dev/themes/default/template/controllers/cart_rules/helpers/list/_hotel_names_tooltip.tpl index eca4b71f3..79ec1a464 100644 --- a/admin-dev/themes/default/template/controllers/cart_rules/helpers/list/_hotel_names_tooltip.tpl +++ b/admin-dev/themes/default/template/controllers/cart_rules/helpers/list/_hotel_names_tooltip.tpl @@ -25,7 +25,7 @@ {if $hotel_names_remaining} {capture name='hotel_names_tooltip'}
-
{l s='Selected Hotels'}
+
{l s='Selected Properties'}
    {foreach from=$selected_hotels item='hotel'}
  • {$hotel|escape:'html':'UTF-8'}
  • diff --git a/classes/order/Order.php b/classes/order/Order.php index cca685821..969bab3fb 100644 --- a/classes/order/Order.php +++ b/classes/order/Order.php @@ -2831,6 +2831,27 @@ class OrderCore extends ObjectModel return Db::getInstance()->executeS('SELECT * FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$id_cart); } + /** + * Get all orders linked to a cart, either as the order's own cart or through a room + * added to an existing order from the back office (that creates a new cart whose + * rooms belong to the order, while orders.id_cart still points at the original cart). + * + * @param int $idCart + * @return array of orders + */ + public static function getAllOrdersLinkedToCart($idCart) + { + return Db::getInstance()->executeS( + 'SELECT o.* FROM `'._DB_PREFIX_.'orders` o + WHERE o.`id_cart` = '.(int) $idCart.' + OR o.`id_order` IN ( + SELECT hbd.`id_order` FROM `'._DB_PREFIX_.'htl_booking_detail` hbd + WHERE hbd.`id_cart` = '.(int) $idCart.' + ) + ORDER BY o.`id_order` ASC' + ); + } + /** * Function to check if order has been completely refunded * @param integer action: can have 3 values as below diff --git a/controllers/admin/AdminCartRulesController.php b/controllers/admin/AdminCartRulesController.php index b534652bc..4c2c6aab0 100644 --- a/controllers/admin/AdminCartRulesController.php +++ b/controllers/admin/AdminCartRulesController.php @@ -47,7 +47,7 @@ class AdminCartRulesControllerCore extends AdminController $this->fields_list = array( 'id_cart_rule' => array('title' => $this->l('ID'), 'align' => 'center', 'class' => 'fixed-width-xs'), 'name' => array('title' => $this->l('Name')), - 'hotel_names' => array('title' => $this->l('Hotels'), 'orderby' => false, 'havingFilter' => true, 'filter_key' => 'hotel_names', 'callback' => 'formatHotelNames'), + 'hotel_names' => array('title' => $this->l('Property'), 'orderby' => false, 'havingFilter' => true, 'filter_key' => 'hotel_names', 'callback' => 'formatHotelNames'), 'priority' => array('title' => $this->l('Priority'), 'align' => 'center', 'class' => 'fixed-width-xs'), 'code' => array('title' => $this->l('Code'), 'class' => 'fixed-width-sm'), 'quantity' => array('title' => $this->l('Quantity'), 'align' => 'center', 'class' => 'fixed-width-xs'), @@ -274,7 +274,7 @@ class AdminCartRulesControllerCore extends AdminController Media::addJsDef( array( 'admin_cart_rule_tab_link' => $this->context->link->getAdminLink('AdminCartRules'), - 'room_access_err' => $this->l('You can only select room types which hotel(s) access is provided to this employee.'), + 'room_access_err' => $this->l('You can only select room types of the properties this employee has access to.'), 'room_rmv_txt' => $this->l('Unselect below room types'), ) ); diff --git a/controllers/admin/AdminCartsController.php b/controllers/admin/AdminCartsController.php index bbdf664fa..253266e3d 100644 --- a/controllers/admin/AdminCartsController.php +++ b/controllers/admin/AdminCartsController.php @@ -286,7 +286,7 @@ class AdminCartsControllerCore extends AdminController $summary = $cart->getSummaryDetails(); /* Display orders information */ - $cartOrders = Order::getAllOrdersByCartId($cart->id); + $cartOrders = Order::getAllOrdersLinkedToCart($cart->id); if ($cartOrders) { $objOrder = new Order($cartOrders[0]['id_order']); if (Validate::isLoadedObject($objOrder)) { diff --git a/controllers/admin/AdminEmailsController.php b/controllers/admin/AdminEmailsController.php index 77587ce49..3510af693 100644 --- a/controllers/admin/AdminEmailsController.php +++ b/controllers/admin/AdminEmailsController.php @@ -119,7 +119,7 @@ class AdminEmailsControllerCore extends AdminController 'type' => 'bool' ) ), - 'submit' => array('title' => $this->l('Save')) + 'submit' => array('title' => $this->l('Save'), 'name' => 'submitOptions') ), 'smtp' => array( 'title' => $this->l('Email'), @@ -181,7 +181,7 @@ class AdminEmailsControllerCore extends AdminController 'class' => 'fixed-width-sm' ), ), - 'submit' => array('title' => $this->l('Save')) + 'submit' => array('title' => $this->l('Save'), 'name' => 'submitOptions') ), 'test' => array( 'title' => $this->l('Test your email configuration'), diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php index bbed3db59..ffe856f1d 100644 --- a/controllers/admin/AdminOrdersController.php +++ b/controllers/admin/AdminOrdersController.php @@ -481,7 +481,15 @@ class AdminOrdersControllerCore extends AdminController } if ($this->tabAccess['edit'] === 1) { - if ((int) $order->isReturnable()) { + // nothing left to refund once every room and service line is deleted + // (amount is not checked: a free order can still be refunded) + $objHotelBookingDetail = new HotelBookingDetail(); + $objServiceProductOrderDetail = new ServiceProductOrderDetail(); + if ((int) $order->isReturnable() + && ($objHotelBookingDetail->getBookingDataByOrderId($order->id) + || $objServiceProductOrderDetail->getServiceProductsInOrder($order->id) + ) + ) { // always "Initiate refund" now, regardless of order status — // cancelling a booking happens through Room Status only $this->page_header_toolbar_btn['cancel'] = array( @@ -7219,6 +7227,12 @@ class AdminOrdersControllerCore extends AdminController $order_invoice->total_discount_tax_excl = 0; $res &= $order_invoice->update(); } + + // the order's own discount totals must follow the deleted cart rules + $order->total_discounts = 0; + $order->total_discounts_tax_incl = 0; + $order->total_discounts_tax_excl = 0; + $res &= $order->update(); } if (isset($order_invoice) && $order_invoice->id) { diff --git a/controllers/admin/AdminPaymentReceiptsController.php b/controllers/admin/AdminPaymentReceiptsController.php index 1ca890269..4e844f549 100644 --- a/controllers/admin/AdminPaymentReceiptsController.php +++ b/controllers/admin/AdminPaymentReceiptsController.php @@ -43,7 +43,7 @@ class AdminPaymentReceiptsControllerCore extends AdminControllerCore ), 'PS_PAYMENT_RECEIPTS_PREFIX' => array( 'title' => $this->l('Receipt prefix'), - 'desc' => $this->l('Prefix used for receipt name (e.g. #IN00001).'), + 'desc' => $this->l('Prefix used for receipt name (e.g. REC000001).'), 'size' => 6, 'type' => 'textLang' ), diff --git a/install-dev/data/xml/configuration.xml b/install-dev/data/xml/configuration.xml index 6c7728f25..24e4114ba 100644 --- a/install-dev/data/xml/configuration.xml +++ b/install-dev/data/xml/configuration.xml @@ -135,7 +135,7 @@ #IN - #IN + REC {"avoid":[]} diff --git a/install-dev/langs/en/data/configuration.xml b/install-dev/langs/en/data/configuration.xml index 610649713..e108a1b05 100644 --- a/install-dev/langs/en/data/configuration.xml +++ b/install-dev/langs/en/data/configuration.xml @@ -4,7 +4,7 @@ #IN - #IN + REC #DE diff --git a/js/admin/orders.js b/js/admin/orders.js index 0ab218d7d..262f2d6bc 100644 --- a/js/admin/orders.js +++ b/js/admin/orders.js @@ -1643,10 +1643,16 @@ $(document).ready(function() { }); $(document).on('click', '#initiateRefund', function(e) { + if ($(this).data('submitted')) { + return false; + } + if ($.trim($('.cancellation_reason').val()) == '') { $('.cancellation_reason').focus().css('border', '1px solid red'); return false; } + + $(this).data('submitted', true); }); // End: CancelRoomBookingModal: Processes // ====================================== diff --git a/modules/hotelreservationsystem/classes/HotelHelper.php b/modules/hotelreservationsystem/classes/HotelHelper.php index d8f9b10d2..3ebcaffb3 100644 --- a/modules/hotelreservationsystem/classes/HotelHelper.php +++ b/modules/hotelreservationsystem/classes/HotelHelper.php @@ -1532,7 +1532,7 @@ class HotelHelper ), array( 'id' => HotelBookingDetail::STATUS_NO_SHOW, - 'color' => '#DC143C', + 'color' => '#FF8C00', 'is_terminal' => 1, 'name' => array( 'en' => 'No-show', @@ -1545,7 +1545,7 @@ class HotelHelper ), array( 'id' => HotelBookingDetail::STATUS_CANCELLED, - 'color' => '#FF8C00', + 'color' => '#DC143C', 'is_terminal' => 1, 'name' => array( 'en' => 'Cancelled', From de84509965700ed04ec788158435837175d64096 Mon Sep 17 00:00:00 2001 From: shazar rahman Date: Mon, 2 Nov 2026 20:07:40 +0530 Subject: [PATCH 07/15] Fixed: code review changes made in cart rule page Co-authored-by: Name --- controllers/admin/AdminCartRulesController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/admin/AdminCartRulesController.php b/controllers/admin/AdminCartRulesController.php index 4c2c6aab0..a79ca2d5e 100644 --- a/controllers/admin/AdminCartRulesController.php +++ b/controllers/admin/AdminCartRulesController.php @@ -47,7 +47,7 @@ class AdminCartRulesControllerCore extends AdminController $this->fields_list = array( 'id_cart_rule' => array('title' => $this->l('ID'), 'align' => 'center', 'class' => 'fixed-width-xs'), 'name' => array('title' => $this->l('Name')), - 'hotel_names' => array('title' => $this->l('Property'), 'orderby' => false, 'havingFilter' => true, 'filter_key' => 'hotel_names', 'callback' => 'formatHotelNames'), + 'hotel_names' => array('title' => $this->l('Properties'), 'orderby' => false, 'havingFilter' => true, 'filter_key' => 'hotel_names', 'callback' => 'formatHotelNames'), 'priority' => array('title' => $this->l('Priority'), 'align' => 'center', 'class' => 'fixed-width-xs'), 'code' => array('title' => $this->l('Code'), 'class' => 'fixed-width-sm'), 'quantity' => array('title' => $this->l('Quantity'), 'align' => 'center', 'class' => 'fixed-width-xs'), From 611ab5496df0d9045d00a4de4efacc79ebb0bc48 Mon Sep 17 00:00:00 2001 From: amit sharma Date: Tue, 3 Nov 2026 10:23:57 +0530 Subject: [PATCH 08/15] Fixed: review changes --- .../views/js/WkAboutHotelBlockFront.js | 10 +++++++++- .../admin/AdminHotelRoomModuleSettingController.php | 2 +- .../wkhotelroom/views/css/WkHotelRoomBlockFront.css | 7 +++++++ modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js | 10 +++++++++- .../views/templates/hook/hotelRoomDisplayBlock.tpl | 2 +- 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/modules/wkabouthotelblock/views/js/WkAboutHotelBlockFront.js b/modules/wkabouthotelblock/views/js/WkAboutHotelBlockFront.js index d934449b0..b9c657ac6 100644 --- a/modules/wkabouthotelblock/views/js/WkAboutHotelBlockFront.js +++ b/modules/wkabouthotelblock/views/js/WkAboutHotelBlockFront.js @@ -34,13 +34,21 @@ $(document).ready(function(){ responsive: {576: {items: 2}}, autoHeight:true, autoplay: htlInteriorSliderAutoplay, - autoplaySpeed:1000, + autoplaySpeed: 500, + smartSpeed: 500, autoplayTimeout: htlInteriorSliderInterval, autoplayHoverPause:true, responsiveClass:true, rtl: language_is_rtl }); + $('.htlInterior-owlCarousel .owl-carousel').on('translated.owl.carousel mouseleave', function() { + var owl = $(this).data('owl.carousel'); + if (owl && owl.settings.autoplay && owl._plugins.autoplay && !owl._plugins.autoplay._paused) { + owl._plugins.autoplay._setAutoPlayInterval(); + } + }); + $('.interiorbox').on('mouseenter', function(){ $(this).find('div.interiorHoverBlockWrapper').show(); }); diff --git a/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php b/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php index 689d4d4aa..24dc1d1dd 100644 --- a/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php +++ b/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php @@ -66,7 +66,7 @@ class AdminHotelRoomModuleSettingController extends ModuleAdminController 'hint' => $this->l('Enter a description for the property rooms block.'), ), 'HOTEL_ROOM_DISPLAY_PROPERTY' => array( - 'title' => $this->l('Display property name and city'), + 'title' => $this->l('Property location'), 'cast' => 'intval', 'type' => 'bool', 'default' => '0', diff --git a/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css b/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css index 7942dea92..8ffc0d805 100644 --- a/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css +++ b/modules/wkhotelroom/views/css/WkHotelRoomBlockFront.css @@ -134,6 +134,13 @@ a.htlRoomTypeBookNow { margin: 0 0 12px; font-size: 22px; } +.htlRoomTypeNameText a:focus, +.htlRoomTypeNameText a:active, +.htlRoomCardImg:focus, +.htlRoomTypeBookNow:focus { + outline: none; + text-decoration: none; +} .htlRoomCardFeatured { padding: 12px 0; overflow: hidden; diff --git a/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js b/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js index 91fca4bdb..6de1d6476 100644 --- a/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js +++ b/modules/wkhotelroom/views/js/WkHotelRoomBlockFront.js @@ -91,7 +91,8 @@ $(document).ready(function() { dots: htlRoomSliderDots, autoplay: htlRoomSliderAutoplay, autoplayTimeout: htlRoomSliderInterval, - autoplaySpeed: 1000, + autoplaySpeed: 500, + smartSpeed: 500, autoplayHoverPause: true, margin: 24, items: 1, @@ -101,6 +102,13 @@ $(document).ready(function() { 992: { items: 3 } } }); + + $('.htlRoom-owlCarousel .owl-carousel').on('translated.owl.carousel mouseleave', function() { + var owl = $(this).data('owl.carousel'); + if (owl && owl.settings.autoplay && owl._plugins.autoplay && !owl._plugins.autoplay._paused) { + owl._plugins.autoplay._setAutoPlayInterval(); + } + }); // fonts and icons can change the widths after the page is shown $(window).on('load', function() { fitRoomCards($('.htlRoom-owlCarousel .owl-carousel')); diff --git a/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl b/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl index 4871fc517..3e2989d8d 100644 --- a/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl +++ b/modules/wkhotelroom/views/templates/hook/hotelRoomDisplayBlock.tpl @@ -53,7 +53,7 @@ {/block}
    {block name='hotel_room_block_room_type_description'} -

    {$roomDisplay.name|escape:'htmlall':'UTF-8'}

    +

    {$roomDisplay.name|escape:'htmlall':'UTF-8'}

    {if isset($roomDisplay.property_name) && $roomDisplay.property_name}

    {$roomDisplay.property_name|escape:'htmlall':'UTF-8'}{if isset($roomDisplay.property_location) && $roomDisplay.property_location}, {$roomDisplay.property_location|escape:'htmlall':'UTF-8'}{/if} From 9a752f53512f4485e61649fd01dc4d971e13095c Mon Sep 17 00:00:00 2001 From: amit sharma Date: Tue, 3 Nov 2026 11:00:35 +0530 Subject: [PATCH 09/15] Fixed: review changes --- admin-dev/themes/default/sass/partials/_tooltip.sass | 3 +++ .../orders/modals/_add_order_extra_services_tab_content.tpl | 2 +- .../modals/_extra_services_service_products_tab_content.tpl | 6 +++--- .../orders/modals/_partials}/service-applied-days.tpl | 2 +- .../_partials/service-applied-days.tpl | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) rename admin-dev/themes/default/template/{helpers => controllers/orders/modals/_partials}/service-applied-days.tpl (96%) diff --git a/admin-dev/themes/default/sass/partials/_tooltip.sass b/admin-dev/themes/default/sass/partials/_tooltip.sass index f3ef5f4b2..2c895029a 100644 --- a/admin-dev/themes/default/sass/partials/_tooltip.sass +++ b/admin-dev/themes/default/sass/partials/_tooltip.sass @@ -42,3 +42,6 @@ .ui-tooltip-label font-weight: 600 margin: 0 + +.label.label-success.service-applied-days + font-size: 11px diff --git a/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl b/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl index e0576ca6c..921b14258 100644 --- a/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl +++ b/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl @@ -64,7 +64,7 @@

    {$product['name']|escape:'html':'UTF-8'} - {include file='helpers/service-applied-days.tpl' price_calculation_method=$product['price_calculation_method'] date_from=$selectedRoomServiceProduct['date_from']|default:'' date_to=$selectedRoomServiceProduct['date_to']|default:''} + {include file='controllers/orders/modals/_partials/service-applied-days.tpl' price_calculation_method=$product['price_calculation_method'] date_from=$selectedRoomServiceProduct['date_from']|default:'' date_to=$selectedRoomServiceProduct['date_to']|default:''}
    diff --git a/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl b/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl index 25a65d039..06ab15b48 100644 --- a/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl +++ b/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl @@ -56,7 +56,7 @@
    {$service['name']|escape:'html':'UTF-8'} - {include file='helpers/service-applied-days.tpl' price_calculation_method=$service['price_calculation_method']|default:0 date_from=$additionalServices['date_from'] date_to=$additionalServices['date_to']} + {include file='controllers/orders/modals/_partials/service-applied-days.tpl' price_calculation_method=$service['price_calculation_method']|default:0 date_from=$additionalServices['date_from'] date_to=$additionalServices['date_to']}
    @@ -137,7 +137,7 @@ {$product['name']|escape:'html':'UTF-8'} - {include file='helpers/service-applied-days.tpl' price_calculation_method=$product['price_calculation_method'] date_from=$date_from|default:'' date_to=$date_to|default:''} + {include file='controllers/orders/modals/_partials/service-applied-days.tpl' price_calculation_method=$product['price_calculation_method'] date_from=$date_from|default:'' date_to=$date_to|default:''} {if $product['auto_add_to_cart'] && $product['price_addition_type'] == Product::PRICE_ADDITION_TYPE_WITH_ROOM} @@ -305,7 +305,7 @@ {$service['name']|escape:'html':'UTF-8'} - {include file='helpers/service-applied-days.tpl' price_calculation_method=$service['price_calculation_method']|default:0 date_from=$additionalServices['date_from'] date_to=$additionalServices['date_to']} + {include file='controllers/orders/modals/_partials/service-applied-days.tpl' price_calculation_method=$service['price_calculation_method']|default:0 date_from=$additionalServices['date_from'] date_to=$additionalServices['date_to']} {if $service['product_auto_add'] && $service['product_price_addition_type'] == Product::PRICE_ADDITION_TYPE_INDEPENDENT} diff --git a/admin-dev/themes/default/template/helpers/service-applied-days.tpl b/admin-dev/themes/default/template/controllers/orders/modals/_partials/service-applied-days.tpl similarity index 96% rename from admin-dev/themes/default/template/helpers/service-applied-days.tpl rename to admin-dev/themes/default/template/controllers/orders/modals/_partials/service-applied-days.tpl index 2e8e4d5e1..aa905b482 100644 --- a/admin-dev/themes/default/template/helpers/service-applied-days.tpl +++ b/admin-dev/themes/default/template/controllers/orders/modals/_partials/service-applied-days.tpl @@ -39,7 +39,7 @@ {if $serviceAppliedGroup == 'checkin'}{l s='Check-in day'}{elseif $serviceAppliedGroup == 'stay'}{l s='During-stay days'}{else}{l s='Check-out day'}{/if}
      {foreach from=$serviceAppliedGroupDates item='serviceAppliedDate'} -
    • {$serviceAppliedDate|date_format:'%d-%m-%Y'}
    • +
    • {Tools::displayDate($serviceAppliedDate)}
    • {/foreach}
    diff --git a/themes/hotel-reservation-theme/_partials/service-applied-days.tpl b/themes/hotel-reservation-theme/_partials/service-applied-days.tpl index 304a8a330..3c426c4b6 100644 --- a/themes/hotel-reservation-theme/_partials/service-applied-days.tpl +++ b/themes/hotel-reservation-theme/_partials/service-applied-days.tpl @@ -39,7 +39,7 @@ {if $serviceAppliedGroup == 'checkin'}{l s='Check-in day'}{elseif $serviceAppliedGroup == 'stay'}{l s='During-stay days'}{else}{l s='Check-out day'}{/if}
      {foreach from=$serviceAppliedGroupDates item='serviceAppliedDate'} -
    • {$serviceAppliedDate|date_format:'%d-%m-%Y'}
    • +
    • {Tools::displayDate($serviceAppliedDate)}
    • {/foreach}
    From 34e178b287689737e6c86d6f3760bcca532b6052 Mon Sep 17 00:00:00 2001 From: amit sharma Date: Tue, 3 Nov 2026 12:59:35 +0530 Subject: [PATCH 10/15] Added : add hook in service product tab and also fix issue a related to display tax amount --- .../default/template/controllers/orders/helpers/view/view.tpl | 4 ++-- .../_partials/service-products-list-row.tpl | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/admin-dev/themes/default/template/controllers/orders/helpers/view/view.tpl b/admin-dev/themes/default/template/controllers/orders/helpers/view/view.tpl index b6c97c962..b364c3140 100644 --- a/admin-dev/themes/default/template/controllers/orders/helpers/view/view.tpl +++ b/admin-dev/themes/default/template/controllers/orders/helpers/view/view.tpl @@ -928,7 +928,7 @@ {/if} - {if isset($total_room_services_tax_excl) && $total_room_services_tax_excl > 0} + {if isset($total_room_services_tax_excl) && ($total_room_services_tax_excl - $total_convenience_fee_tax_excl) > 0} {l s='Total Extra services (Tax excl.)'} @@ -1036,7 +1036,7 @@ {/if} - {if isset($total_convenience_fee_tax_excl) && $total_convenience_fee_tax_excl > 0} + {if isset($total_convenience_fee_tax_only) && $total_convenience_fee_tax_only > 0} {l s='Convenience Fee Tax'} 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 4afef90b0..1432c8829 100644 --- a/themes/hotel-reservation-theme/_partials/service-products-list-row.tpl +++ b/themes/hotel-reservation-theme/_partials/service-products-list-row.tpl @@ -63,6 +63,9 @@ {l s='Maximum'} {$service_product.max_quantity} {l s='quantity can be added'}.
{/if} + {block name='displayServiceProductActionsAfter'} + {hook h='displayServiceProductActionsAfter' id_service_product=$service_product['id_product']} + {/block}
{/if} {/block} From fbe9eed5a3a2e70e19e69a165af336ae23ccfd9c Mon Sep 17 00:00:00 2001 From: amit sharma Date: Tue, 3 Nov 2026 16:08:21 +0530 Subject: [PATCH 11/15] Fixed: tooltip body scrolling issue --- admin-dev/themes/default/sass/partials/_tooltip.sass | 3 ++- themes/hotel-reservation-theme/css/global.css | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/admin-dev/themes/default/sass/partials/_tooltip.sass b/admin-dev/themes/default/sass/partials/_tooltip.sass index 2c895029a..0779ca8b1 100644 --- a/admin-dev/themes/default/sass/partials/_tooltip.sass +++ b/admin-dev/themes/default/sass/partials/_tooltip.sass @@ -21,7 +21,8 @@ margin-bottom: 5px .ui-tooltip-body - + max-height: 250px; + overflow-y: auto; > div margin-bottom: 6px margin-right: 10px diff --git a/themes/hotel-reservation-theme/css/global.css b/themes/hotel-reservation-theme/css/global.css index 677cbe9ee..ed0870c60 100644 --- a/themes/hotel-reservation-theme/css/global.css +++ b/themes/hotel-reservation-theme/css/global.css @@ -9495,6 +9495,8 @@ div a.our_properties_link{ display: grid; grid-template-columns: auto 1fr; gap: 5px 15px; + max-height: 250px; + overflow-y: auto; } .ui-tooltip-elem-txt { From e338075938bee817f6fee338ee545d5e125f0424 Mon Sep 17 00:00:00 2001 From: amit sharma Date: Tue, 3 Nov 2026 16:42:56 +0530 Subject: [PATCH 12/15] Fixed: property location tooltip title --- .../controllers/admin/AdminHotelRoomModuleSettingController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php b/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php index 24dc1d1dd..9ca9877ac 100644 --- a/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php +++ b/modules/wkhotelroom/controllers/admin/AdminHotelRoomModuleSettingController.php @@ -70,7 +70,7 @@ class AdminHotelRoomModuleSettingController extends ModuleAdminController 'cast' => 'intval', 'type' => 'bool', 'default' => '0', - 'hint' => $this->l('Show the property name and the city under the room type name in the room cards.'), + 'hint' => $this->l('Display the property location below the room type name in the room cards, or hide it if it is not required.'), ), 'HOTEL_ROOM_DISPLAY_NAV_TYPE' => array( 'title' => $this->l('Navigation Type'), From 5c439863c3134450b8515f3ef2b579c3f8b612ae Mon Sep 17 00:00:00 2001 From: amit sharma Date: Tue, 3 Nov 2026 17:12:56 +0530 Subject: [PATCH 13/15] Updated: change add service ui --- .../_add_order_extra_services_tab_content.tpl | 66 ++++++++---------- ..._services_service_products_tab_content.tpl | 68 +++++++++---------- 2 files changed, 61 insertions(+), 73 deletions(-) diff --git a/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl b/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl index 921b14258..c17bb8606 100644 --- a/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl +++ b/admin-dev/themes/default/template/controllers/orders/modals/_add_order_extra_services_tab_content.tpl @@ -131,40 +131,6 @@
-
- - - -
@@ -181,8 +147,6 @@
-
-
+
+
+
+ + +
+
+
diff --git a/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl b/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl index 06ab15b48..faa574de8 100644 --- a/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl +++ b/admin-dev/themes/default/template/controllers/orders/modals/_extra_services_service_products_tab_content.tpl @@ -195,40 +195,6 @@
-
- - - -
@@ -245,9 +211,7 @@
-
-
-
+
+
+
+
+ + +
+
+ {if $roomTypeTaxRuleGroupExist}
From 7897bbc894b9dfa6fb7ebcbb45fdf9225e1a923d Mon Sep 17 00:00:00 2001 From: shazar rahman Date: Tue, 3 Nov 2026 17:44:52 +0530 Subject: [PATCH 14/15] Fixed: form values are not escaped in back office Co-authored-by: Name --- .../admin/AdminSearchConfController.php | 4 ++-- .../helpers/form/form.tpl | 4 ++-- .../admin/add_hotel/helpers/form/form.tpl | 24 +++++++++---------- .../helpers/form/form.tpl | 4 ++-- .../order_refund_rules/helpers/form/form.tpl | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/controllers/admin/AdminSearchConfController.php b/controllers/admin/AdminSearchConfController.php index 00d2daab7..5809d2d56 100644 --- a/controllers/admin/AdminSearchConfController.php +++ b/controllers/admin/AdminSearchConfController.php @@ -335,11 +335,11 @@ class AdminSearchConfControllerCore extends AdminController $this->errors[] = $this->l('Aliases and results are both required.'); } if (!Validate::isValidSearch($search)) { - $this->errors[] = $search.' '.$this->l('Is not a valid result'); + $this->errors[] = Tools::safeOutput($search).' '.$this->l('Is not a valid result'); } foreach ($aliases as $alias) { if (!Validate::isValidSearch($alias)) { - $this->errors[] = $alias.' '.$this->l('Is not a valid alias'); + $this->errors[] = Tools::safeOutput($alias).' '.$this->l('Is not a valid alias'); } } diff --git a/modules/blocknavigationmenu/views/templates/admin/custom_navigation_link_setting/helpers/form/form.tpl b/modules/blocknavigationmenu/views/templates/admin/custom_navigation_link_setting/helpers/form/form.tpl index 264969825..f27638a3e 100644 --- a/modules/blocknavigationmenu/views/templates/admin/custom_navigation_link_setting/helpers/form/form.tpl +++ b/modules/blocknavigationmenu/views/templates/admin/custom_navigation_link_setting/helpers/form/form.tpl @@ -127,7 +127,7 @@
{foreach from=$languages item=language} {assign var="navigation_link_name" value="navigation_link_name_`$language.id_lang`"} - + {/foreach}
{if $languages|@count > 1} @@ -176,7 +176,7 @@
- +
diff --git a/modules/hotelreservationsystem/views/templates/admin/add_hotel/helpers/form/form.tpl b/modules/hotelreservationsystem/views/templates/admin/add_hotel/helpers/form/form.tpl index 4e4123d84..6b0cdc270 100644 --- a/modules/hotelreservationsystem/views/templates/admin/add_hotel/helpers/form/form.tpl +++ b/modules/hotelreservationsystem/views/templates/admin/add_hotel/helpers/form/form.tpl @@ -183,7 +183,7 @@ id="short_description_{$language.id_lang}" {if isset($PS_SHORT_DESC_LIMIT) && $PS_SHORT_DESC_LIMIT} maxlength="{$PS_SHORT_DESC_LIMIT|intval}"{/if} cols="2" rows="3" - class="form-control">{if isset($smarty.post.$short_desc_name)}{$smarty.post.$short_desc_name}{elseif isset($edit)}{$hotel_info.short_description[{$language.id_lang}]}{/if} + class="form-control">{if isset($smarty.post.$short_desc_name)}{$smarty.post.$short_desc_name|escape:'htmlall':'UTF-8'}{elseif isset($edit)}{$hotel_info.short_description[{$language.id_lang}]|escape:'htmlall':'UTF-8'}{/if}
{/foreach}
@@ -201,7 +201,7 @@ name="description_{$language.id_lang}" id="description_{$language.id_lang}" cols="2" rows="3" - class="wk_tinymce form-control">{if isset($smarty.post.$description)}{$smarty.post.$description}{elseif isset($edit)}{$hotel_info.description[{$language.id_lang}]}{/if} + class="wk_tinymce form-control">{if isset($smarty.post.$description)}{$smarty.post.$description|escape:'htmlall':'UTF-8'}{elseif isset($edit)}{$hotel_info.description[{$language.id_lang}]|escape:'htmlall':'UTF-8'}{/if} {/foreach} @@ -209,7 +209,7 @@
- +
@@ -219,7 +219,7 @@ - +
@@ -232,13 +232,13 @@
- +
- +
@@ -261,7 +261,7 @@ {l s='Check-in:' mod='hotelreservationsystem'}
- +
@@ -269,7 +269,7 @@ {l s='Check-out:' mod='hotelreservationsystem'}
- +
@@ -305,13 +305,13 @@
- +
- +
@@ -339,7 +339,7 @@ name="policies_{$language.id_lang}" id="policies_{$language.id_lang}" cols="2" rows="3" - class="wk_tinymce form-control">{if isset($smarty.post.$policies)}{$smarty.post.$policies}{elseif isset($edit)}{$hotel_info.policies[{$language.id_lang}]}{/if} + class="wk_tinymce form-control">{if isset($smarty.post.$policies)}{$smarty.post.$policies|escape:'htmlall':'UTF-8'}{elseif isset($edit)}{$hotel_info.policies[{$language.id_lang}]|escape:'htmlall':'UTF-8'}{/if}
{/foreach}
@@ -519,7 +519,7 @@
- +
diff --git a/modules/hotelreservationsystem/views/templates/admin/hotel_feature_prices_settings/helpers/form/form.tpl b/modules/hotelreservationsystem/views/templates/admin/hotel_feature_prices_settings/helpers/form/form.tpl index 8456fdf26..7396a91ac 100644 --- a/modules/hotelreservationsystem/views/templates/admin/hotel_feature_prices_settings/helpers/form/form.tpl +++ b/modules/hotelreservationsystem/views/templates/admin/hotel_feature_prices_settings/helpers/form/form.tpl @@ -40,7 +40,7 @@
{foreach from=$languages item=language} {assign var="feature_price_name" value="feature_price_name_`$language.id_lang`"} - + {/foreach}
{if $languages|@count > 1} @@ -182,7 +182,7 @@
{if isset($edit)} {if $objFeaturePrice->impact_type == HotelRoomTypeFeaturePricing::IMPACT_TYPE_FIXED_PRICE}{$defaultcurrency_sign}{else}%{/if}{else}%{/if} - +
diff --git a/modules/hotelreservationsystem/views/templates/admin/order_refund_rules/helpers/form/form.tpl b/modules/hotelreservationsystem/views/templates/admin/order_refund_rules/helpers/form/form.tpl index b5764b51c..a687eb6c0 100644 --- a/modules/hotelreservationsystem/views/templates/admin/order_refund_rules/helpers/form/form.tpl +++ b/modules/hotelreservationsystem/views/templates/admin/order_refund_rules/helpers/form/form.tpl @@ -65,7 +65,7 @@ name="description_{$language.id_lang|escape:'htmlall':'UTF-8'}" id="description_{$language.id_lang|escape:'htmlall':'UTF-8'}" cols="2" rows="3" - class="form-control">{if isset($smarty.post.$description)}{$smarty.post.$description}{elseif isset($edit)}{$refund_rules_info.description[$language.id_lang]|escape:'htmlall':'UTF-8'}{/if} + class="form-control">{if isset($smarty.post.$description)}{$smarty.post.$description|escape:'htmlall':'UTF-8'}{elseif isset($edit)}{$refund_rules_info.description[$language.id_lang]|escape:'htmlall':'UTF-8'}{/if} {/foreach} From 2079c91cc12e717b8489c6479d07e98c3ce85923 Mon Sep 17 00:00:00 2001 From: amit sharma Date: Tue, 3 Nov 2026 18:27:47 +0530 Subject: [PATCH 15/15] Fixed: Cart popup not updating after adding or removing service products --- themes/hotel-reservation-theme/js/order-opc.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/themes/hotel-reservation-theme/js/order-opc.js b/themes/hotel-reservation-theme/js/order-opc.js index 901a67ced..88f81788f 100644 --- a/themes/hotel-reservation-theme/js/order-opc.js +++ b/themes/hotel-reservation-theme/js/order-opc.js @@ -679,6 +679,10 @@ $(document).ready(function() success: function(jsonData) { if (!jsonData.hasError) { showSuccessMessage(txtExtraServiceSucc); + // refresh the header cart dropdown too + if (typeof ajaxCart !== 'undefined') { + ajaxCart.refresh(); + } } else { showErrorMessage(jsonData.errors);