From e928368638ff0ed42a249005dff62de6e4dcbf8e Mon Sep 17 00:00:00 2001 From: "vishalsingh.qlo325" Date: Wed, 10 Sep 2025 15:17:04 +0530 Subject: [PATCH 01/31] Fixed: Incorrect information on the room type page regarding max capacity in front office --- themes/hotel-reservation-theme/product.tpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/themes/hotel-reservation-theme/product.tpl b/themes/hotel-reservation-theme/product.tpl index 9492fbc86..67f4a03fe 100644 --- a/themes/hotel-reservation-theme/product.tpl +++ b/themes/hotel-reservation-theme/product.tpl @@ -238,13 +238,13 @@ {/block} {block name='product_info_tab_room_guests'} - {if isset($room_type_info['adults']) && isset($room_type_info['children']) } + {if isset($room_type_info['max_adults']) && isset($room_type_info['max_children']) }
{l s='Max Capacity'}
-

{$room_type_info['adults']} {l s='Adults'}, {$room_type_info['children']} {if $room_type_info['children'] > 1}{l s='Children'}{else}{l s='Child'}{/if} ({l s='Max guests'}: {$room_type_info['max_guests']|escape:'htmlall':'UTF-8'})

+

{$room_type_info['max_adults']} {l s='Adults'}, {$room_type_info['max_children']} {if $room_type_info['max_children'] > 1}{l s='Children'}{else}{l s='Child'}{/if} ({l s='Max guests'}: {$room_type_info['max_guests']|escape:'htmlall':'UTF-8'})

{/if} From 64d385c16253b403c9c6bb87c809e1e12bbe27ea Mon Sep 17 00:00:00 2001 From: Amit sharma Date: Tue, 16 Dec 2025 11:17:07 +0530 Subject: [PATCH 02/31] Added: Ensured that complete order bills are cleared before the last room is checked out. --- controllers/admin/AdminOrdersController.php | 54 +++++++++++-------- .../classes/HotelBookingDetail.php | 15 ++++++ 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php index cd2874dba..23897e713 100644 --- a/controllers/admin/AdminOrdersController.php +++ b/controllers/admin/AdminOrdersController.php @@ -8714,30 +8714,40 @@ class AdminOrdersControllerCore extends AdminController } if (empty($this->errors)) { - $objHotelBookingDetail->id_status = $newStatus; - if ($newStatus == HotelBookingDetail::STATUS_CHECKED_IN) { - $objHotelBookingDetail->check_in = $statusDate; - } elseif ($newStatus == HotelBookingDetail::STATUS_CHECKED_OUT) { - $objHotelBookingDetail->check_out = $statusDate; - } else { - $objHotelBookingDetail->check_in = ''; - $objHotelBookingDetail->check_out = ''; - } - if ($objHotelBookingDetail->save()) { - Hook::exec( - 'actionRoomBookingStatusUpdateAfter', - array( - 'id_hotel_booking_detail' => $objHotelBookingDetail->id, - 'id_order' => $objHotelBookingDetail->id_order, - 'id_room' => $objHotelBookingDetail->id_room, - 'date_from' => $objHotelBookingDetail->date_from, - 'date_to' => $objHotelBookingDetail->date_to - ) - ); - Tools::redirectAdmin(self::$currentIndex.'&id_order='.(int) $objHotelBookingDetail->id_order.'&vieworder&token='.$this->token.'&conf=4'); + $id_order = $objHotelBookingDetail->id_order; + $order = new Order($id_order); + $activeRooms = $objHotelBookingDetail->getActiveRoomsCountByOrder($id_order); + $hasPendingBills = $order->getTotalPaid() < $order->getOrderTotal(); + + if ($activeRooms == 1 && $newStatus == HotelBookingDetail::STATUS_CHECKED_OUT && $hasPendingBills) { + $this->errors[] = Tools::displayError('You cannot checkout the last room while there are pending bills for this order.'); } else { - $this->errors[] = Tools::displayError('Some error occurred. Please try again.'); + $objHotelBookingDetail->id_status = $newStatus; + if ($newStatus == HotelBookingDetail::STATUS_CHECKED_IN) { + $objHotelBookingDetail->check_in = $statusDate; + } elseif ($newStatus == HotelBookingDetail::STATUS_CHECKED_OUT) { + $objHotelBookingDetail->check_out = $statusDate; + } else { + $objHotelBookingDetail->check_in = ''; + $objHotelBookingDetail->check_out = ''; + } + if ($objHotelBookingDetail->save()) { + Hook::exec( + 'actionRoomBookingStatusUpdateAfter', + array( + 'id_hotel_booking_detail' => $objHotelBookingDetail->id, + 'id_order' => $objHotelBookingDetail->id_order, + 'id_room' => $objHotelBookingDetail->id_room, + 'date_from' => $objHotelBookingDetail->date_from, + 'date_to' => $objHotelBookingDetail->date_to + ) + ); + + Tools::redirectAdmin(self::$currentIndex . '&id_order=' . (int) $objHotelBookingDetail->id_order . '&vieworder&token=' . $this->token . '&conf=4'); + } else { + $this->errors[] = Tools::displayError('Some error occurred. Please try again.'); + } } } } else { diff --git a/modules/hotelreservationsystem/classes/HotelBookingDetail.php b/modules/hotelreservationsystem/classes/HotelBookingDetail.php index ce5ce56b2..81fae1482 100644 --- a/modules/hotelreservationsystem/classes/HotelBookingDetail.php +++ b/modules/hotelreservationsystem/classes/HotelBookingDetail.php @@ -2591,6 +2591,21 @@ class HotelBookingDetail extends ObjectModel return Db::getInstance()->executeS($sql); } + public function getActiveRoomsCountByOrder($id_order) + { + $sql = 'SELECT COUNT(*) + FROM `'._DB_PREFIX_.'htl_booking_detail` + WHERE `id_order` = '.(int)$id_order.' + AND `is_refunded` = 0 + AND `is_back_order` = 0 + AND `id_status` IN (' + .HotelBookingDetail::STATUS_CHECKED_IN.','. + HotelBookingDetail::STATUS_ALLOTED.' + )'; + + return (int) Db::getInstance()->getValue($sql); + } + public function updateHotelCartHotelOrderOnOrderEdit( $idOrder, $idRoom, From 858e1797be79eeb08450229710cd088c276df844 Mon Sep 17 00:00:00 2001 From: azhar bhat Date: Fri, 9 Jan 2026 15:32:54 +0530 Subject: [PATCH 03/31] fixed Incorrect message on the admin products on trying to enable the room type if the hotel is inactive --- controllers/admin/AdminProductsController.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/controllers/admin/AdminProductsController.php b/controllers/admin/AdminProductsController.php index bf4321607..dacb1a554 100644 --- a/controllers/admin/AdminProductsController.php +++ b/controllers/admin/AdminProductsController.php @@ -2023,6 +2023,14 @@ class AdminProductsControllerCore extends AdminController if (($error = $this->object->validateFieldsLang(false, true)) !== true) { $this->errors[] = $error; } + if(!count($this->errors)){ + $objHotelRoomType = new HotelRoomType(); + $roomTypeInfo = $objHotelRoomType->getRoomTypeInfoByIdProduct($this->object->id); + $objHotelBranchInformation = new HotelBranchInformation((int)$roomTypeInfo['id_hotel']); + if(!$objHotelBranchInformation->active){ + $this->errors[] = $this->l('Enable the hotel first to update status.'); + } + } if (count($this->errors)) { return false; From a6b27ba29902bb907a44ac32b9c0381b9fb460ce Mon Sep 17 00:00:00 2001 From: azhar bhat Date: Wed, 14 Jan 2026 19:59:44 +0530 Subject: [PATCH 04/31] Vulnerability Issue fixed --- modules/qlohotelreview/views/js/hook/review.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/qlohotelreview/views/js/hook/review.js b/modules/qlohotelreview/views/js/hook/review.js index 57227636a..2a30ce2ef 100644 --- a/modules/qlohotelreview/views/js/hook/review.js +++ b/modules/qlohotelreview/views/js/hook/review.js @@ -147,7 +147,7 @@ var QhrReviewImages = { reader.readAsDataURL(file); }, removeFile: function(iInput, iFile) { - var input = $('.images-field input.input-images').get(iInput); + var input = $('.images-field input.input-images').eq(iInput); var files = $(input).get(0).files; var dataTransfer = new DataTransfer(); $(files).each(function(iiFile, file) { @@ -155,7 +155,10 @@ var QhrReviewImages = { dataTransfer.items.add(file); } }); - input.files = dataTransfer.files; + input.get(0).files = dataTransfer.files; + if (input.get(0).files.length === 0) { + input.remove(); + } }, resetPreviews: function() { $('.previews-wrap').html(''); From b2a5b523b6580bcde96c66fee5cfc5915b87ecbe Mon Sep 17 00:00:00 2001 From: azhar bhat Date: Wed, 14 Jan 2026 20:03:58 +0530 Subject: [PATCH 05/31] fixed Vulnerability issue while uploading images in hotel reviews --- modules/qlohotelreview/controllers/front/default.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/qlohotelreview/controllers/front/default.php b/modules/qlohotelreview/controllers/front/default.php index 0156e3112..c380cd5f7 100644 --- a/modules/qlohotelreview/controllers/front/default.php +++ b/modules/qlohotelreview/controllers/front/default.php @@ -85,6 +85,16 @@ class QloHotelReviewDefaultModuleFrontController extends ModuleFrontController } } + if (is_array($_FILES) && array_key_exists('images', $_FILES) ) { + $allowedExtensions = array('jpg', 'png'); + foreach ($_FILES['images']['name'] as $key => $imageName) { + $extension = Tools::strtolower(pathinfo($imageName, PATHINFO_EXTENSION)); + if (!in_array($extension, $allowedExtensions)) { + $errors['general'][] = $imageName . ' ' . $objModule->l('is not a supported image format.','default'); + } + } + } + if (!count($errors['by_key']) && !count($errors['general'])) { $customerReview = QhrHotelReview::getByCustomer( $objOrder->id_customer, From 909651a022a1b36b18dced094ac4b9e61f35d0a5 Mon Sep 17 00:00:00 2001 From: azhar bhat Date: Thu, 15 Jan 2026 14:49:50 +0530 Subject: [PATCH 06/31] Feature added Disable location and Hotel field for 1 property --- modules/hotelreservationsystem/classes/HotelHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/hotelreservationsystem/classes/HotelHelper.php b/modules/hotelreservationsystem/classes/HotelHelper.php index a196694f5..3ac83dea4 100644 --- a/modules/hotelreservationsystem/classes/HotelHelper.php +++ b/modules/hotelreservationsystem/classes/HotelHelper.php @@ -1040,8 +1040,8 @@ class HotelHelper $home_banner_default_title = $homeBannerTitleLang[$objDefaultLanguage->iso_code]; } - Configuration::updateValue('WK_HOTEL_LOCATION_ENABLE', 1); - Configuration::updateValue('WK_HOTEL_NAME_ENABLE', 1); + Configuration::updateValue('WK_HOTEL_LOCATION_ENABLE', 0); + Configuration::updateValue('WK_HOTEL_NAME_ENABLE', 0); Configuration::updateValue('WK_HOTEL_NAME_SEARCH_THRESHOLD', 5); Configuration::updateValue('WK_SEARCH_AUTO_FOCUS_NEXT_FIELD', 1); Configuration::updateValue('WK_ROOM_LEFT_WARNING_NUMBER', 10); From a6b1d8a6b47d256f4b4fe9d2d27b845d7f481d52 Mon Sep 17 00:00:00 2001 From: azhar bhat Date: Thu, 15 Jan 2026 15:04:53 +0530 Subject: [PATCH 07/31] removed code related to other pr --- modules/qlohotelreview/controllers/front/default.php | 10 ---------- modules/qlohotelreview/views/js/hook/review.js | 7 ++----- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/modules/qlohotelreview/controllers/front/default.php b/modules/qlohotelreview/controllers/front/default.php index c380cd5f7..0156e3112 100644 --- a/modules/qlohotelreview/controllers/front/default.php +++ b/modules/qlohotelreview/controllers/front/default.php @@ -85,16 +85,6 @@ class QloHotelReviewDefaultModuleFrontController extends ModuleFrontController } } - if (is_array($_FILES) && array_key_exists('images', $_FILES) ) { - $allowedExtensions = array('jpg', 'png'); - foreach ($_FILES['images']['name'] as $key => $imageName) { - $extension = Tools::strtolower(pathinfo($imageName, PATHINFO_EXTENSION)); - if (!in_array($extension, $allowedExtensions)) { - $errors['general'][] = $imageName . ' ' . $objModule->l('is not a supported image format.','default'); - } - } - } - if (!count($errors['by_key']) && !count($errors['general'])) { $customerReview = QhrHotelReview::getByCustomer( $objOrder->id_customer, diff --git a/modules/qlohotelreview/views/js/hook/review.js b/modules/qlohotelreview/views/js/hook/review.js index 2a30ce2ef..57227636a 100644 --- a/modules/qlohotelreview/views/js/hook/review.js +++ b/modules/qlohotelreview/views/js/hook/review.js @@ -147,7 +147,7 @@ var QhrReviewImages = { reader.readAsDataURL(file); }, removeFile: function(iInput, iFile) { - var input = $('.images-field input.input-images').eq(iInput); + var input = $('.images-field input.input-images').get(iInput); var files = $(input).get(0).files; var dataTransfer = new DataTransfer(); $(files).each(function(iiFile, file) { @@ -155,10 +155,7 @@ var QhrReviewImages = { dataTransfer.items.add(file); } }); - input.get(0).files = dataTransfer.files; - if (input.get(0).files.length === 0) { - input.remove(); - } + input.files = dataTransfer.files; }, resetPreviews: function() { $('.previews-wrap').html(''); From 970138f30584782cd7e5eca66b628c45cd327fe2 Mon Sep 17 00:00:00 2001 From: aradhana kumari Date: Fri, 16 Jan 2026 11:45:24 +0530 Subject: [PATCH 08/31] Give an option at performance tab for enabling or disabling Debug mode --- .../admin/AdminPerformanceController.php | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/controllers/admin/AdminPerformanceController.php b/controllers/admin/AdminPerformanceController.php index 415dabab0..064693774 100644 --- a/controllers/admin/AdminPerformanceController.php +++ b/controllers/admin/AdminPerformanceController.php @@ -29,6 +29,11 @@ */ class AdminPerformanceControllerCore extends AdminController { + public const DEBUG_MODE_SUCCEEDED = 0; + public const DEBUG_MODE_ERROR_NO_READ_ACCESS = 1; + public const DEBUG_MODE_ERROR_NO_WRITE_ACCESS = 2; + public const DEBUG_MODE_ERROR_NO_DEFINITION_FOUND = 3; + public function __construct() { $this->bootstrap = true; @@ -169,6 +174,24 @@ class AdminPerformanceControllerCore extends AdminController ), 'hint' => $this->l('Enable or disable non QloApps Modules.') ), + array( + 'type' => 'switch', + 'label' => $this->l('Debug mode'), + 'name' => 'debug_mode', + 'class' => 't', + 'is_bool' => true, + 'values' => array( + array( + 'value' => 1, + 'label' => $this->l('Enabled') + ), + array( + 'value' => 0, + 'label' => $this->l('Disabled') + ) + ), + 'hint' => $this->l('Enable or disable debug mode. Debug mode will enable extended error reporting.') + ), array( 'type' => 'switch', 'label' => $this->l('Disable all overrides'), @@ -196,6 +219,7 @@ class AdminPerformanceControllerCore extends AdminController ); $this->fields_value['native_module'] = Configuration::get('PS_DISABLE_NON_NATIVE_MODULE'); + $this->fields_value['debug_mode'] = _PS_MODE_DEV_; $this->fields_value['overrides'] = Configuration::get('PS_DISABLE_OVERRIDES'); } @@ -885,6 +909,14 @@ class AdminPerformanceControllerCore extends AdminController if (Tools::isSubmit('submitAddconfiguration')) { Configuration::updateGlobalValue('PS_DISABLE_NON_NATIVE_MODULE', (int)Tools::getValue('native_module')); Configuration::updateGlobalValue('PS_DISABLE_OVERRIDES', (int)Tools::getValue('overrides')); + + $debugValue = ((int) Tools::getValue('debug_mode') === (int)1) ? 'true' : 'false'; + $result = $this->changePsModeDevValue($debugValue); + + if ($result !== self::DEBUG_MODE_SUCCEEDED) { + $this->errors[] = $this->l('Unable to update debug mode. Please check file permissions.'); + } + Tools::generateIndex(); } @@ -894,6 +926,42 @@ class AdminPerformanceControllerCore extends AdminController } } + public function changePsModeDevValue($value) + { + if ($this->isDefinesReadable()) { + return $this->updateDebugModeValueInMainFile($value); + } + + return self::DEBUG_MODE_ERROR_NO_READ_ACCESS; + } + + public function isDefinesReadable() + { + return is_readable(_PS_ROOT_DIR_ . '/config/defines.inc.php'); + } + + public function updateDebugModeValueInMainFile($value) + { + $filename = _PS_ROOT_DIR_ . '/config/defines.inc.php'; + $cleanedFileContent = php_strip_whitespace($filename); + $fileContent = Tools::file_get_contents($filename); + + if (!preg_match('/define\(\'_PS_MODE_DEV_\', ([a-zA-Z]+)\);/Ui', $cleanedFileContent)) { + return self::DEBUG_MODE_ERROR_NO_DEFINITION_FOUND; + } + + $fileContent = preg_replace('/define\(\'_PS_MODE_DEV_\', ([a-zA-Z]+)\);/Ui', 'define(\'_PS_MODE_DEV_\', ' . $value . ');', $fileContent); + if (!@file_put_contents($filename, $fileContent)) { + return self::DEBUG_MODE_ERROR_NO_WRITE_ACCESS; + } + + if (function_exists('opcache_invalidate')) { + @opcache_invalidate($filename); + } + + return self::DEBUG_MODE_SUCCEEDED; + } + public function displayAjaxTestServer() { /* PrestaShop demo mode */ From fe2147a547532ec7bd3e6584861998e69e37f909 Mon Sep 17 00:00:00 2001 From: azhar bhat Date: Mon, 19 Jan 2026 12:32:13 +0530 Subject: [PATCH 09/31] fixed Dashboard Occupancy panel issue --- controllers/admin/AdminStatsController.php | 91 ++++--------- .../classes/HotelBookingDetail.php | 124 ++++++++++++++++++ 2 files changed, 153 insertions(+), 62 deletions(-) diff --git a/controllers/admin/AdminStatsController.php b/controllers/admin/AdminStatsController.php index ba6b3b371..bdfa27c73 100644 --- a/controllers/admin/AdminStatsController.php +++ b/controllers/admin/AdminStatsController.php @@ -1385,70 +1385,37 @@ class AdminStatsControllerCore extends AdminStatsTabController public static function getOccupancyData($dateFrom, $dateTo, $idsHotel = false) { - if ($dateFrom == $dateTo) { - $dateTo = date('Y-m-d', strtotime('+1 day', strtotime($dateTo))); - } - + $objHotelBookingDetail = new HotelBookingDetail(); + $objHotelBranchInformation = new HotelBranchInformation(); + $allHotels = $objHotelBranchInformation->getAllHotels(); $occupancyData = array('count_total' => 0, 'count_occupied' => 0, 'count_available' => 0, 'count_unavailable' => 0); - - $countTotal = self::getTotalRooms($idsHotel, true); - $occupancyData['count_total'] = $countTotal; - - // Occupied rooms are booked rooms that are not refunded in the date range - $countOccupied = 0; - $occupiedRooms = Db::getInstance()->executeS( - 'SELECT DISTINCT hbd.`id_room` - FROM `'._DB_PREFIX_.'htl_booking_detail` hbd - LEFT JOIN `'._DB_PREFIX_.'htl_room_information` hri - ON (hri.`id` = hbd.`id_room`) - LEFT JOIN `'._DB_PREFIX_.'product` p - ON (p.`id_product` = hri.`id_product`) - WHERE p.`active` = 1 - AND hbd.`is_refunded` = 0 - AND IF(hbd.`id_status` = '. HotelBookingDetail::STATUS_CHECKED_OUT .', hbd.`date_from` < DATE_FORMAT(hbd.`check_out`, "%Y-%m-%d") AND hbd.`date_from` < \''.pSQL($dateTo).'\' AND DATE_FORMAT(hbd.`check_out`, "%Y-%m-%d") > \''.pSQL($dateFrom).'\', hbd.`date_from` < \''.pSQL($dateTo).'\' AND hbd.`date_to` > \''.pSQL($dateFrom).'\')'. - HotelBranchInformation::addHotelRestriction($idsHotel, 'hbd') - ); - - if ($occupiedRooms) { - $occupiedRooms = array_column($occupiedRooms, 'id_room'); - $occupancyData['count_occupied'] = count($occupiedRooms); - } else { - $occupancyData['count_occupied'] = 0; + if($idsHotel == 0){ + $dataStats = [ + 'num_unavail'=> 0, + 'num_booked'=> 0, + 'num_avail'=> 0, + 'total_rooms'=> 0, + ]; + foreach ($allHotels as $hotel) { + $idhotel = (int) $hotel['id']; + $bookingData = $objHotelBookingDetail->getDateWiseBooking($dateFrom , $dateTo , $idhotel); + $dataStats['num_avail'] += $bookingData['stats']['available']; + $dataStats['num_unavail'] += $bookingData['stats']['unavailable']; + $dataStats['num_booked'] += $bookingData['stats']['booked']; + $dataStats['total_rooms'] += $bookingData['stats']['total_rooms']; + } + $occupancyData['count_available'] = $dataStats['num_avail']; + $occupancyData['count_occupied'] = $dataStats['num_booked']; + $occupancyData['count_unavailable'] = $dataStats['num_unavail']; + $occupancyData['count_total'] = $dataStats['total_rooms']; } - - // Unavailable rooms are rooms that are not booked for the date range and in the inactive status - $countUnavailable = Db::getInstance()->getValue( - 'SELECT COUNT(hri.`id`) - FROM `'._DB_PREFIX_.'htl_room_information` hri - LEFT JOIN `'._DB_PREFIX_.'htl_branch_info` hbi - ON (hbi.`id` = hri.`id_hotel`) - LEFT JOIN `'._DB_PREFIX_.'product` p - ON (p.`id_product` = hri.`id_product`) - WHERE p.`active` = 1 '. - ($occupiedRooms ? ' AND hri.`id` NOT IN ('.implode(',', $occupiedRooms).')' : ''). - ' AND hri.`id_status` = '.(int) HotelRoomInformation::STATUS_INACTIVE. - HotelBranchInformation::addHotelRestriction($idsHotel, 'hbi', 'id') - ); - $occupancyData['count_unavailable'] = $countUnavailable; - - // Available rooms are rooms that are not booked for the date range and in the temporary inactive for the date range - $countDisabled = Db::getInstance()->getValue( - 'SELECT IFNULL(COUNT(hri.`id`), 0) - FROM `'._DB_PREFIX_.'htl_room_information` hri - LEFT JOIN `'._DB_PREFIX_.'htl_room_disable_dates` hrdd - ON (hrdd.`id_room` = hri.`id`) - LEFT JOIN `'._DB_PREFIX_.'product` p - ON (p.`id_product` = hri.`id_product`) - WHERE hri.`id_status` = '.(int) HotelRoomInformation::STATUS_TEMPORARY_INACTIVE. - ($occupiedRooms ? ' AND hri.`id` NOT IN ('.implode(',', $occupiedRooms).')' : ''). - ' AND ("'.pSQL($dateTo).'" > hrdd.`date_from` AND "'.pSQL($dateFrom).'" < hrdd.`date_to`) - AND p.`active` = 1'. - (!is_null($idsHotel) ? HotelBranchInformation::addHotelRestriction($idsHotel, 'hri') : '') - ); - $occupancyData['count_unavailable'] += $countDisabled; - - $occupancyData['count_available'] = $occupancyData['count_total'] - $occupancyData['count_occupied'] - $occupancyData['count_unavailable']; - + else{ + $bookingData = $objHotelBookingDetail->getDateWiseBooking($dateFrom , $dateTo , $idsHotel); + $occupancyData['count_available'] = $bookingData['stats']['available']; + $occupancyData['count_occupied'] = $bookingData['stats']['booked']; + $occupancyData['count_unavailable'] = $bookingData['stats']['unavailable']; + $occupancyData['count_total'] = $bookingData['stats']['total_rooms']; + } return $occupancyData; } diff --git a/modules/hotelreservationsystem/classes/HotelBookingDetail.php b/modules/hotelreservationsystem/classes/HotelBookingDetail.php index fbf4ba1c6..dc475e073 100644 --- a/modules/hotelreservationsystem/classes/HotelBookingDetail.php +++ b/modules/hotelreservationsystem/classes/HotelBookingDetail.php @@ -3781,4 +3781,128 @@ class HotelBookingDetail extends ObjectModel return parent::add($auto_date, $null_values); } + //Datewise Booking Data + public function getDateWiseBooking($dateFrom, $dateTo, $idHotel) + { + $objBookingDetail = new HotelBookingDetail(); + if ($dateFrom == $dateTo) { + $dateTo = date('Y-m-d', strtotime($dateTo . ' +1 day')); + } + $bookingParams = [ + 'date_from' => $dateFrom, + 'date_to' => $dateTo, + 'search_available'=> 1, + 'search_partial' => 1, + 'search_booked' => 1, + 'search_unavai' => 1, + 'hotel_id' => $idHotel, + ]; + $bookingData = $objBookingDetail->getBookingData($bookingParams); + $bookedDates = []; + $unavailableDates = []; + if (!empty($bookingData['rm_data'])) { + foreach ($bookingData['rm_data'] as $key => $roomType) { + // get all rooms of room type + $rooms = HotelRoomInformation::getHotelRoomsInfo( + $bookingParams['hotel_id'], + $roomType['id_product'] + ); + foreach ($rooms ?: [] as $room) { + $bookingData['rm_data'][$key]['all_rooms'][$room['id']] = [ + 'id_room' => $room['id'], + 'room_num' => $room['room_num'], + ]; + } + // booked rooms date mapping + foreach ($roomType['data']['booked'] ?: [] as $bookedRoom) { + foreach ($bookedRoom['detail'] as $detail) { + for ( + $d = date('Y-m-d', strtotime($detail['date_from'])); + $d < date('Y-m-d', strtotime($detail['date_to'])); + $d = date('Y-m-d', strtotime('+1 day', strtotime($d))) + ) { + $bookedDates[$d][$roomType['id_product']][$bookedRoom['id_room']] = + $bookedRoom['id_room']; + } + } + } + // unavailable rooms date mapping + foreach ($roomType['data']['unavailable'] ?: [] as $unavailableRoom) { + foreach ($unavailableRoom['detail'] as $detail) { + for ( + $d = date('Y-m-d', strtotime($detail['date_from'])); + $d < date('Y-m-d', strtotime($detail['date_to'])); + $d = date('Y-m-d', strtotime('+1 day', strtotime($d))) + ) { + $unavailableDates[$d][$roomType['id_product']][$unavailableRoom['id_room']] = + $unavailableRoom['id_room']; + } + } + } + } + } + $response = [ + 'data' => [], + 'stats' => [ + 'total_rooms' => 0, + 'available' => 0, + 'booked' => 0, + 'unavailable' => 0, + ], + ]; + for ( + $currentDate = date('Y-m-d', strtotime($dateFrom)); + $currentDate < date('Y-m-d', strtotime($dateTo)); + $currentDate = date('Y-m-d', strtotime('+1 day', strtotime($currentDate))) + ) { + $nextDate = date('Y-m-d', strtotime('+1 day', strtotime($currentDate))); + + $dateWiseInfo = [ + 'id_hotel' => $idHotel, + 'date_from' => $currentDate, + 'date_to' => $nextDate, + 'room_types'=> [], + ]; + foreach ($bookingData['rm_data'] ?: [] as $roomType) { + $allRooms = $roomType['all_rooms'] ?: []; + // available initially all rooms + $available = $allRooms; + $booked = []; + $unavai = []; + // remove booked + if (!empty($bookedDates[$currentDate][$roomType['id_product']])) { + $booked = array_intersect_key( + $allRooms, + $bookedDates[$currentDate][$roomType['id_product']] + ); + $available = array_diff_key($available, $booked); + } + // remov unavailable + if (!empty($unavailableDates[$currentDate][$roomType['id_product']])) { + $unavai = array_intersect_key( + $allRooms, + $unavailableDates[$currentDate][$roomType['id_product']] + ); + $available = array_diff_key($available, $unavai); + } + $response['stats']['available'] += count($available); + $response['stats']['booked'] += count($booked); + $response['stats']['unavailable'] += count($unavai); + $response['stats']['total_rooms'] += count($allRooms); + + $dateWiseInfo['room_types'][] = [ + 'id_room_type' => $roomType['id_product'], + 'name' => $roomType['name'], + 'rooms' => [ + 'available' => $available, + 'booked' => $booked, + 'unavailable' => $unavai, + ], + ]; + } + $response['data'][] = $dateWiseInfo; + } + + return$response; + } } From b8f0a27e66c3b508f98ba7244e2d0122afba885d Mon Sep 17 00:00:00 2001 From: Amit sharma Date: Tue, 20 Jan 2026 12:40:02 +0530 Subject: [PATCH 10/31] Fixed: disable room types should not be visible in the suggestion during room reallocation. --- .../hotelreservationsystem/classes/HotelBookingDetail.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/hotelreservationsystem/classes/HotelBookingDetail.php b/modules/hotelreservationsystem/classes/HotelBookingDetail.php index fbf4ba1c6..8b383bd04 100644 --- a/modules/hotelreservationsystem/classes/HotelBookingDetail.php +++ b/modules/hotelreservationsystem/classes/HotelBookingDetail.php @@ -1814,10 +1814,12 @@ class HotelBookingDetail extends ObjectModel $availableRoomTypes = array(); $context = Context::getContext(); foreach ($avail_rooms as $roomInfo) { - $availableRoomTypes[$roomInfo['id_product']]['id_product'] = $roomInfo['id_product']; $objProduct = new Product($roomInfo['id_product'], false, $context->language->id); - $availableRoomTypes[$roomInfo['id_product']]['room_type_name'] = $objProduct->name; - $availableRoomTypes[$roomInfo['id_product']]['rooms'][] = $roomInfo; + if($objProduct->active){ + $availableRoomTypes[$roomInfo['id_product']]['id_product'] = $roomInfo['id_product']; + $availableRoomTypes[$roomInfo['id_product']]['room_type_name'] = $objProduct->name; + $availableRoomTypes[$roomInfo['id_product']]['rooms'][] = $roomInfo; + } } return $availableRoomTypes; From 1959df04dcc552fd535bccc9ed3547650100b8bf Mon Sep 17 00:00:00 2001 From: Amit sharma Date: Tue, 20 Jan 2026 12:42:31 +0530 Subject: [PATCH 11/31] Fixed: disable room types should not be visible in the suggestion during room reallocation. --- modules/hotelreservationsystem/classes/HotelBookingDetail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hotelreservationsystem/classes/HotelBookingDetail.php b/modules/hotelreservationsystem/classes/HotelBookingDetail.php index 8b383bd04..680e7bf79 100644 --- a/modules/hotelreservationsystem/classes/HotelBookingDetail.php +++ b/modules/hotelreservationsystem/classes/HotelBookingDetail.php @@ -1815,7 +1815,7 @@ class HotelBookingDetail extends ObjectModel $context = Context::getContext(); foreach ($avail_rooms as $roomInfo) { $objProduct = new Product($roomInfo['id_product'], false, $context->language->id); - if($objProduct->active){ + if(Validate::isLoadedObject($objProduct) && $objProduct->active){ $availableRoomTypes[$roomInfo['id_product']]['id_product'] = $roomInfo['id_product']; $availableRoomTypes[$roomInfo['id_product']]['room_type_name'] = $objProduct->name; $availableRoomTypes[$roomInfo['id_product']]['rooms'][] = $roomInfo; From 30a01f7cc4bc6d14960bc1d4c9987ee5ce14e946 Mon Sep 17 00:00:00 2001 From: azhar bhat Date: Thu, 22 Jan 2026 16:48:47 +0530 Subject: [PATCH 12/31] Fixed issue where a success message was displayed while changing room type status via bulk action even when the associated hotel was disabled. --- controllers/admin/AdminProductsController.php | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/controllers/admin/AdminProductsController.php b/controllers/admin/AdminProductsController.php index dacb1a554..85e16f6aa 100644 --- a/controllers/admin/AdminProductsController.php +++ b/controllers/admin/AdminProductsController.php @@ -2024,11 +2024,12 @@ class AdminProductsControllerCore extends AdminController $this->errors[] = $error; } if(!count($this->errors)){ - $objHotelRoomType = new HotelRoomType(); - $roomTypeInfo = $objHotelRoomType->getRoomTypeInfoByIdProduct($this->object->id); - $objHotelBranchInformation = new HotelBranchInformation((int)$roomTypeInfo['id_hotel']); - if(!$objHotelBranchInformation->active){ - $this->errors[] = $this->l('Enable the hotel first to update status.'); + $objHotelRoomType = new HotelRoomType(); + if($roomTypeInfo = $objHotelRoomType->getRoomTypeInfoByIdProduct($this->object->id)){ + $objHotelBranchInformation = new HotelBranchInformation((int)$roomTypeInfo['id_hotel']); + if(!$objHotelBranchInformation->active){ + $this->errors[] = $this->l('Please enable the hotel "'.$roomTypeInfo['hotel_name'].'" first in order to update the status.'); + } } } @@ -2049,6 +2050,24 @@ class AdminProductsControllerCore extends AdminController return $res; } + public function processBulkStatusSelection($status) + { + if (is_array($this->boxes) && !empty($this->boxes)) { + foreach ($this->boxes as $id) { + $objHotelRoomType = new HotelRoomType(); + if($roomTypeInfo = $objHotelRoomType->getRoomTypeInfoByIdProduct($id)){ + $objHotelBranchInformation = new HotelBranchInformation((int)$roomTypeInfo['id_hotel']); + if(!$objHotelBranchInformation->active){ + $this->errors[] = $this->l('Please enable the hotel "'.$roomTypeInfo['hotel_name'].'" first in order to update the status.'); + } + } + } + } + if (!count($this->errors)) { + parent::processBulkStatusSelection($status); + } + } + public function processToggleShowAtFront() { if (!$this->loadObject()) { From ebb9a65dda3a89f5a5176a9ae64defa912033182 Mon Sep 17 00:00:00 2001 From: aradhana kumari Date: Fri, 23 Jan 2026 15:09:29 +0530 Subject: [PATCH 13/31] Add the debug icon at header --- admin/themes/default/template/header.tpl | 12 ++++++++++++ classes/controller/AdminController.php | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/admin/themes/default/template/header.tpl b/admin/themes/default/template/header.tpl index 148be94a4..bb6f6f97f 100644 --- a/admin/themes/default/template/header.tpl +++ b/admin/themes/default/template/header.tpl @@ -298,6 +298,18 @@ {/if}