Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update disable dates selection for a room at back office #632

Merged
merged 5 commits into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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