Files
hotel/modules/hotelreservationsystem/classes/HotelRoomInformation.php
Rohit Jain bdb420d36f Merge pull request #1786 from varunkewlani322/gli-2942
Added: No Show and Cancellation booking status in back-office, and updated refund request management
2026-09-11 17:16:12 +05:30

510 lines
23 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 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
*/
class HotelRoomInformation extends ObjectModel
{
public $id;
public $id_product;
public $id_hotel;
public $room_num;
public $id_status;
public $floor;
public $comment;
public $date_add;
public $date_upd;
const STATUS_ACTIVE = 1;
const STATUS_INACTIVE = 2;
const STATUS_TEMPORARY_INACTIVE = 3;
const STATUS_SEARCH_LOS_UNSATISFIED = 4;
const STATUS_SEARCH_OCCUPANCY_UNSATISFIED = 5;
public static $definition = array(
'table' => 'htl_room_information',
'primary' => 'id',
'fields' => array(
'id_product' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'id_hotel' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'room_num' => array('type' => self::TYPE_STRING),
'id_status' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'floor' => array('type' => self::TYPE_STRING),
'comment' => array('type' => self::TYPE_STRING),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate')
),
);
protected $webserviceParameters = array(
'objectMethods' => array(
'add' => 'addWs',
'update' => 'updateWs',
'delete' => 'deleteWs',
),
'objectsNodeName' => 'rooms',
'objectNodeName' => 'room',
'fields' => array(
'id_product' => array(
'xlink_resource' => array(
'resourceName' => 'products',
)
),
'id_hotel' => array(
'setter' => false,
'xlink_resource' => array(
'resourceName' => 'hotels',
)
),
),
);
public function update($null_values = false)
{
if ($idRoom = $this->id) {
// delete rooms from cart which are set inactive
if ($this->id_status == HotelRoomInformation::STATUS_INACTIVE) {
$objCartBookingData = new HotelCartBookingData();
if (!$objCartBookingData->deleteCartBookingData(0, 0, $idRoom)) {
return false;
}
}
}
return parent::update();
}
//Overrided ObjectModel::delete()
public function delete()
{
if ($idRoom = $this->id) {
$objCartBookingData = new HotelCartBookingData();
if (!$this->deleteRoomDisableDates()
|| !$objCartBookingData->deleteCartBookingData(0, 0, $idRoom)
|| !parent::delete()
) {
return false;
}
}
return true;
}
public function deleteRoomDisableDates($idRoom = false)
{
if (!$idRoom) {
$idRoom = $this->id;
if (!$idRoom) {
return false;
}
}
$objRoomDisableDates = new HotelRoomDisableDates();
$objRoomDisableDates->deleteRoomDisableDates((int)$idRoom);
return true;
}
/**
* [deleteByProductId :: To delete all rooms information which belongs to a room type(which is a product in real) By product id]
* @param [int] $id_product [Id of the product form which all rooms information to be deleted]
* @return [Boolean] [Returns true if deleted successfully else returns false]
*/
public function deleteByProductId($idProduct)
{
if ($rooms = Db::getInstance()->executeS(
'SELECT * FROM `'._DB_PREFIX_.'htl_room_information` WHERE `id_product`='.(int) $idProduct
)) {
foreach ($rooms as $room) {
$objRoomInfo = new HotelRoomInformation($room['id']);
if (!$objRoomInfo->delete()) {
return false;
}
}
}
return true;
}
public function getAllRoomStatus()
{
$status = array(
'STATUS_ACTIVE' => array(
'id' => HotelRoomInformation::STATUS_ACTIVE,
'status' => self::getRoomStatusTitle(HotelRoomInformation::STATUS_ACTIVE)
),
'STATUS_INACTIVE' => array(
'id' => HotelRoomInformation::STATUS_INACTIVE,
'status' => self::getRoomStatusTitle(HotelRoomInformation::STATUS_INACTIVE)
),
'STATUS_TEMPORARY_INACTIVE' => array(
'id' => HotelRoomInformation::STATUS_TEMPORARY_INACTIVE,
'status' => self::getRoomStatusTitle(HotelRoomInformation::STATUS_TEMPORARY_INACTIVE)
),
);
return $status;
}
public static function getRoomStatusTitle($idStatus)
{
$moduleInstance = Module::getInstanceByName('hotelreservationsystem');
$status = array(
HotelRoomInformation::STATUS_ACTIVE => $moduleInstance->l('Active', 'hotelreservationsystem'),
HotelRoomInformation::STATUS_INACTIVE => $moduleInstance->l('Inactive', 'hotelreservationsystem'),
HotelRoomInformation::STATUS_TEMPORARY_INACTIVE => $moduleInstance->l('Temporarily Inactive', 'hotelreservationsystem'),
HotelRoomInformation::STATUS_SEARCH_LOS_UNSATISFIED => $moduleInstance->l('Length of stay restriction not satisfied', 'hotelreservationsystem'),
HotelRoomInformation::STATUS_SEARCH_OCCUPANCY_UNSATISFIED => $moduleInstance->l('Occupancy exceeds room capacity', 'hotelreservationsystem'),
);
return isset($status[$idStatus]) ? $status[$idStatus] : '';
}
/**
* [getHotelRoomInfoByProductId :: To get all rooms information belong to a room type(product) by product id]
* @param [int] $id_product [Id of the product]
* @return [array|false] [If data found returns array containing all rooms information belongs to a room type(product) which product id is passed else returns false]
*/
public function getHotelRoomInfoByProductId($id_product)
{
$result = Db::getInstance()->executeS('SELECT * FROM `'._DB_PREFIX_.'htl_room_information` WHERE `id_product`='.(int) $id_product);
if ($result) {
return $result;
}
return false;
}
/**
* [getHotelRoomInfo :: To get all rooms information belong to a room type(product) and belongss to a hotel wwhich hotel id is passed]
* @param [type] $id_product [Id of the room type(product)]
* @param [type] $id_hotel [Id of the hotel]
* @param [int] $is_getNum [
* If $is_getNum is passed
* then returns number of rooms belong to a room type(product) and belongss to a hotel wwhich hotel id is passed
* else
* Returns array containing all rooms information belong to a room type(product) and belongss to a hotel wwhich hotel id is passed
* ]
* @return [array|int|boolean] [If $is_getNum is passed
* then returns number of rooms belong to a room type(product) and belongss to a hotel wwhich hotel id is passed
* else
* if data found
* Returns array containing all rooms information belong to a room type(product) and belongss to a hotel wwhich hotel id is passed
* else
* returns false; ]
*/
public function getHotelRoomInfo($id_product, $id_hotel, $is_getNum = 0)
{
$sql = "SELECT * FROM `"._DB_PREFIX_."htl_room_information` WHERE `id_product` = ".(int) $id_product." AND `id_hotel` = ".(int) $id_hotel;
$rm_info = Db::getInstance()->executeS($sql);
if ($is_getNum) {
$no_row = Db::getInstance()->NumRows();
return $no_row;
} else {
if ($rm_info) {
return $rm_info;
} else {
return false;
}
}
}
/**
* [getHotelRoomInfoById :: To get Information of a room by its id(primary key)]
* @param [int] $id [id of the room in the table(primary key)]
* @return [array|false] [If data found returns array containing information of the room which id is passed else returns false]
*/
public function getHotelRoomInfoById($id)
{
$sql = "SELECT `room_num` FROM `"._DB_PREFIX_."htl_room_information` WHERE `id` = ".(int) $id;
$rm_num = Db::getInstance()->getValue($sql);
if ($rm_num) {
return $rm_num;
} else {
return false;
}
}
public static function getHotelRoomsInfo($idHotel = null, $idProduct = null, $idLang = null)
{
if (!$idLang) {
$idLang = Context::getContext()->language->id;
}
$sql = 'SELECT hri.*, hri.`id_product`, hri.`id_hotel`, hrt.`adults`, hrt.`children`, hrt.`max_adults`,
hrt.`max_children`, hrt.`max_guests`, hrt.`min_los`, hrt.`max_los`, pl.`name` AS room_type_name, hbil.`hotel_name` AS hotel_name
FROM `'._DB_PREFIX_.'htl_room_information` hri
INNER JOIN `'._DB_PREFIX_.'htl_room_type` hrt ON (hrt.`id_product` = hri.`id_product`)
INNER JOIN `'._DB_PREFIX_.'htl_branch_info` hbi ON (hbi.`id` = hri.`id_hotel`)
INNER JOIN `'._DB_PREFIX_.'htl_branch_info_lang` hbil ON (hbil.`id` = hri.`id_hotel` AND hbil.`id_lang` = '.(int) $idLang.')
INNER JOIN `'._DB_PREFIX_.'product` p ON (p.`id_product` = hri.`id_product`)
INNER JOIN `'._DB_PREFIX_.'product_lang` pl ON (pl.`id_product` = p.`id_product` AND pl.`id_lang` = '.(int) $idLang.')
WHERE 1 '.($idHotel ? ' AND hri.`id_hotel` = '.(int) $idHotel : '').
($idProduct ? ' AND hri.`id_product` = '.(int) $idProduct : '').'
ORDER BY hri.`id_product`, hri.`id`';
return Db::getInstance()->executeS($sql);
}
/**
* Deprecated
* [deleteHotelRoomInfoById :: To delete room information which id is passed]
* @param [int] $id_room_info [Id of the room which information(row in the table) to be deleted]
* @return [Boolean] [Returns true if deleted successfully else returns false]
*/
public function deleteHotelRoomInfoById($id_room_info)
{
$result = Db::getInstance()->delete('htl_room_information', '`id` = '.(int)$id_room_info, 1);
return $result;
}
public function getRoomTypeAvailableRoomsForDateRange($id_hotel, $id_product, $date_from, $date_to)
{
return Db::getInstance()->executeS('SELECT * FROM `'._DB_PREFIX_.'htl_room_information` where `id_hotel`='.(int) $id_hotel.' AND `id_product`='.(int) $id_product.' AND `id` NOT IN (SELECT `id_room` from `'._DB_PREFIX_.'htl_booking_detail` where `date_from`< \''.pSQL($date_to).'\' AND `date_to`>\''.pSQL($date_from).'\' AND `id_product`='.(int) $id_product.' AND `id_hotel`='.(int) $id_hotel.')');
}
public function getRoomTypeDisabledRoomsForDateRange($id_hotel, $id_product, $date_from, $date_to)
{
return Db::getInstance()->executeS('SELECT * FROM `'._DB_PREFIX_.'htl_room_information` where `id_hotel`='.(int) $id_hotel.' AND `id_product`='.(int) $id_product.' AND `id_status`=3 AND `id` NOT IN (SELECT `id_room` from `'._DB_PREFIX_.'htl_booking_detail` where `date_from`< \''.pSQL($date_to).'\' AND `date_to`>\''.pSQL($date_from).'\' AND `id_product`='.(int) $id_product.' AND `id_hotel`='.(int) $id_hotel.')');
}
public function getRoomTypeBookedRoomsForDateRange($id_hotel, $id_product, $date_from, $date_to)
{
return Db::getInstance()->executeS('SELECT * FROM `'._DB_PREFIX_.'htl_booking_detail` where `date_from`< \''.pSQL($date_to).'\' AND `date_to`>\''.pSQL($date_from).'\' AND `id_product`='.(int) $id_product.' AND `id_hotel`='.(int) $id_hotel);
}
public function getFutureBookings($idRoom)
{
return Db::getInstance()->executeS('SELECT `id`, `id_order`, `date_from`, `date_to` FROM `'._DB_PREFIX_.'htl_booking_detail` where `date_to` > \''.pSQL(date('Y-m-d')).'\' AND `id` NOT IN ('.OrderReturn::getRefundedBookingIdsSubquery().') AND `id_room`='.(int) $idRoom);
}
// Webservice :: webservice add function
public function addWs($autodate = true, $null_values = false)
{
$objRoomType = new HotelRoomType();
if ($roomTypeInfo = $objRoomType->getRoomTypeInfoByIdProduct($this->id_product)) {
$this->id_hotel = $roomTypeInfo['id_hotel'];
return $this->add($autodate, $null_values);
} else {
WebserviceRequest::getInstance()->setError(400, 'Invalid id product', 134);
}
return false;
}
// Webservice :: webservice update function
public function updateWs($null_values = false)
{
$objRoomType = new HotelRoomType();
if ($roomTypeInfo = $objRoomType->getRoomTypeInfoByIdProduct($this->id_product)) {
$this->id_hotel = $roomTypeInfo['id_hotel'];
return $this->update($null_values);
} else {
WebserviceRequest::getInstance()->setError(400, 'Invalid id product', 134);
}
return false;
}
// Webservice :: webservice delete function
public function deleteWs()
{
return $this->delete();
}
// ── REPORT METHODS ────────────────────────────────────────────────────────
/**
* Room-type × date grid showing total / booked / available / OOO per row.
* Used by availability report tab.
*
* @param array $params date_from, date_to, id_hotel, id_product, id_lang
* @return array rows: date, id_product, room_type_name, total_rooms, rooms_booked, out_of_order, available, occupancy_pct
*/
public static function getAvailabilityReport(array $params)
{
$dateFrom = pSQL($params['date_from']);
$dateTo = pSQL(isset($params['date_to']) ? $params['date_to'] : $params['date_from']);
$idsHotel = isset($params['ids_hotel']) ? $params['ids_hotel'] : (isset($params['id_hotel']) ? $params['id_hotel'] : false);
$idProduct = isset($params['id_product']) ? (int) $params['id_product'] : 0;
$idLang = isset($params['id_lang']) ? (int) $params['id_lang'] : 0;
if (!$idLang) {
$idLang = Context::getContext()->language->id;
}
$roomTypes = Db::getInstance()->executeS(
'SELECT hri.`id_product`, pl.`name` AS room_type_name,
COUNT(hri.`id`) AS total_rooms,
SUM(CASE WHEN hri.`id_status` IN ('.(int) self::STATUS_INACTIVE.','.(int) self::STATUS_TEMPORARY_INACTIVE.') THEN 1 ELSE 0 END) AS ooo_rooms
FROM `'._DB_PREFIX_.'htl_room_information` hri
INNER JOIN `'._DB_PREFIX_.'product` p ON (p.`id_product` = hri.`id_product` AND p.`active` = 1)
INNER JOIN `'._DB_PREFIX_.'product_lang` pl
ON (pl.`id_product` = hri.`id_product` AND pl.`id_lang` = '.(int) $idLang.')
WHERE 1'
.HotelBranchInformation::addHotelRestriction($idsHotel, 'hri')
.($idProduct ? ' AND hri.`id_product` = '.$idProduct : '').'
GROUP BY hri.`id_product`'
);
if (!$roomTypes) {
return array();
}
$dateToNext = pSQL(date('Y-m-d', strtotime('+1 day', strtotime($dateTo))));
$bookingsRaw = Db::getInstance()->executeS(
'SELECT hbd.`id_product`, hbd.`id_room`, hbd.`date_from`, hbd.`date_to`
FROM `'._DB_PREFIX_.'htl_booking_detail` hbd
INNER JOIN `'._DB_PREFIX_.'orders` o ON (o.`id_order` = hbd.`id_order` AND o.`valid` = 1)
WHERE hbd.`is_refunded` = 0 AND hbd.`is_cancelled` = 0
AND hbd.`date_from` < "'.$dateToNext.'" AND hbd.`date_to` > "'.$dateFrom.'"'
.HotelBranchInformation::addHotelRestriction($idsHotel, 'hbd')
.($idProduct ? ' AND hbd.`id_product` = '.$idProduct : '')
);
$bookingsByProduct = array();
foreach ($bookingsRaw as $b) {
$bookingsByProduct[$b['id_product']][] = $b;
}
$result = array();
$current = $dateFrom;
while ($current <= $dateTo) {
$next = date('Y-m-d', strtotime('+1 day', strtotime($current)));
foreach ($roomTypes as $rt) {
$idProd = $rt['id_product'];
$bookedRooms = array();
if (isset($bookingsByProduct[$idProd])) {
foreach ($bookingsByProduct[$idProd] as $b) {
if ($b['date_from'] < $next && $b['date_to'] > $current) {
$bookedRooms[$b['id_room']] = true;
}
}
}
$booked = count($bookedRooms);
$total = (int) $rt['total_rooms'];
$ooo = (int) $rt['ooo_rooms'];
$available = max(0, $total - $booked - $ooo);
$result[] = array(
'date' => $current,
'id_product' => $idProd,
'room_type_name' => $rt['room_type_name'],
'total_rooms' => $total,
'rooms_booked' => $booked,
'out_of_order' => $ooo,
'available' => $available,
'occupancy_pct' => $total ? round($booked / $total * 100, 1) : 0.0,
);
}
$current = $next;
}
return $result;
}
/**
* Per-room status with current guest info for room-status report tab.
*
* @param array $params date_from, date_to, id_hotel, id_product, id_lang, housekeeping_installed
* @return array
*/
public static function getRoomStatus(array $params)
{
$dateFrom = pSQL($params['date_from']);
$dateTo = pSQL(isset($params['date_to']) ? $params['date_to'] : $params['date_from']);
$dateToNext = pSQL(date('Y-m-d', strtotime('+1 day', strtotime($dateTo))));
$idsHotel = isset($params['ids_hotel']) ? $params['ids_hotel'] : (isset($params['id_hotel']) ? $params['id_hotel'] : false);
$idProduct = isset($params['id_product']) ? (int) $params['id_product'] : 0;
$idLang = isset($params['id_lang']) ? (int) $params['id_lang'] : 0;
$housekeepingInstalled = !empty($params['housekeeping_installed']);
if (!$idLang) {
$idLang = Context::getContext()->language->id;
}
return Db::getInstance()->executeS(
'SELECT hri.`id` AS id_room, hri.`room_num`, hri.`floor`,
CASE WHEN hri.`id_status` = '.(int) self::STATUS_TEMPORARY_INACTIVE.' AND hrdd.`id_room` IS NULL
THEN '.(int) self::STATUS_ACTIVE.'
ELSE hri.`id_status`
END AS id_status,
hri.`id_product`, hri.`id_hotel`,
pl.`name` AS room_type_name, hbil.`hotel_name`,
bkgs.`id_order`, bkgs.`date_from`, bkgs.`date_to`,
bkgs.`id_status` AS booking_status,
c.`id_customer`,
CONCAT(c.`firstname`, " ", c.`lastname`) AS guest_name'
.($housekeepingInstalled ? ', hri.`id_housekeeping_status`' : '').'
FROM `'._DB_PREFIX_.'htl_room_information` hri
INNER JOIN `'._DB_PREFIX_.'product` p ON (p.`id_product` = hri.`id_product`)
INNER JOIN `'._DB_PREFIX_.'product_lang` pl
ON (pl.`id_product` = hri.`id_product` AND pl.`id_lang` = '.(int) $idLang.')
INNER JOIN `'._DB_PREFIX_.'htl_branch_info` hbi ON (hbi.`id` = hri.`id_hotel`)
INNER JOIN `'._DB_PREFIX_.'htl_branch_info_lang` hbil
ON (hbil.`id` = hri.`id_hotel` AND hbil.`id_lang` = '.(int) $idLang.')
LEFT JOIN (
SELECT `id_room`
FROM `'._DB_PREFIX_.'htl_room_disable_dates`
WHERE `date_from` < "'.$dateToNext.'" AND `date_to` > "'.$dateFrom.'"
GROUP BY `id_room`
) hrdd ON (hrdd.`id_room` = hri.`id`)
LEFT JOIN (
SELECT hbd.`id_room`,
MIN(hbd.`id_order`) AS `id_order`,
MIN(hbd.`date_from`) AS `date_from`,
MAX(hbd.`date_to`) AS `date_to`,
MIN(hbd.`id_status`) AS `id_status`,
MIN(hbd.`id_customer`) AS `id_customer`
FROM `'._DB_PREFIX_.'htl_booking_detail` hbd
WHERE hbd.`is_refunded` = 0
AND hbd.`date_from` < "'.$dateToNext.'" AND hbd.`date_to` > "'.$dateFrom.'"
GROUP BY hbd.`id_room`
) bkgs ON (bkgs.`id_room` = hri.`id`)
LEFT JOIN `'._DB_PREFIX_.'customer` c ON (c.`id_customer` = bkgs.`id_customer`)
WHERE p.`active` = 1 AND p.`booking_product` = 1'
.($idProduct ? ' AND hri.`id_product` = '.$idProduct : '')
.HotelBranchInformation::addHotelRestriction($idsHotel, 'hri').'
ORDER BY hbil.`hotel_name`, pl.`name`, hri.`room_num`'
);
}
/**
* Floor list for filter dropdown in reports.
*
* @param array $params id_hotel, id_product
* @return array rows: floor
*/
public static function getDistinctFloors(array $params = array())
{
$idsHotel = isset($params['ids_hotel']) ? $params['ids_hotel'] : (isset($params['id_hotel']) ? $params['id_hotel'] : false);
$idProduct = isset($params['id_product']) ? (int) $params['id_product'] : 0;
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(
'SELECT DISTINCT hri.`floor`
FROM `'._DB_PREFIX_.'htl_room_information` hri
INNER JOIN `'._DB_PREFIX_.'product` p
ON (p.`id_product` = hri.`id_product` AND p.`active` = 1 AND p.`booking_product` = 1)
WHERE hri.`floor` != "" AND hri.`floor` IS NOT NULL'
.($idProduct ? ' AND hri.`id_product` = '.$idProduct : '')
.HotelBranchInformation::addHotelRestriction($idsHotel, 'hri').'
ORDER BY hri.`floor`'
);
}
}