Skip to content

Commit

Permalink
Merge pull request #632 from abhishek-webkul/fix-disable-dates
Browse files Browse the repository at this point in the history
Update disable dates selection for a room at back office
  • Loading branch information
rohit053 authored Mar 20, 2023
2 parents a53410c + fd04ab1 commit b112435
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{**
* 2010-2023 Webkul.
*
* NOTICE OF LICENSE
*
* All right is reserved,
* Please go through LICENSE.txt file inside our module
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to newer
* versions in the future. If you wish to customize this module for your
* needs please refer to CustomizationPolicy.txt file inside our module for more information.
*
* @author Webkul IN
* @copyright 2010-2023 Webkul IN
* @license LICENSE.txt
*}

{l s='This room already has bookings for highlighted date range(s):'}

<table width="70%">
<tr>
<th class="text-center">{l s='Order ID'}</th>
<th class="text-center">{l s='Date From'}</th>
<th class="text-center">{l s='Date To'}</th>
</tr>
{foreach from=$booked_rows_list item=booked_row}
<tr>
<td class="text-center">
<a href="{$link->getAdminLink('AdminOrders')}&id_order={$booked_row->id_order}&vieworder" target="_blank"><strong>#{$booked_row->id_order|intval}</strong></a>
</td>
<td class="text-center">{dateFormat date=$booked_row->date_from}</td>
<td class="text-center">{dateFormat date=$booked_row->date_to}</td>
</tr>
{/foreach}
</table>
119 changes: 85 additions & 34 deletions admin/themes/default/template/controllers/products/configuration.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
<input type="text" class="form-control room_comment" value="{$room_info['comment']}" name="{$var_name_room_info|cat:'[comment]'}">
</td>
<td class="col-sm-2 center">
<a class="btn btn-default deactiveDatesModal {if $room_info['id_status'] != $rm_status['STATUS_TEMPORARY_INACTIVE']['id'] }disabled{/if}" data-toggle="modal" data-target="#deactiveDatesModal">{if $room_info['id_status'] != $rm_status['STATUS_TEMPORARY_INACTIVE']['id'] }{l s='Add Dates'}{else}{l s='View Dates'}{/if}
<a class="btn btn-default deactiveDatesModal {if $room_info['id_status'] != $rm_status['STATUS_TEMPORARY_INACTIVE']['id'] }disabled{/if}" data-toggle="modal" data-target="#deactiveDatesModal" data-id-room="{$room_info['id']}">{if $room_info['id_status'] != $rm_status['STATUS_TEMPORARY_INACTIVE']['id'] }{l s='Add Dates'}{else}{l s='View Dates'}{/if}
</a>
<input type="hidden" class="form-control disable_dates_json" name="{$var_name_room_info|cat:'[disable_dates_json]'}" {if $room_info['id_status'] == $rm_status['STATUS_TEMPORARY_INACTIVE']['id']}value="{$room_info['disable_dates_json']|escape:'html':'UTF-8'}"{/if}>
</td>
Expand Down Expand Up @@ -184,6 +184,7 @@
<h4 class="modal-title"><i class="icon-calendar"></i>&nbsp; {l s='Disable Dates'}</h4>
</div>
<div class="modal-body">
<div class="text-left errors-wrap" style="display: none;"></div>
<div class="alert alert-info">
<p>{l s='Please note that the date chosen for field \'Date To\' is not considered as a blocking date.'}</p>
</div>
Expand Down Expand Up @@ -239,13 +240,13 @@
var prod_link = "{$link->getAdminLink('AdminProducts')}";
var rm_status = {$rm_status|@json_encode};
var currentRoomRow = 0;
var datesMissing = "{$datesMissing}";
var datesOverlapping = "{$datesOverlapping}";
$(document).ready(function() {
const DisableDatesModal = {
init: function() {
this.addNewRow();
DisableDatesModal.addNewRow();
DisableDatesModal.hideErrors();
DisableDatesModal.removeAllInvalidRowDataMarkers();
},
addNewRow: function() {
$('#deactiveDatesModal tbody').append(this.disableDatesRowHtml);
Expand All @@ -260,33 +261,58 @@
$(dateRangeRow).find('.room_disable_reason').val(dateRange.reason);
});
},
getValidationErrors: function() {
let $return = false;
validateDisableDates: function(cb) {
DisableDatesModal.hideErrors();
DisableDatesModal.removeAllInvalidRowDataMarkers();
DisableDatesModal.disableRowDeleteActionButtons();
let idRoom = parseInt($('#deactiveDatesModal .room-disable-dates').attr('data-id-room'));
idRoom = idRoom == isNaN(idRoom) ? 0 : idRoom;
const disableDates = Array();
$('#deactiveDatesModal .room-disable-dates tbody tr').each(function(i, tr) {
const dateFrom = $(tr).find('.disabled_date_from').val().trim();
const dateTo = $(tr).find('.disabled_date_to').val().trim();
if (!dateFrom.length || !dateTo.length) {
$return = datesMissing;
}
disableDates.push({ dateFrom, dateTo });
const date_from = $(tr).find('.disabled_date_from').val().trim();
const date_to = $(tr).find('.disabled_date_to').val().trim();
disableDates.push({ date_from, date_to });
});
$.each(disableDates, function(keyOuter, dateRangeOuter) {
$.each(disableDates, function(keyInner, dateRangeInner) {
if (keyInner != keyOuter) {
if ((dateRangeOuter.dateFrom <= dateRangeInner.dateTo)
&& (dateRangeInner.dateFrom <= dateRangeOuter.dateTo)
) {
$return = datesOverlapping;
$.ajax({
url: prod_link,
type: 'POST',
data: {
ajax: true,
action: 'validateDisableDates',
id_room: idRoom,
disable_dates: disableDates,
},
dataType: 'JSON',
success: function(response) {
if (response.status) {
if (typeof cb === 'function') {
cb();
}
} else {
DisableDatesModal.showErrors(response.errors);
DisableDatesModal.addInvalidRowDataMarkers(response.rows_to_highlight);
}
});
},
complete: function () {
DisableDatesModal.enableRowDeleteActionButtons();
}
});
},
showErrors: function(errors) {
$('#deactiveDatesModal .errors-wrap').html(errors);
$('#deactiveDatesModal .errors-wrap').show();
},
hideErrors: function() {
$('#deactiveDatesModal .errors-wrap').hide();
$('#deactiveDatesModal .errors-wrap').html('');
},
addInvalidRowDataMarkers: function(rowsToHighlight) {
rowsToHighlight.map(function (rowIndex) {
const tr = $('#deactiveDatesModal .room-disable-dates tbody tr').eq(rowIndex);
DisableDatesModal.markRowDataInvalid(tr);
});
return $return;
},
getDisableDatesInfo: function() {
const disableDates = Array();
Expand All @@ -300,6 +326,24 @@
return disableDates;
},
disableRowDeleteActionButtons: function() {
const disableDates = Array();
$('#deactiveDatesModal .room-disable-dates .remove-disable-dates-button').addClass('disabled');
},
enableRowDeleteActionButtons: function() {
const disableDates = Array();
$('#deactiveDatesModal .room-disable-dates .remove-disable-dates-button').removeClass('disabled');
},
markRowDataInvalid: function(tr) {
$(tr).css({ 'outline': '1px solid #D27C82', 'border-radius': '2px' });
},
removeAllInvalidRowDataMarkers: function(tr) {
$('#deactiveDatesModal .room-disable-dates tr').css('outline', '');
$(tr).css('outline', '');
},
removeRowDataMark: function(tr) {
$(tr).css('outline', '');
},
disableDatesRowHtml: `
<tr class="disabledDatesTr">
<td class="col-sm-2 center">
Expand All @@ -322,31 +366,38 @@
$('#deactiveDatesModal').on('show.bs.modal', function(e) {
const triggerRoomRow = $(e.relatedTarget);
const roomRowIndex = parseInt($(triggerRoomRow).closest('tr').attr('data-row-index'));
const idRoom = parseInt($(triggerRoomRow).attr('data-id-room'));
$('#deactiveDatesModal table.room-disable-dates tbody').html('');
$('#deactiveDatesModal table.room-disable-dates').attr('data-room-row-index', roomRowIndex);
$('#deactiveDatesModal table.room-disable-dates').attr('data-id-room', idRoom);
let disableDates = $(triggerRoomRow).closest('tr').find('.disable_dates_json').val();
if (!disableDates) {
DisableDatesModal.init();
return;
}
disableDates = JSON.parse(disableDates);
DisableDatesModal.hideErrors();
DisableDatesModal.populateWithDatesInfo(disableDates);
});
// copy json formatted dates to room
$(document).on('click', '.deactiveDatesModalSubmit', function() {
const error = DisableDatesModal.getValidationErrors();
if (error) {
alert(error);
return;
}
// Disable dates data filling when model open
$('#deactiveDatesModal').on('hide.bs.modal', function(e) {
const disableDates = DisableDatesModal.getDisableDatesInfo();
const roomRowIndex = parseInt($('#deactiveDatesModal table.room-disable-dates').attr('data-room-row-index'));
const roomRow = $('#product-configuration .hotel-room tr.room_data_values[data-row-index='+roomRowIndex+']');
$(roomRow).find('.disable_dates_json').val(JSON.stringify(disableDates));
$('#deactiveDatesModal').modal('hide');
});
// copy json formatted dates to room
$(document).on('click', '.deactiveDatesModalSubmit', function() {
DisableDatesModal.validateDisableDates(function () {
const disableDates = DisableDatesModal.getDisableDatesInfo();
const roomRowIndex = parseInt($('#deactiveDatesModal table.room-disable-dates').attr('data-room-row-index'));
const roomRow = $('#product-configuration .hotel-room tr.room_data_values[data-row-index='+roomRowIndex+']');
$(roomRow).find('.disable_dates_json').val(JSON.stringify(disableDates));
$('#deactiveDatesModal').modal('hide');
});
});
// Add new room detail
Expand Down Expand Up @@ -456,7 +507,7 @@
onClose: function(selectedDate) {
var dateTo = $(this).closest('tr').find('.disabled_date_to').val();
if (!dateTo || (dateTo && selectedDate >= dateTo)) {
$('.disabled_date_to').datepicker('show');
$(this).closest('tr').find('.disabled_date_to').datepicker('show');
}
},
});
Expand Down
89 changes: 84 additions & 5 deletions controllers/admin/AdminProductsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2778,8 +2778,6 @@ public function initFormConfiguration($obj)
'product' => $obj,
'htl_info' => $hotelInfo,
'rm_status' => $roomStatus,
'datesMissing' => $this->l('Some dates are missing. Please select all the date ranges.'),
'datesOverlapping' => $this->l('Some dates are conflicting with each other. Please check and reselect the date ranges.'),
)
);
} else {
Expand Down Expand Up @@ -3117,7 +3115,7 @@ public function ajaxProcessDeleteRoomTypeLengthOfStayRestriction()
}
}

public function validateDisableDateRanges($disableDates, $index)
public function validateDisableDateRanges($disableDates, $index, $idRoom)
{
if (count($disableDates)) {
foreach ($disableDates as $disable_key => $disableDate) {
Expand All @@ -3134,6 +3132,7 @@ public function validateDisableDateRanges($disableDates, $index)
$index
);
} else {
$objHotelBookingDetail = new HotelBookingDetail();
foreach ($disableDates as $key => $disDate) {
if ($key != $disable_key) {
if ((($disableDate['date_from'] < $disDate['date_from']) && ($disableDate['date_to'] <= $disDate['date_from'])) || (($disableDate['date_from'] > $disDate['date_from']) && ($disableDate['date_from'] >= $disDate['date_to']))) {
Expand All @@ -3145,6 +3144,13 @@ public function validateDisableDateRanges($disableDates, $index)
);
}
}
// check if room has booking for current date range
if ($objHotelBookingDetail->chechRoomBooked($idRoom, $disDate['date_from'], $disDate['date_to'])) {
$this->errors[] = sprintf(
Tools::displayError('The %s room already has bookings for selected disable dates. Please reselect disable dates.'),
$index
);
}
}
}
}
Expand Down Expand Up @@ -3242,7 +3248,7 @@ public function validateConfigurationPostData()
if ($roomInfo['id_status'] == HotelRoomInformation::STATUS_TEMPORARY_INACTIVE) {
$disableDates = json_decode($roomInfo['disable_dates_json'], true);
if ($roomInfo['disable_dates_json'] !== 0) {
$this->validateDisableDateRanges($disableDates, $index);
$this->validateDisableDateRanges($disableDates, $index, $roomInfo['id']);
}
}
}
Expand Down Expand Up @@ -4631,6 +4637,79 @@ public function ajaxProcessGetIdHotelByIdProduct()
die(json_encode($response));
}

public function ajaxProcessValidateDisableDates()
{
$response = array('status' => false);

$idRoom = (int) Tools::getValue('id_room');
$disableDates = Tools::getValue('disable_dates');

$rowsToHighlight = array();
$bookedRows = array();
if (is_array($disableDates) && count($disableDates)) {
foreach ($disableDates as $key => $dateRange) {
if (!Validate::isDate($dateRange['date_from']) || !Validate::isDate($dateRange['date_to'])) {
$this->errors[] = $this->l('Some dates are missing. Please select all the date ranges.');
$rowsToHighlight[] = $key;
}
}

if (!count($this->errors)) {
foreach ($disableDates as $keyOuter => $dateRangeOuter) {
foreach ($disableDates as $keyInner => $dateRangeInner) {
if ($keyInner != $keyOuter) {
if ((($dateRangeOuter['date_from'] >= $dateRangeInner['date_from']) && ($dateRangeOuter['date_from'] < $dateRangeInner['date_to']))
|| (($dateRangeInner['date_from'] >= $dateRangeOuter['date_from']) && ($dateRangeInner['date_from'] < $dateRangeOuter['date_to']))
) {
$this->errors[] = $this->l('Some dates are conflicting with each other. Please check and reselect the date ranges.');
$rowsToHighlight[] = $keyOuter;
$rowsToHighlight[] = $keyInner;
}
}
}
}
}

if (!count($this->errors)) {
if ($idRoom) {
$objHotelBookingDetail = new HotelBookingDetail();
foreach ($disableDates as $key => $dateRange) {
if ($bookingRow = $objHotelBookingDetail->chechRoomBooked($idRoom, $dateRange['date_from'], $dateRange['date_to'])) {
$bookedRows[] = new HotelBookingDetail($bookingRow['id']);
$rowsToHighlight[] = $key;
}
}
}
}
}

if (count($bookedRows)) {
$this->context->smarty->assign(array(
'link' => $this->context->link,
'booked_rows_list' => $bookedRows,
));

$this->errors[] = $this->context->smarty->fetch('controllers/products/booked_room_date_ranges_list.tpl');
}

$this->errors = array_unique($this->errors);
$rowsToHighlight = array_values(array_unique($rowsToHighlight));

if (!count($this->errors)) {
$response['status'] = true;
} else {
$this->context->smarty->assign(array(
'errors' => $this->errors,
));

$response['errors'] = $this->context->smarty->fetch('alerts.tpl');
$response['rows_to_highlight'] = $rowsToHighlight;
$response['status'] = false;
}

$this->ajaxDie(json_encode($response));
}

public function processImageLegends()
{
if (Tools::getValue('key_tab') == 'Images' && Tools::getValue('submitAddproductAndStay') == 'update_legends' && Validate::isLoadedObject($product = new Product((int)Tools::getValue('id_product')))) {
Expand Down Expand Up @@ -4662,4 +4741,4 @@ public function displayPreviewLink($token = null, $id, $name = null)

return $tpl->fetch();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1254,7 +1254,7 @@ protected function getSearchBookedRooms($params)
// This function algo is same as available rooms algo and it not similar to booked rooms algo.
public function chechRoomBooked($id_room, $date_from, $date_to)
{
$sql = 'SELECT `id_product`, `id_order`, `id_cart`, `id_room`, `id_hotel`, `id_customer`
$sql = 'SELECT `id`, `id_product`, `id_order`, `id_cart`, `id_room`, `id_hotel`, `id_customer`
FROM `'._DB_PREFIX_.'htl_booking_detail` WHERE `id_room` = '.(int)$id_room.
' AND `is_back_order` = 0 AND `is_refunded` = 0 AND ((date_from <= \''.pSQL($date_from).'\' AND date_to > \''.
pSQL($date_from).'\' AND date_to <= \''.pSQL($date_to).'\') OR (date_from > \''.pSQL($date_from).
Expand Down

0 comments on commit b112435

Please sign in to comment.