File "default.php"
Full Path: /home/romayxjt/public_html/wp-content/plugins/vikbooking/admin/views/ratesoverv/tmpl/default.php
File size: 146.71 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* @package VikBooking
* @subpackage com_vikbooking
* @author Alessio Gaggii - e4j - Extensionsforjoomla.com
* @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
* @link https://vikwp.com
*/
defined('ABSPATH') or die('No script kiddies please!');
$all_rooms = $this->all_rooms;
$categories = $this->categories;
$roomrows = $this->roomrows;
$seasoncal_nights = $this->seasons_cal_nights;
$seasons_cal = $this->seasons_cal;
$tsstart = $this->tsstart;
// JS lang defs
JText::script('VBO_BOOKNOW');
JText::script('VBPVIEWORDERSTHREE');
JText::script('VBEDITORDERTHREE');
JText::script('VBDAYS');
JText::script('VBDAY');
JText::script('VBMAILADULTS');
JText::script('VBMAILADULT');
JText::script('VBMAILCHILDREN');
JText::script('VBMAILCHILD');
JText::script('VBO_MISSING_SUBUNIT');
JText::script('VBRATESOVWRATESCALCULATORCALC');
JText::script('VBRATESOVWRATESCALCULATORCALCING');
JText::script('VBOVCMRATESRES');
JText::script('VBO_IS_DERIVED_RATE');
JText::script('VBO_PLEASE_FILL_FIELDS');
JText::script('VBO_RATES_AND_RESTR');
JText::script('VBSAVE');
JText::script('VBANNULLA');
JText::script('VBAPPLY');
JText::script('VBNEWRESTRICTIONDFROMRANGE');
JText::script('VBNEWRESTRICTIONDTORANGE');
$document = JFactory::getDocument();
$vbo_app = VikBooking::getVboApplication();
$vbo_app->loadSelect2();
$vbo_app->loadDatePicker();
$vbo_app->loadDatesRangePicker();
$is_mobile = VikBooking::detectUserAgent(false, false);
$pdebug = VikRequest::getint('e4j_debug', '', 'request');
$vbo_df = VikBooking::getDateFormat();
$datesep = VikBooking::getDateSeparator();
$df = $vbo_df == "%d/%m/%Y" ? 'd/m/Y' : ($vbo_df == "%m/%d/%Y" ? 'm/d/Y' : 'Y/m/d');
$juidf = $vbo_df == "%d/%m/%Y" ? 'dd/mm/yy' : ($vbo_df == "%m/%d/%Y" ? 'mm/dd/yy' : 'yy/mm/dd');
$currencysymb = VikBooking::getCurrencySymb();
list($currency_digits, $currency_decimals, $currency_thousands) = explode(':', VikBooking::getNumberFormatData());
// immediately define the maximum visible days
$MAX_DAYS = $this->max_days;
// check-in/out times
$pcheckinh = 0;
$pcheckinm = 0;
$pcheckouth = 0;
$pcheckoutm = 0;
$timeopst = VikBooking::getTimeOpenStore();
if (is_array($timeopst)) {
$opent = VikBooking::getHoursMinutes($timeopst[0]);
$closet = VikBooking::getHoursMinutes($timeopst[1]);
$pcheckinh = $opent[0];
$pcheckinm = $opent[1];
$pcheckouth = $closet[0];
$pcheckoutm = $closet[1];
}
/**
* Check if season records should be preloaded. Beware of the hundreds of MBs of server's memory
* that could be used for pre-loading and pre-caching records in favour of CPU.
*
* @since 1.16.10 (J) - 1.6.10 (WP)
* @since 1.18.0 (J) - 1.8.0 (WP) seasons caching is enabled by default for better performances.
*/
$from_info = getdate($tsstart);
$season_from_ts = mktime($pcheckinh, $pcheckinm, 0, $from_info['mon'], $from_info['mday'], $from_info['year']);
$season_to_ts = mktime($pcheckouth, $pcheckoutm, 0, $from_info['mon'], $from_info['mday'] + $MAX_DAYS, $from_info['year']);
$cached_seasons = VikBooking::getDateSeasonRecords($season_from_ts, $season_to_ts, $this->req_room_ids);
// update configuration record
VBOFactory::getConfig()->set('pre_cache_seasons', 1);
/**
* In order to improve the performances, we parse all listing rates at once, as long as season records were cached.
* This is only performed over the first (main) room rate plan, because multiple rate plans are not compatible.
*
* @since 1.18.0 (J) - 1.8.0 (WP)
*/
$main_room_rates = array_map(function($rrate) {
// convert a possible multi-rate-plan listing into a single-rate-plan listing
return [$rrate[0]];
}, array_filter($this->roomrates));
$current_rates_pool = [];
$iter_date = $from_info;
$cell_count = 0;
while ($cell_count < $MAX_DAYS) {
$day_key = date('Y-m-d', $iter_date[0]);
$today_tsin = mktime($pcheckinh, $pcheckinm, 0, $iter_date['mon'], $iter_date['mday'], $iter_date['year']);
$today_tsout = mktime($pcheckouth, $pcheckoutm, 0, $iter_date['mon'], ($iter_date['mday'] + 1), $iter_date['year']);
$listing_tars = VikBooking::applySeasonalPrices($main_room_rates, $today_tsin, $today_tsout, $cached_seasons);
// scan the tariff results
foreach ($listing_tars as $listing_id => $tars) {
// initialize listing rates, if needed
if (!isset($current_rates_pool[$listing_id])) {
$current_rates_pool[$listing_id] = [];
}
// set rate for this listing and day (associative by rate plan id - just one)
$current_rates_pool[$listing_id][$day_key] = array_combine(array_column($tars, 'idprice'), array_values($tars));
}
// increase cells counter
$cell_count++;
// go to next day
$iter_date = getdate(mktime(0, 0, 0, $iter_date['mon'], ($iter_date['mday'] + 1), $iter_date['year']));
}
// free memory up
unset($main_room_rates);
// build environment data
$mb_support = function_exists('mb_substr');
$short_wdays = [
JText::translate('VBSUNDAY'),
JText::translate('VBMONDAY'),
JText::translate('VBTUESDAY'),
JText::translate('VBWEDNESDAY'),
JText::translate('VBTHURSDAY'),
JText::translate('VBFRIDAY'),
JText::translate('VBSATURDAY'),
];
$short_mons = [
JText::translate('VBMONTHONE'),
JText::translate('VBMONTHTWO'),
JText::translate('VBMONTHTHREE'),
JText::translate('VBMONTHFOUR'),
JText::translate('VBMONTHFIVE'),
JText::translate('VBMONTHSIX'),
JText::translate('VBMONTHSEVEN'),
JText::translate('VBMONTHEIGHT'),
JText::translate('VBMONTHNINE'),
JText::translate('VBMONTHTEN'),
JText::translate('VBMONTHELEVEN'),
JText::translate('VBMONTHTWELVE'),
];
foreach ($short_wdays as $k => $v) {
if ($mb_support) {
$short_wdays[$k] = mb_substr($v, 0, 3, 'UTF-8');
} else {
$short_wdays[$k] = substr($v, 0, 3);
}
}
foreach ($short_mons as $k => $v) {
if ($mb_support) {
$short_mons[$k] = mb_substr($v, 0, 3, 'UTF-8');
} else {
$short_mons[$k] = substr($v, 0, 3);
}
}
$json_short_wdays = json_encode($short_wdays);
$json_short_mons = json_encode($short_mons);
$json_room_ota_rels = json_encode($this->room_ota_relations);
$json_mini_thumbnails = json_encode(VBORoomHelper::getInstance()->loadMiniThumbnails($all_rooms));
// add to DOM the necessary script declaration
$document->addScriptDeclaration(
<<<JS
var vboMapWdays = $json_short_wdays;
var vboMapMons = $json_short_mons;
var vboRoomOtaRels = $json_room_ota_rels;
var vboListingsMiniThumbnails = $json_mini_thumbnails;
var vbo_currency_symbol = "$currencysymb";
var vbo_currency_digits = "$currency_digits";
var vbo_currency_decimals = "$currency_decimals";
var vbo_currency_thousands = "$currency_thousands";
JS
);
$price_types_show = true;
$los_show = true;
$cookie = JFactory::getApplication()->input->cookie;
$cookie_tab = $cookie->get('vboRovwRab', 'cal', 'string');
$collapse_status = $cookie->get('vboRovwColl', 0, 'int');
// access room helper to detect LOS rates
$room_helper = VBORoomHelper::getInstance();
// derived rate plans data
$have_derived_rates = [];
$derived_rates_info = [];
foreach (VikBooking::getAvailabilityInstance()->loadRatePlans() as $rate_plan) {
if ($rate_plan['derived_id'] && $rate_plan['derived_data']) {
$derived_rates_info[$rate_plan['id']] = $rate_plan;
if (!in_array($rate_plan['derived_id'], $have_derived_rates)) {
// push parent rate to the list
$have_derived_rates[] = $rate_plan['derived_id'];
}
}
}
?>
<div class="vbo-ratesoverview-top-outer">
<div class="vbo-ratesoverview-top-outer-inner vbo-toggle-small">
<?php echo $vbo_app->printYesNoButtons('vbo_collapse', JText::translate('VBYES'), JText::translate('VBNO'), (!$collapse_status ? 1 : 0), 1, 0, "vboToggleCollapse();"); ?>
<span onclick="jQuery(this).parent().find('input').trigger('click');"><?php echo JText::translate('VBO_EXPAND'); ?></span>
</div>
</div>
<div class="vbo-ratesoverview-top-container<?php echo $collapse_status ? ' collapsed' : ''; ?>">
<div class="vbo-ratesoverview-roomsel-block">
<form method="get" action="index.php?option=com_vikbooking" name="vboratesovwform">
<input type="hidden" name="option" value="com_vikbooking" />
<input type="hidden" name="task" value="ratesoverv" />
<div class="vbo-ratesoverview-roomsel-entry vbo-ratesoverview-roomsel-entry-chrooms">
<label for="roomsel"><?php VikBookingIcons::e('bed'); ?> <?php echo JText::translate('VBPVIEWORDERSTHREE'); ?></label>
<select name="cid[]" <?php echo count($all_rooms) > 1 ? 'multiple="multiple"' : 'onchange="document.vboratesovwform.submit();"' ?> id="roomsel" style="min-width: 160px; max-width: 250px;">
<?php
foreach ($all_rooms as $room) {
?>
<option value="<?php echo $room['id']; ?>"<?php echo in_array($room['id'], $this->req_room_ids) ? ' selected="selected"' : ''; ?>><?php echo $room['name']; ?></option>
<?php
}
/**
* Use the optgroup to separate rooms from categories in the
* drop down menu, only if all_rooms > 1 e categories > 1.
*
* @since 1.13
*/
if (count($all_rooms) > 1 && count($categories) > 1) {
?>
<optgroup label="<?php echo addslashes(JText::translate('VBOCATEGORYFILTER')); ?>">
<?php
foreach ($categories as $cat) {
// we use negative values for the IDs of the categories
$cat_id = ($cat['id'] - ($cat['id'] * 2));
?>
<option value="<?php echo $cat_id; ?>"><?php echo (in_array($cat['id'], $this->reqcats) ? '- ' : '') . $cat['name']; ?></option>
<?php
}
?>
</optgroup>
<?php
}
//
?>
</select>
<button type="button" class="btn vbo-config-btn" title="<?php echo htmlspecialchars(JText::translate('VBODRIVERLOAD')); ?>" onclick="document.vboratesovwform.submit();"><i class="vboicn-loop2"></i></button>
<?php
if (count($all_rooms) > 1 && count($all_rooms) < 50 && count($this->req_room_ids) < count($all_rooms)) {
// display select all rooms button
?>
<div class="vbo-roverview-selall-rooms">
<button type="button" class="btn vbo-config-btn" onclick="vboSelectAllRooms(this);"><?php VikBookingIcons::e('layer-group'); ?> <?php echo JText::translate('VBOSELECTALL'); ?></button>
</div>
<?php
}
?>
</div>
<div class="vbo-ratesoverview-roomsel-entry vbo-ratesoverview-roomsel-entry-calc">
<label for="checkindate" onclick="vboCheckCollapse();"><?php VikBookingIcons::e('calculator'); ?> <?php echo JText::translate('VBRATESOVWRATESCALCULATOR'); ?></label>
<div class="vbo-ratesoverview-roomsel-entry-calc-inner"<?php echo $collapse_status ? ' style="display: none;"' : ''; ?>>
<span class="vbo-ratesoverview-entryinline vbo-ratesoverview-rcalc-srooms">
<select name="roomselcalc" id="roomselcalc" style="max-width: 250px;">
<?php
foreach ($all_rooms as $room) {
?>
<option value="<?php echo $room['id']; ?>"<?php echo $room['id'] == ($roomrows[$this->firstroom]['id'] ?? '') ? ' selected="selected"' : ''; ?>><?php echo $room['name']; ?></option>
<?php
}
?>
</select>
</span>
<span class="vbo-ratesoverview-entryinline">
<div class="vbo-field-calendar">
<div class="input-append">
<input type="text" autocomplete="off" value="" class="vbo-roverv-rcalc-cal" size="10" id="checkindate" name="checkindate" placeholder="<?php echo JText::translate('VBPICKUPAT'); ?>" />
<button type="button" class="btn btn-secondary" id="checkindate-trig"><?php VikBookingIcons::e('calendar', 'icn-nomargin'); ?></button>
</div>
</div>
</span>
<span class="vbo-ratesoverview-entryinline">
<div class="vbo-field-calendar">
<div class="input-append">
<input type="text" autocomplete="off" value="" class="vbo-roverv-rcalc-cal" size="10" id="checkoutdate" name="checkoutdate" placeholder="<?php echo JText::translate('VBRELEASEAT'); ?>" />
<button type="button" class="btn btn-secondary" id="checkoutdate-trig"><?php VikBookingIcons::e('calendar', 'icn-nomargin'); ?></button>
</div>
</div>
</span>
<span class="vbo-ratesoverview-entryinline"><span><?php echo JText::translate('VBRATESOVWRATESCALCNUMNIGHTS'); ?></span> <input type="number" id="vbo-numnights" value="1" min="1" max="365" step="1" /></span>
<span class="vbo-ratesoverview-entryinline"><span><?php echo JText::translate('VBRATESOVWRATESCALCNUMADULTS'); ?></span> <input type="number" id="vbo-numadults" value="<?php echo ($roomrows[$this->firstroom]['fromadult'] ?? ''); ?>" step="1"/></span>
<span class="vbo-ratesoverview-entryinline"><span><?php echo JText::translate('VBRATESOVWRATESCALCNUMCHILDREN'); ?></span> <input type="number" id="vbo-numchildren" value="<?php echo ($roomrows[$this->firstroom]['fromchild'] ?? ''); ?>" step="1"/></span>
<span class="vbo-ratesoverview-entryinline"><button type="button" class="btn vbo-config-btn" id="vbo-ratesoverview-calculate"><?php echo JText::translate('VBRATESOVWRATESCALCULATORCALC'); ?></button></span>
</div>
<div class="vbo-ratesoverview-calculation-response"></div>
</div>
<div class="vbo-ratesoverview-roomsel-entry vbo-ratesoverview-roomsel-entry-forecast"<?php echo (!empty($cookie_tab) && $cookie_tab != 'cal' ? ' style="display: none;"' : ''); ?>>
<label onclick="vboCheckCollapse();"><?php VikBookingIcons::e('cloud-sun-rain'); ?> <?php echo JText::translate('VBOFORECAST'); ?></label>
<div class="vbo-roverv-forecast-inner"<?php echo $collapse_status ? ' style="display: none;"' : ''; ?>>
<?php echo JLayoutHelper::render('reports.occupancy', array('vbo_page' => 'ratesoverv', 'room_ids' => $this->req_room_ids)); ?>
</div>
</div>
<div class="vbo-ratesoverview-roomsel-entry vbo-ratesoverview-roomsel-entry-los"<?php echo (!empty($cookie_tab) && $cookie_tab == 'cal' ? ' style="display: none;"' : ''); ?>>
<label><?php echo JText::translate('VBRATESOVWNUMNIGHTSACT'); ?></label>
<?php
foreach ($seasoncal_nights as $numnights) {
?>
<span class="vbo-ratesoverview-numnight" id="numnights<?php echo $numnights; ?>"><?php echo $numnights; ?></span>
<input type="hidden" name="nights_cal[]" id="inpnumnights<?php echo $numnights; ?>" value="<?php echo $numnights; ?>" />
<?php
}
?>
<input type="number" id="vbo-addnumnight" value="<?php echo isset($numnights) ? ($numnights + 1) : 1; ?>" min="1"/>
<span id="vbo-addnumnight-act"><?php VikBookingIcons::e('plus-square'); ?></span>
<button type="button" class="btn vbo-config-btn vbo-apply-los-btn" onclick="document.vboratesovwform.submit();"><?php echo JText::translate('VBRATESOVWAPPLYLOS'); ?></button>
</div>
</form>
</div>
<div class="vbo-ratesoverview-right-block">
<div class="vbo-ratesoverview-right-inner"></div>
</div>
</div>
<div class="vbo-ratesoverview-bottom-container">
<?php
foreach ($roomrows as $rid => $roomrow) {
if (count($this->req_room_ids) < 2) {
?>
<div class="vbo-ratesoverview-bottom-head">
<div class="vbo-ratesoverview-roomdetails">
<h3 class="vbo-ratesoverview-roomname"><?php echo $roomrow['name']; ?></h3>
</div>
<div class="vbo-ratesoverview-tabscont">
<div class="vbo-ratesoverview-tab-cal <?php echo (!empty($cookie_tab) && $cookie_tab == 'cal' ? 'vbo-ratesoverview-tab-active' : 'vbo-ratesoverview-tab-unactive'); ?>"><i class="vboicn-calendar"></i> <?php echo JText::translate('VBRATESOVWTABCALENDAR'); ?></div>
<div class="vbo-ratesoverview-tab-los <?php echo (!empty($cookie_tab) && $cookie_tab == 'cal' ? 'vbo-ratesoverview-tab-unactive' : 'vbo-ratesoverview-tab-active'); ?>"><i class="vboicn-clock"></i> <?php echo JText::translate('VBRATESOVWTABLOS'); ?></div>
</div>
</div>
<?php
}
?>
<div class="vbo-ratesoverview-caltab-cont" style="display: <?php echo count($this->req_room_ids) > 1 || (!empty($cookie_tab) && $cookie_tab == 'cal') ? 'block' : 'none'; ?>;">
<?php
if (count($this->req_room_ids) > 1) {
// display room name here when multiple rooms as well as the OBP toggle
if (!isset($vbo_show_toggle_obp)) {
// toggle button for showing/hiding the occupancy based pricing rules
$vbo_show_toggle_obp = 1;
$obp_status = $cookie->get('vboRovwObp', 1, 'int');
?>
<div class="vbo-ratesoverview-obp-toggle" data-obpstartstatus="<?php echo $obp_status; ?>" style="display: none;">
<div class="vbo-ratesoverview-obp-toggle-inner vbo-toggle-small">
<?php echo $vbo_app->printYesNoButtons('show_obp', JText::translate('VBYES'), JText::translate('VBNO'), $obp_status, 1, 0, "vboToggleOBPRows();"); ?>
<span class="vbo-ratesoverview-obp-toggle-txt" onclick="jQuery(this).parent().find('input').trigger('click');"><?php echo JText::translate('VBOROVERVOBP'); ?></span>
</div>
</div>
<?php
}
?>
<div class="vbo-ratesoverview-roomdetails">
<h3 class="vbo-ratesoverview-roomname" data-idroom="<?php echo $roomrow['id']; ?>"><?php echo $roomrow['name']; ?></h3>
</div>
<?php
} else {
// room name node is needed for JS
?>
<div class="vbo-ratesoverview-roomdetails" style="display: none;">
<h3 class="vbo-ratesoverview-roomname" data-idroom="<?php echo $roomrow['id']; ?>"><?php echo $roomrow['name']; ?></h3>
</div>
<?php
}
?>
<div class="vbo-ratesoverview-caltab-wrapper">
<div class="vbo-table-responsive">
<table class="vboverviewtable vbratesoverviewtable vbo-table" data-idroom="<?php echo $rid; ?>">
<tbody>
<tr class="vbo-roverviewrowone">
<td class="bluedays skip-bluedays-click">
<form name="vbratesoverview" method="post" action="index.php?option=com_vikbooking&task=ratesoverv">
<div class="vbo-roverview-datecmd-top">
<div class="vbo-roverview-datecmd-date">
<span>
<?php VikBookingIcons::e('calendar'); ?>
<input type="text" autocomplete="off" value="<?php echo date($df, $tsstart); ?>" class="vbodatepicker" name="startdate" />
</span>
</div>
</div>
</form>
</td>
<?php
$nowts = getdate($tsstart);
$days_labels = array(
JText::translate('VBSUN'),
JText::translate('VBMON'),
JText::translate('VBTUE'),
JText::translate('VBWED'),
JText::translate('VBTHU'),
JText::translate('VBFRI'),
JText::translate('VBSAT')
);
$long_days_labels = array(
JText::translate('VBSUNDAY'),
JText::translate('VBMONDAY'),
JText::translate('VBTUESDAY'),
JText::translate('VBWEDNESDAY'),
JText::translate('VBTHURSDAY'),
JText::translate('VBFRIDAY'),
JText::translate('VBSATURDAY')
);
$months_labels = array(
JText::translate('VBMONTHONE'),
JText::translate('VBMONTHTWO'),
JText::translate('VBMONTHTHREE'),
JText::translate('VBMONTHFOUR'),
JText::translate('VBMONTHFIVE'),
JText::translate('VBMONTHSIX'),
JText::translate('VBMONTHSEVEN'),
JText::translate('VBMONTHEIGHT'),
JText::translate('VBMONTHNINE'),
JText::translate('VBMONTHTEN'),
JText::translate('VBMONTHELEVEN'),
JText::translate('VBMONTHTWELVE')
);
$long_months_labels = $months_labels;
foreach ($months_labels as $i => $v) {
$months_labels[$i] = function_exists('mb_substr') ? mb_substr($v, 0, 3, 'UTF-8') : substr($v, 0, 3);
}
$cell_count = 0;
$weekend_arr = array(0, 6);
while ($cell_count < $MAX_DAYS) {
$style = '';
$curdayymd = date('Y-m-d', $nowts[0]);
$read_day = $days_labels[$nowts['wday']] . ' ' . $nowts['mday'] . ' ' . $months_labels[$nowts['mon']-1] . ' ' . $nowts['year'];
$cell_classes = array(
'bluedays',
'cell-' . $nowts['mday'] . '-' . $nowts['mon'],
);
/**
* Critical dates defined at room-day level.
*
* @since 1.13.5
*/
$rdaynote_keyid = $curdayymd . '_' . $rid . '_0';
$rdaynote_icn = '';
if (isset($this->rdaynotes[$rdaynote_keyid])) {
// note exists for this combination of date, room ID and subunit
array_push($cell_classes, 'vbo-roverw-roomdaynote-full');
$rdaynote_icn = '<i class="' . VikBookingIcons::i('sticky-note') . '"></i>';
}
//
if (in_array((int)$nowts['wday'], $weekend_arr)) {
array_push($cell_classes, 'vbo-roverw-tablewday-wend');
}
if (isset($this->festivities[$curdayymd])) {
array_push($cell_classes, 'vbo-roverv-festcell');
}
?>
<td data-ymd="<?php echo $curdayymd; ?>" data-readymd="<?php echo $read_day; ?>" data-rid="<?php echo $rid; ?>" class="<?php echo implode(' ', $cell_classes); ?>"<?php echo $style; ?>>
<?php
if (!empty($rdaynote_icn)) {
?>
<span class="vbo-roverw-roomdaynote-icn"><?php echo $rdaynote_icn; ?></span>
<?php
}
?>
<span class="vbo-roverw-tablewday"><?php echo $days_labels[$nowts['wday']]; ?></span>
<span class="vbo-roverw-tablemday"><?php echo $nowts['mday']; ?></span>
<span class="vbo-roverw-tablemonth"><?php echo $months_labels[$nowts['mon']-1]; ?></span>
</td>
<?php
$next = $nowts['mday'] + 1;
$dayts = mktime(0, 0, 0, $nowts['mon'], $next, $nowts['year']);
$nowts = getdate($dayts);
$cell_count++;
}
?>
<td class="vbo-roverv-gonext-cell" data-rid="<?php echo $rid; ?>" rowspan="<?php echo count($this->roomrates[$rid]) + 3; ?>">
<div class="vbo-roverv-gonext-cell-inner">
<button type="button" class="btn vbo-config-btn vbo-config-btn-rounded vbo-config-btn-large" onclick="vboDisplayNextDays(this);"><?php VikBookingIcons::e('angle-double-right'); ?></button>
</div>
</td>
</tr>
<?php
$room_obp_overrides = [];
$closed_roomrateplans = VikBooking::getRoomRplansClosingDates($roomrow['id']);
foreach ($this->roomrates[$rid] as $roomrate) {
$nowts = getdate($tsstart);
$cell_count = 0;
$rplan_minlos = !empty($roomrate['minlos']) && $roomrate['minlos'] > 0 ? $roomrate['minlos'] : 0;
$rplan_haslos = $room_helper->hasLosRecords($roomrate['idroom'], $roomrate['idprice'], true);
// check for derived rate plans
$derived_str = '';
$derived_icn = '';
if (isset($derived_rates_info[$roomrate['idprice']])) {
// build derived info string
$derived_data = $derived_rates_info[$roomrate['idprice']]['derived_data'] ?? [];
$derived_str .= ($derived_rates_info[$roomrate['idprice']]['parent_rate_name'] ?? '') . ' ';
$derived_str .= ($derived_data['type'] ?? 'percent') == 'absolute' ? $currencysymb . ' ' : '';
$derived_str .= ($derived_data['mode'] ?? 'discount') == 'discount' ? '-' : '+';
$derived_str .= $derived_data['value'] ?? 0;
$derived_str .= ($derived_data['type'] ?? 'percent') == 'percent' ? ' %' : '';
// set derived icon
$derived_icn = '<span class="badge badge-warning"><i class="' . VikBookingIcons::i('link') . '"></i></span> ';
}
?>
<tr class="vbo-roverviewtablerow" id="vbo-roverw-<?php echo $roomrate['id'].'-'.$roomrate['idroom']; ?>">
<td class="vbo-roverv-rplan<?php echo $rplan_minlos || $rplan_haslos ? ' vbo-roverv-rplan-restricted' : ''; ?>" data-defrate="<?php echo $roomrate['cost']; ?>" data-roomname="<?php echo htmlspecialchars($roomrow['name']); ?>" data-room-plan="<?php echo $roomrate['idroom'] . '-' . $roomrate['idprice'] ?>" data-has-derived-rates="<?php echo in_array($roomrate['idprice'], $have_derived_rates) ? '1' : '0'; ?>">
<span class="vbo-rplan-name<?php echo $derived_str ? ' vbo-rplan-is-derived' : ''; ?>" title="<?php echo $this->escape($derived_str); ?>"><?php echo $derived_icn . $roomrate['name']; ?></span>
<?php
if ($rplan_minlos || $rplan_haslos) {
?>
<div class="vbo-roverv-rplan-restrictions<?php echo $rplan_haslos ? ' vbo-roverv-rplan-haslosrates' : ''; ?>">
<?php
if ($rplan_haslos) {
?>
<span class="badge badge-info vbo-roverv-rplan-restrictions-los">LOS</span>
<?php
}
if ($rplan_minlos) {
?>
<span class="vbo-roverv-rplan-restrictions-lbl"><?php echo JText::translate('VBOMINIMUMSTAY'); ?></span>
<span class="vbo-roverv-rplan-restrictions-val"><?php echo $rplan_minlos; ?></span>
<?php
}
?>
</div>
<?php
}
?>
</td>
<?php
while ($cell_count < $MAX_DAYS) {
$style = '';
$dclass = "vbo-roverw-rplan-on";
if (count($closed_roomrateplans) > 0 && array_key_exists($roomrate['idprice'], $closed_roomrateplans) && in_array(date('Y-m-d', $nowts[0]), $closed_roomrateplans[$roomrate['idprice']])) {
$dclass = "vbo-roverw-rplan-off";
}
$id_block = "cell-".$nowts['mday'].'-'.$nowts['mon']."-".$nowts['year']."-".$roomrate['idprice']."-".$roomrate['idroom'];
$dclass .= ' day-block';
$day_key = date('Y-m-d', $nowts[0]);
if ($current_rates_pool[$rid][$day_key][$roomrate['idprice']] ?? []) {
// rates were loaded already
$tars = [$current_rates_pool[$rid][$day_key][$roomrate['idprice']]];
} else {
// load rates
$today_tsin = mktime($pcheckinh, $pcheckinm, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
$today_tsout = mktime($pcheckouth, $pcheckoutm, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
$tars = VikBooking::applySeasonsRoom([$roomrate], $today_tsin, $today_tsout, [], $cached_seasons);
}
// store the OBP overrides for this day and rate plan
if (!empty($tars[0]['occupancy_ovr'])) {
if (!isset($room_obp_overrides[$nowts[0]])) {
$room_obp_overrides[$nowts[0]] = [];
}
$room_obp_overrides[$nowts[0]][] = [
'idprice' => $roomrate['idprice'],
'obp' => $tars[0]['occupancy_ovr'],
];
}
?>
<td align="center" class="<?php echo $dclass.' cell-'.$nowts['mday'].'-'.$nowts['mon']; ?>" id="<?php echo $id_block; ?>" data-vboprice="<?php echo $tars[0]['cost']; ?>" data-vbodate="<?php echo date('Y-m-d', $nowts[0]); ?>" data-vbodateread="<?php echo $days_labels[$nowts['wday']].', '.$months_labels[$nowts['mon']-1].' '.$nowts['mday']; ?>" data-vbospids="<?php echo (array_key_exists('spids', $tars[0]) && count($tars[0]['spids']) > 0 ? implode('-', $tars[0]['spids']) : ''); ?>"<?php echo $style; ?>>
<span class="vbo-rplan-currency"><?php echo $currencysymb; ?></span>
<span class="vbo-rplan-price"><?php echo $tars[0]['cost']; ?></span>
</td>
<?php
$next = $nowts['mday'] + 1;
$dayts = mktime(0, 0, 0, $nowts['mon'], $next, $nowts['year']);
$nowts = getdate($dayts);
$cell_count++;
}
?>
</tr>
<?php
}
// Occupancy Based Pricing rules
$adultsdiff = array_reverse(VikBooking::loadRoomAdultsDiff($roomrow['id']), true);
// display the room OBP rules (must be defined at room-level or no overrides will be displayed)
foreach ($adultsdiff as $adults => $diffusageprice) {
$base_obp_rules = $diffusageprice;
$nowts = getdate($tsstart);
$cell_count = 0;
?>
<tr class="vbo-roverviewtablerow-occupancy">
<td>
<span class="vbo-rplan-name vbo-rplan-name-occ">
<span><?php echo JText::translate('VBPVIEWOPTIONALSTHREE'); ?></span>
<span class="vbo-occ-label"><?php VikBookingIcons::e('male'); ?> x <?php echo $adults ?></span>
</span>
</td>
<?php
while ($cell_count < $MAX_DAYS) {
$style = '';
$dclass = "vbo-roverw-rplan-occ";
// check for OBP overrides
$compare_obp_ovr = [];
if (isset($room_obp_overrides[$nowts[0]]) && count($room_obp_overrides[$nowts[0]]) === count($this->roomrates[$rid])) {
// the OBP overrides affect all room rate plans, make sure the overrides are identical though
$compare_obp_ovr = $room_obp_overrides[$nowts[0]][0]['obp'];
foreach ($room_obp_overrides[$nowts[0]] as $room_obp_override) {
if ($compare_obp_ovr != $room_obp_override['obp']) {
// this OBP override does not match the first one
$compare_obp_ovr = [];
break;
}
}
}
if ($compare_obp_ovr && isset($compare_obp_ovr[$adults])) {
// display the OBP override value for this day
$diffusageprice = $compare_obp_ovr[$adults];
} else {
// display the OBP rules at room-level
$diffusageprice = $base_obp_rules;
}
if (($diffusageprice['value'] - floor($diffusageprice['value'])) <= 0) {
$diffusageprice['value'] = intval($diffusageprice['value']);
}
if ($diffusageprice['chdisc'] == 1) {
// charge
if ($diffusageprice['valpcent'] == 1) {
// fixed value
$occ_diff = '+ ' . $currencysymb . ' ' . $diffusageprice['value'];
} else {
// percentage value
$occ_diff = '+ ' . $diffusageprice['value'] . '%';
}
} else {
// discount
if ($diffusageprice['valpcent'] == 1) {
// fixed value
$occ_diff = '- ' . $currencysymb . ' ' . $diffusageprice['value'];
} else {
// percentage value
$occ_diff = '- ' . $diffusageprice['value'] . '%';
}
}
?>
<td align="center" class="<?php echo $dclass; ?>"<?php echo $style; ?>>
<span class="vbo-roverv-priceoccdiff"><?php echo $occ_diff; ?></span>
</td>
<?php
$next = $nowts['mday'] + 1;
$dayts = mktime(0, 0, 0, $nowts['mon'], $next, $nowts['year']);
$nowts = getdate($dayts);
$cell_count++;
}
?>
</tr>
<?php
}
?>
<tr class="vbo-roverviewtableavrow">
<td><span class="vbo-roverview-roomunits"><?php echo $roomrow['units']; ?></span><span class="vbo-roverview-uleftlbl"><?php echo JText::translate('VBPCHOOSEBUSYCAVAIL'); ?></span></td>
<?php
$nowts = getdate($tsstart);
$cell_count = 0;
$last_booking_info = [];
$last_booking_tag = [];
$room_bookings_pool = [];
while ($cell_count < $MAX_DAYS) {
$style = '';
$is_checkin = false;
$dclass = "vbo-roverw-daynotbusy";
$id_block = "cell-".$nowts['mday'].'-'.$nowts['mon']."-".$nowts['year']."-".$nowts['wday']."-".$rid."-avail";
$prev_day_key = date('Y-m-d', strtotime('-1 day', $nowts[0]));
$cur_day_key = date('Y-m-d', $nowts[0]);
$totfound = 0;
$last_bid_data = [];
$bids_pool = [];
$day_booking_snake = '';
$day_booking_data = [];
foreach (($this->booked_dates[$roomrow['id']] ?? []) as $b) {
$tmpone = getdate($b['checkin']);
$ritts = mktime(0, 0, 0, $tmpone['mon'], $tmpone['mday'], $tmpone['year']);
$tmptwo = getdate($b['checkout']);
$conts = mktime(0, 0, 0, $tmptwo['mon'], $tmptwo['mday'], $tmptwo['year']);
if ($nowts[0] >= $ritts && $nowts[0] < $conts) {
// booking found
$dclass = "vbo-roverw-daybusy";
$last_bid_data = $b;
$totfound++;
// push bid to pool
$bid_str = '-' . $b['idorder'] . '-';
if (!in_array($bid_str, $bids_pool)) {
$bids_pool[] = $bid_str;
}
// push day booking details
if (!isset($room_bookings_pool[$roomrow['id']])) {
$room_bookings_pool[$roomrow['id']] = [];
}
if (!isset($room_bookings_pool[$roomrow['id']][$cur_day_key])) {
$room_bookings_pool[$roomrow['id']][$cur_day_key] = [];
}
if ($roomrow['units'] == 1 && !$b['closure'] && !($b['sharedcal'] ?? 0)) {
// push room day booking
$room_bookings_pool[$roomrow['id']][$cur_day_key][] = $b;
}
if ($nowts[0] == $ritts) {
// turn flag on
$is_checkin = true;
}
}
}
// count units left
$units_remaining = $roomrow['units'] - $totfound;
if ($units_remaining > 0 && $units_remaining < $roomrow['units'] && $roomrow['units'] > 1) {
// room with hotel-like inventory
$dclass .= " vbo-roverw-daybusypartially";
} elseif ($units_remaining <= 0 && $roomrow['units'] <= 1 && $last_bid_data) {
// single-unit listing
// gather the booking color tag data
$btag_style = '';
$binfo = ($last_booking_info['data'] ?? null) && ($last_booking_info['id'] ?? null) == $last_bid_data['idorder'] ? $last_booking_info['data'] : $last_bid_data;
if ($binfo) {
$bcolortag = ($last_booking_tag['data'] ?? null) && ($last_booking_tag['id'] ?? null) == $last_bid_data['idorder'] ? $last_booking_tag['data'] : VikBooking::applyBookingColorTag($binfo);
if ($bcolortag) {
// set values
$bcolortag['name'] = JText::translate($bcolortag['name']);
$btag_style = "background-color: ".$bcolortag['color']."; color: ".(array_key_exists('fontcolor', $bcolortag) ? $bcolortag['fontcolor'] : '#ffffff').";";
$dclass .= ' vbo-roverw-hascolortag';
// cache data to avoid duplicate queries
$last_booking_info = [
'id' => $last_bid_data['idorder'],
'data' => $binfo,
];
$last_booking_tag = [
'id' => $last_bid_data['idorder'],
'data' => $bcolortag,
];
}
}
if (!empty($btag_style)) {
$style = !empty($style) ? ' style="display: none; '.$btag_style.'"' : ' style="'.$btag_style.'"';
$style .= ' title="'.addslashes($bcolortag['name']).'"';
}
/**
* Build room-day-booking snake.
*
* @since 1.17.2 (J) - 1.7.2 (WP)
*/
if ($room_bookings_pool[$roomrow['id']][$cur_day_key][0] ?? []) {
$day_booking_data = $room_bookings_pool[$roomrow['id']][$cur_day_key][0];
}
if ($room_bookings_pool[$roomrow['id']][$prev_day_key][0] ?? []) {
if (!$room_bookings_pool[$roomrow['id']][$prev_day_key][0]['closure'] && date('Y-m-d', $room_bookings_pool[$roomrow['id']][$prev_day_key][0]['checkout']) == $cur_day_key) {
// prepend checkout snake
$day_booking_snake .= '<div class="vbo-tableaux-booking vbo-tableaux-booking-singleunit vbo-tableaux-booking-checkout"><span> </span></div>';
}
}
if ($day_booking_data && !$day_booking_data['closure']) {
// build tableaux-style snake container for guest
$customer_descr = '';
if ($is_checkin) {
// customer details
if (!empty($day_booking_data['first_name']) || !empty($day_booking_data['last_name'])) {
// check if we need to display a profile picture or a channel logo
$booking_avatar_src = null;
$booking_avatar_alt = null;
if (!empty($day_booking_data['pic'])) {
// customer profile picture
$booking_avatar_src = strpos($day_booking_data['pic'], 'http') === 0 ? $day_booking_data['pic'] : VBO_SITE_URI . 'resources/uploads/' . $day_booking_data['pic'];
$booking_avatar_alt = basename($booking_avatar_src);
} elseif (!empty($day_booking_data['idorderota']) && !empty($day_booking_data['channel'])) {
// channel logo
$logo_helper = VikBooking::getVcmChannelsLogo($day_booking_data['channel'], $get_istance = true);
if ($logo_helper !== false) {
$booking_avatar_src = $logo_helper->getSmallLogoURL();
$booking_avatar_alt = $logo_helper->provenience;
}
}
if (!empty($booking_avatar_src)) {
// make sure the alt attribute is not too long in case of broken images
$booking_avatar_alt = !empty($booking_avatar_alt) && strlen($booking_avatar_alt) > 15 ? '...' . substr($booking_avatar_alt, -12) : $booking_avatar_alt;
// append booking avatar image
$customer_descr .= '<span class="vbo-tableaux-booking-avatar"><img src="' . $booking_avatar_src . '" class="vbo-tableaux-booking-avatar-img" ' . (!empty($booking_avatar_alt) ? 'alt="' . htmlspecialchars($booking_avatar_alt) . '" ' : '') . '/></span>';
}
// customer name
$customer_fullname = trim($day_booking_data['first_name'] . ' ' . $day_booking_data['last_name']);
if (strlen($customer_fullname) > 26) {
if (function_exists('mb_substr')) {
$customer_fullname = trim(mb_substr($customer_fullname, 0, 26, 'UTF-8')) . '..';
} else {
$customer_fullname = trim(substr($customer_fullname, 0, 26)) . '..';
}
}
$customer_descr .= '<span class="vbo-tableaux-guest-name">' . $customer_fullname . '</span>';
} else {
// parse the customer data string
$custdata_parts = explode("\n", $day_booking_data['custdata']);
$enoughinfo = false;
if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
// get the first two fields
$custvalues = array();
foreach ($custdata_parts as $custdet) {
if (strlen($custdet) < 1) {
continue;
}
$custdet_parts = explode(':', $custdet);
if (count($custdet_parts) >= 2) {
unset($custdet_parts[0]);
array_push($custvalues, trim(implode(':', $custdet_parts)));
}
if (count($custvalues) > 1) {
break;
}
}
if (count($custvalues) > 1) {
$enoughinfo = true;
$customer_nominative = trim(implode(' ', $custvalues));
if (strlen($customer_nominative) > 26) {
if (function_exists('mb_substr')) {
$customer_nominative = trim(mb_substr($customer_nominative, 0, 26, 'UTF-8')) . '..';
} else {
$customer_nominative = trim(substr($customer_nominative, 0, 26)) . '..';
}
}
if (!empty($day_booking_data['idorderota']) && !empty($day_booking_data['channel'])) {
// add support for the channel logo for the imported OTA reservations with no customer record
$logo_helper = VikBooking::getVcmChannelsLogo($day_booking_data['channel'], $get_istance = true);
if ($logo_helper !== false) {
$booking_avatar_src = $logo_helper->getSmallLogoURL();
$booking_avatar_alt = $logo_helper->provenience;
// make sure the alt attribute is not too long in case of broken images
$booking_avatar_alt = !empty($booking_avatar_alt) && strlen($booking_avatar_alt) > 15 ? '...' . substr($booking_avatar_alt, -12) : $booking_avatar_alt;
// append booking avatar image
$customer_descr .= '<span class="vbo-tableaux-booking-avatar"><img src="' . $booking_avatar_src . '" class="vbo-tableaux-booking-avatar-img" ' . (!empty($booking_avatar_alt) ? 'alt="' . htmlspecialchars($booking_avatar_alt) . '" ' : '') . '/></span>';
}
}
// set customer nominative built
$customer_descr .= '<span class="vbo-tableaux-guest-name">' . $customer_nominative . '</span>';
}
}
if (!$enoughinfo) {
$customer_descr .= '<span class="vbo-tableaux-guest-name">#' . $day_booking_data['idorder'] . '</span>';
}
}
}
// set value
$day_booking_snake .= '<div class="vbo-tableaux-booking vbo-tableaux-booking-singleunit ' . ($is_checkin ? 'vbo-tableaux-booking-checkin' : 'vbo-tableaux-booking-stay') . '"' . ($is_checkin ? ' data-nights="' . $day_booking_data['days'] . '"' : '') . '><span>' . ($is_checkin ? $customer_descr : ' ') . '</span></div>';
}
}
if ($roomrow['units'] <= 1 && !$totfound) {
// no booked records
if ($room_bookings_pool[$roomrow['id']][$prev_day_key][0] ?? []) {
if (!$room_bookings_pool[$roomrow['id']][$prev_day_key][0]['closure'] && date('Y-m-d', $room_bookings_pool[$roomrow['id']][$prev_day_key][0]['checkout']) == $cur_day_key) {
// prepend checkout snake
$day_booking_snake .= '<div class="vbo-tableaux-booking vbo-tableaux-booking-singleunit vbo-tableaux-booking-checkout"><span> </span></div>';
}
}
}
?>
<td align="center" class="vbo-grid-avcell <?php echo $dclass.' cell-'.$nowts['mday'].'-'.$nowts['mon']; ?>" id="<?php echo $id_block; ?>" data-bids="<?php echo implode(',', $bids_pool); ?>" data-vbodateread="<?php echo $days_labels[$nowts['wday']].', '.$months_labels[$nowts['mon']-1].' '.$nowts['mday']; ?>" data-curunits="<?php echo $units_remaining; ?>"<?php echo $style; ?>>
<?php
if (($day_booking_snake ?? '')) {
echo $day_booking_snake;
} else {
?>
<span class="vbo-roverw-curunits"><?php echo $units_remaining; ?></span>
<?php
}
?>
</td>
<?php
$next = $nowts['mday'] + 1;
$dayts = mktime(0, 0, 0, ($nowts['mon'] < 10 ? "0".$nowts['mon'] : $nowts['mon']), ($next < 10 ? "0".$next : $next), $nowts['year']);
$nowts = getdate($dayts);
$cell_count++;
}
?>
</tr>
<?php
// VBO 1.11 - MinLOS restrictions row
?>
<tr class="vbo-roverviewtablerow-restrs">
<td><span class="vbo-roverview-restrs"><?php echo JText::translate('VBOMINIMUMSTAY'); ?></span></td>
<?php
$nowts = getdate($tsstart);
$cell_count = 0;
$glob_minlos = VikBooking::getDefaultNightsCalendar();
$glob_minlos = $glob_minlos < 1 ? 1 : $glob_minlos;
while ($cell_count < $MAX_DAYS) {
$style = '';
$dclass = "vbo-roverw-rplan-restr";
$id_block = "cell-".$nowts['mday'].'-'.$nowts['mon']."-".$nowts['year']."-".$rid."-restr";
$today_tsin = mktime(0, 0, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
$today_tsout = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
$restr = VikBooking::parseSeasonRestrictions($today_tsin, $today_tsout, 1, (isset($this->all_restrictions[$rid]) ? $this->all_restrictions[$rid] : array()));
$minlos = count($restr) ? $restr['minlos'] : $glob_minlos;
?>
<td align="center" class="<?php echo $dclass; ?>" id="<?php echo $id_block; ?>"<?php echo $style; ?>>
<span class="vbo-roverw-curminlos<?php echo $minlos > 1 ? ' vbo-roverw-curminlos-active' : ''; ?>"><?php echo $minlos; ?></span>
</td>
<?php
$next = $nowts['mday'] + 1;
$dayts = mktime(0, 0, 0, ($nowts['mon'] < 10 ? "0".$nowts['mon'] : $nowts['mon']), ($next < 10 ? "0".$next : $next), $nowts['year']);
$nowts = getdate($dayts);
$cell_count++;
}
?>
</tr>
<?php
//
?>
</tbody>
</table>
</div>
<div class="vbo-ratesoverview-period-container" style="<?php echo $collapse_status ? 'display: none;' : ''; ?>">
<div class="vbo-ratesoverview-period-inner">
<div class="vbo-ratesoverview-period-lbl">
<span><?php echo JText::translate('VBOROVWSELPERIOD'); ?></span>
</div>
<div class="vbo-ratesoverview-period-boxes">
<div class="vbo-ratesoverview-period-boxes-inner">
<div class="vbo-ratesoverview-period-box-left">
<div class="vbo-ratesoverview-period-box-lbl">
<span><?php echo JText::translate('VBOROVWSELPERIODFROM'); ?></span>
</div>
<div class="vbo-ratesoverview-period-box-val">
<div class="vbo-ratesoverview-period-from">
<span class="vbo-ratesoverview-period-wday"></span>
<span class="vbo-ratesoverview-period-mday"></span>
<span class="vbo-ratesoverview-period-month"></span>
</div>
<span class="vbo-ratesoverview-period-from-icon"><?php VikBookingIcons::e('calendar'); ?></span>
</div>
</div>
<div class="vbo-ratesoverview-period-box-right">
<div class="vbo-ratesoverview-period-box-lbl">
<span><?php echo JText::translate('VBOROVWSELPERIODTO'); ?></span>
</div>
<div class="vbo-ratesoverview-period-box-val">
<div class="vbo-ratesoverview-period-to">
<span class="vbo-ratesoverview-period-wday"></span>
<span class="vbo-ratesoverview-period-mday"></span>
<span class="vbo-ratesoverview-period-month"></span>
</div>
<span class="vbo-ratesoverview-period-to-icon"><?php VikBookingIcons::e('calendar'); ?></span>
</div>
</div>
</div>
<div class="vbo-ratesoverview-period-box-cals" style="display: none;">
<div class="vbo-ratesoverview-period-box-cals-inner">
<div class="vbo-ratesoverview-period-cal-left">
<h4><?php echo JText::translate('VBOROVWSELPERIODFROM') . ' / ' . JText::translate('VBOROVWSELPERIODTO'); ?></h4>
<div class="vbo-period-from" data-idroom="<?php echo $rid; ?>" data-roomname="<?php echo htmlspecialchars($roomrow['name']); ?>"></div>
<div class="vbo-period-to" data-idroom="<?php echo $rid; ?>" data-roomname="<?php echo htmlspecialchars($roomrow['name']); ?>"></div>
<input type="hidden" class="vbo-period-from-val" value="" />
<input type="hidden" class="vbo-period-to-val" value="" />
</div>
<div class="vbo-ratesoverview-period-cal-cmd">
<h4><?php echo JText::translate('VBOROVWSELRPLAN'); ?></h4>
<div class="vbo-ratesoverview-period-cal-cmd-inner">
<select class="vbo-selperiod-rplanid" onchange="vboUpdateRplan(this);">
<?php
foreach ($this->roomrates[$rid] as $krr => $roomrate) {
?>
<option value="<?php echo $roomrate['idprice']; ?>" data-defrate="<?php echo $roomrate['cost']; ?>"<?php echo $krr < 1 ? ' selected="selected"' : ''; ?>><?php echo $roomrate['name']; ?></option>
<?php
}
?>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="vbo-ratesoverview-orphans-wrapper" id="vbo-ratesoverview-orphans-wrapper-<?php echo $rid; ?>" style="display: none;">
<div class="vbo-ratesoverview-orphans-lbl">
<span><?php echo $vbo_app->createPopover(array('title' => JText::translate('VBORPHANSFOUND'), 'content' => JText::translate('VBORPHANSFOUNDSHELP'), 'icon_class' => VikBookingIcons::i('exclamation-triangle'))); ?> <?php echo JText::translate('VBORPHANSFOUND'); ?></span>
</div>
<div class="vbo-ratesoverview-orphans-list" id="vbo-ratesoverview-orphans-list-<?php echo $rid; ?>"></div>
</div>
</div>
</div>
</div>
<?php
// start los pricing overview IF statement for just 1 room
if (count($this->req_room_ids) < 2) :
?>
<div class="vbo-ratesoverview-lostab-cont"<?php echo (!empty($cookie_tab) && $cookie_tab == 'cal' ? ' style="display: none;"' : ''); ?>>
<?php
if (count($seasons_cal) > 0) {
//Special Prices Timeline
if (isset($seasons_cal['seasons']) && count($seasons_cal['seasons'])) {
?>
<div class="vbo-timeline-container">
<ul id="vbo-timeline">
<?php
foreach ($seasons_cal['seasons'] as $ks => $timeseason) {
$s_val_diff = '';
if ($timeseason['val_pcent'] == 2) {
//percentage
$s_val_diff = (($timeseason['diffcost'] - abs($timeseason['diffcost'])) > 0.00 ? VikBooking::numberFormat($timeseason['diffcost']) : intval($timeseason['diffcost']))." %";
} else {
//absolute
$s_val_diff = $currencysymb.''.VikBooking::numberFormat($timeseason['diffcost']);
}
$s_explanation = array();
if (empty($timeseason['year'])) {
$s_explanation[] = JText::translate('VBSEASONANYYEARS');
}
if (!empty($timeseason['losoverride'])) {
$s_explanation[] = JText::translate('VBSEASONBASEDLOS');
}
?>
<li data-fromts="<?php echo $timeseason['from_ts']; ?>" data-tots="<?php echo $timeseason['to_ts']; ?>">
<input type="radio" name="timeline" class="vbo-timeline-radio" id="vbo-timeline-dot<?php echo $ks; ?>" <?php echo $ks === 0 ? 'checked="checked"' : ''; ?>/>
<div class="vbo-timeline-relative">
<label class="vbo-timeline-label" for="vbo-timeline-dot<?php echo $ks; ?>"><?php echo $timeseason['spname']; ?></label>
<span class="vbo-timeline-date"><?php echo VikBooking::formatSeasonDates($timeseason['from_ts'], $timeseason['to_ts']); ?></span>
<span class="vbo-timeline-circle" onclick="Javascript: jQuery('#vbo-timeline-dot<?php echo $ks; ?>').trigger('click');"></span>
</div>
<div class="vbo-timeline-content">
<p>
<span class="vbo-seasons-calendar-slabel vbo-seasons-calendar-season-<?php echo $timeseason['type'] == 2 ? 'discount' : 'charge'; ?>"><?php echo $timeseason['type'] == 2 ? '-' : '+'; ?> <?php echo $s_val_diff; ?> <?php echo JText::translate('VBSEASONPERNIGHT'); ?></span>
<br/>
<?php
if (count($s_explanation) > 0) {
echo implode(' - ', $s_explanation);
}
?>
</p>
</div>
</li>
<?php
}
?>
</ul>
</div>
<script>
jQuery(function() {
jQuery('.vbo-timeline-container').css('min-height', (jQuery('.vbo-timeline-container').outerHeight() + 20));
});
</script>
<?php
}
//
//Begin Seasons Calendar
?>
<div class="table-responsive">
<table class="table vbo-seasons-calendar-table">
<tr class="vbo-seasons-calendar-nightsrow">
<td> </td>
<?php
foreach ($seasons_cal['offseason'] as $numnights => $ntars) {
?>
<td><span><?php echo JText::sprintf(($numnights > 1 ? 'VBOSEASONCALNUMNIGHTS' : 'VBOSEASONCALNUMNIGHT'), $numnights); ?></span></td>
<?php
}
?>
</tr>
<tr class="vbo-seasons-calendar-offseasonrow">
<td>
<span class="vbo-seasons-calendar-offseasonname"><?php echo JText::translate('VBOSEASONSCALOFFSEASONPRICES'); ?></span>
</td>
<?php
foreach ($seasons_cal['offseason'] as $numnights => $tars) {
?>
<td>
<div class="vbo-seasons-calendar-offseasoncosts">
<?php
foreach ($tars as $tar) {
?>
<div class="vbo-seasons-calendar-offseasoncost">
<?php
if ($price_types_show) {
?>
<span class="vbo-seasons-calendar-pricename"><?php echo $tar['name']; ?></span>
<?php
}
?>
<span class="vbo-seasons-calendar-pricecost">
<span class="vbo_currency"><?php echo $currencysymb; ?></span><span class="vbo_price"><?php echo VikBooking::numberFormat($tar['cost']); ?></span>
</span>
</div>
<?php
if (!$price_types_show) {
break;
}
}
?>
</div>
</td>
<?php
}
?>
</tr>
<?php
if (!isset($seasons_cal['seasons'])) {
$seasons_cal['seasons'] = array();
}
foreach ($seasons_cal['seasons'] as $s_id => $s) {
$restr_diff_nights = array();
if ($los_show && array_key_exists($s_id, $seasons_cal['restrictions'])) {
$restr_diff_nights = VikBooking::compareSeasonRestrictionsNights($seasons_cal['restrictions'][$s_id]);
}
$s_val_diff = '';
if ($s['val_pcent'] == 2) {
//percentage
$s_val_diff = (($s['diffcost'] - abs($s['diffcost'])) > 0.00 ? VikBooking::numberFormat($s['diffcost']) : intval($s['diffcost']))." %";
} else {
//absolute
$s_val_diff = $currencysymb.''.VikBooking::numberFormat($s['diffcost']);
}
?>
<tr class="vbo-seasons-calendar-seasonrow">
<td>
<div class="vbo-seasons-calendar-seasondates">
<span class="vbo-seasons-calendar-seasonfrom"><?php echo date(str_replace("/", $datesep, $df), $s['from_ts']); ?></span>
<span class="vbo-seasons-calendar-seasondates-separe">-</span>
<span class="vbo-seasons-calendar-seasonto"><?php echo date(str_replace("/", $datesep, $df), $s['to_ts']); ?></span>
</div>
<div class="vbo-seasons-calendar-seasonchargedisc">
<span class="vbo-seasons-calendar-slabel vbo-seasons-calendar-season-<?php echo $s['type'] == 2 ? 'discount' : 'charge'; ?>"><span class="vbo-seasons-calendar-operator"><?php echo $s['type'] == 2 ? '-' : '+'; ?></span><?php echo $s_val_diff; ?></span>
</div>
<span class="vbo-seasons-calendar-seasonname"><a href="index.php?option=com_vikbooking&task=editseason&cid[]=<?php echo $s['id']; ?>" target="_blank"><?php echo $s['spname']; ?></a></span>
<?php
if ($los_show && array_key_exists($s_id, $seasons_cal['restrictions']) && count($restr_diff_nights) == 0) {
//Season Restrictions
$season_restrictions = array();
foreach ($seasons_cal['restrictions'][$s_id] as $restr) {
$season_restrictions = $restr;
break;
}
?>
<div class="vbo-seasons-calendar-restrictions">
<?php
if ($season_restrictions['minlos'] > 1) {
?>
<span class="vbo-seasons-calendar-restriction-minlos"><?php echo JText::translate('VBORESTRMINLOS'); ?><span class="vbo-seasons-calendar-restriction-minlos-badge"><?php echo $season_restrictions['minlos']; ?></span></span>
<?php
}
if (array_key_exists('maxlos', $season_restrictions) && $season_restrictions['maxlos'] > 1) {
?>
<span class="vbo-seasons-calendar-restriction-maxlos"><?php echo JText::translate('VBORESTRMAXLOS'); ?><span class="vbo-seasons-calendar-restriction-maxlos-badge"><?php echo $season_restrictions['maxlos']; ?></span></span>
<?php
}
if (array_key_exists('wdays', $season_restrictions) && count($season_restrictions['wdays']) > 0) {
?>
<div class="vbo-seasons-calendar-restriction-wdays">
<label><?php echo JText::translate((count($season_restrictions['wdays']) > 1 ? 'VBORESTRARRIVWDAYS' : 'VBORESTRARRIVWDAY')); ?></label>
<?php
foreach ($season_restrictions['wdays'] as $wday) {
?>
<span class="vbo-seasons-calendar-restriction-wday"><?php echo VikBooking::sayWeekDay($wday); ?></span>
<?php
}
?>
</div>
<?php
} elseif ((array_key_exists('cta', $season_restrictions) && count($season_restrictions['cta']) > 0) || (array_key_exists('ctd', $season_restrictions) && count($season_restrictions['ctd']) > 0)) {
if (array_key_exists('cta', $season_restrictions) && count($season_restrictions['cta']) > 0) {
?>
<div class="vbo-seasons-calendar-restriction-wdays vbo-seasons-calendar-restriction-cta">
<label><?php echo JText::translate('VBORESTRWDAYSCTA'); ?></label>
<?php
foreach ($season_restrictions['cta'] as $wday) {
?>
<span class="vbo-seasons-calendar-restriction-wday"><?php echo VikBooking::sayWeekDay(str_replace('-', '', $wday)); ?></span>
<?php
}
?>
</div>
<?php
}
if (array_key_exists('ctd', $season_restrictions) && count($season_restrictions['ctd']) > 0) {
?>
<div class="vbo-seasons-calendar-restriction-wdays vbo-seasons-calendar-restriction-ctd">
<label><?php echo JText::translate('VBORESTRWDAYSCTD'); ?></label>
<?php
foreach ($season_restrictions['ctd'] as $wday) {
?>
<span class="vbo-seasons-calendar-restriction-wday"><?php echo VikBooking::sayWeekDay(str_replace('-', '', $wday)); ?></span>
<?php
}
?>
</div>
<?php
}
}
?>
</div>
<?php
}
?>
</td>
<?php
if (array_key_exists($s_id, $seasons_cal['season_prices']) && count($seasons_cal['season_prices'][$s_id]) > 0) {
foreach ($seasons_cal['season_prices'][$s_id] as $numnights => $tars) {
$show_day_cost = true;
if ($los_show && array_key_exists($s_id, $seasons_cal['restrictions']) && array_key_exists($numnights, $seasons_cal['restrictions'][$s_id])) {
if ($seasons_cal['restrictions'][$s_id][$numnights]['allowed'] === false) {
$show_day_cost = false;
}
}
?>
<td>
<?php
if ($show_day_cost) {
?>
<div class="vbo-seasons-calendar-seasoncosts">
<?php
foreach ($tars as $tar) {
//print the types of price that are not being modified by this special price with opacity
$not_affected = (!array_key_exists('origdailycost', $tar));
//
?>
<div class="vbo-seasons-calendar-seasoncost<?php echo ($not_affected ? ' vbo-seasons-calendar-seasoncost-notaffected' : ''); ?>">
<?php
if ($price_types_show) {
?>
<span class="vbo-seasons-calendar-pricename"><?php echo $tar['name']; ?></span>
<?php
}
?>
<span class="vbo-seasons-calendar-pricecost">
<span class="vbo_currency"><?php echo $currencysymb; ?></span><span class="vbo_price"><?php echo VikBooking::numberFormat($tar['cost']); ?></span>
</span>
</div>
<?php
if (!$price_types_show) {
break;
}
}
?>
</div>
<?php
} else {
?>
<div class="vbo-seasons-calendar-seasoncosts-disabled"></div>
<?php
}
?>
</td>
<?php
}
}
?>
</tr>
<?php
}
?>
</table>
</div>
<?php
//End Seasons Calendar
} else {
?>
<p class="vbo-warning"><?php echo JText::translate('VBOWARNNORATESROOM'); ?></p>
<?php
}
?>
</div>
<?php
// end los pricing overview IF statement for just 1 room
endif;
}
?>
</div>
<?php
// overlay modal to change rates, restrictions etc..
$vcm_enabled = VikBooking::vcmAutoUpdate();
?>
<div class="vbo-ratesoverview-newratesrestr-helper" style="display: none;">
<div class="vbo-ratesoverview-newratesrestr-wrap">
<div class="vbo-roverw-infoblock">
<span id="rovervw-roomname"></span>
<div class="vbo-roverw-inforates">
<span id="rovervw-rplan"></span>
<span id="rovervw-fromdate"></span> - <span id="rovervw-todate"></span>
</div>
</div>
<div class="vbo-roverw-alldays">
<div class="vbo-roverw-alldays-inner"></div>
</div>
<div class="vbo-roverw-setnewrate">
<div class="vbo-roverw-setnewrate-title">
<h4><?php VikBookingIcons::e('calculator'); ?> <?php echo JText::translate('VBO_RATES_AND_RESTR'); ?></h4>
<div class="vbo-roverw-setnewrate-skip-derived vbo-toggle-small vbo-toggle-mini" style="display: none;">
<label for="roverw-skip-derived-on" class="vbo-roverw-setnewrate-skip-derived-lbl"><?php echo JText::translate('VBO_SKIP_DERIVED_RPLANS'); ?></label>
<?php echo $vbo_app->printYesNoButtons('roverw-skip-derived', JText::translate('VBYES'), JText::translate('VBNO'), 0, 1, 0); ?>
</div>
</div>
<div class="vbo-roverw-flexnew">
<div class="vbo-roverw-newrwrap">
<h4><?php VikBookingIcons::e('edit'); ?> <?php echo JText::translate('VBRATESOVWSETNEWRATE'); ?></h4>
<div class="vbo-roverw-newrcont">
<label for="roverw-newrate" class="vbo-roverw-setnewrate-currency"><?php echo $currencysymb; ?></label>
<input type="number" step="any" min="0" id="roverw-newrate" value="" placeholder="" size="7" />
</div>
</div>
<div class="vbo-roverw-newrestr-wrap" style="display: none;">
<div class="vbo-roverw-newrestrcont">
<h4><?php VikBookingIcons::e('ban'); ?> <?php echo JText::translate('VBOMINIMUMSTAYSET'); ?></h4>
<div class="vbo-roverw-newrestrcont-inner">
<label for="roverw-newrestr" class="vbo-roverw-setnewrestr-lbl"><?php echo JText::translate('VBDAYS'); ?></label>
<input type="number" step="1" min="0" id="roverw-newrestr" value="" size="7" />
</div>
</div>
</div>
</div>
<div class="vbo-roverw-setnewrate-inner">
<div class="vbo-roverw-setnewrate-vcm">
<div class="vbo-roverw-setnewrate-vcm-head">
<span class="<?php echo $vcm_enabled < 0 ? 'vbo-vcm-notinstalled' : 'vbo-vcm-installed'; ?>">
<?php echo $vbo_app->createPopover(array('title' => JText::translate('VBOUPDRATESONCHANNELS'), 'content' => ($vcm_enabled < 0 ? JText::translate('VBCONFIGVCMAUTOUPDMISS') : JText::translate('VBOUPDRATESONCHANNELSHELP')), 'icon_class' => VikBookingIcons::i('rocket'))); ?>
<?php echo JText::translate('VBOUPDRATESONCHANNELS'); ?>
</span>
</div>
<div class="vbo-roverw-setnewrate-vcm-body vbo-toggle-small">
<?php
echo $vbo_app->printYesNoButtons('roverw-newrate-vcm', JText::translate('VBYES'), JText::translate('VBNO'), ($vcm_enabled > 0 ? 1 : 0), 1, 0, 'vboCheckVcmRestrictions();', ['blue']);
if ($vcm_enabled < 0) {
// disable the toggle button when VCM is not available
?>
<script type="text/javascript">
jQuery(function() {
jQuery('input[name="roverw-newrate-vcm"]').prop('disabled', true);
});
</script>
<?php
}
?>
</div>
<div class="vbo-roverw-setnewrate-vcm-otas"></div>
</div>
</div>
</div>
<div class="vbo-roverw-closeopenrp">
<h4><i class="vboicn-switch"></i><?php echo JText::translate('VBRATESOVWCLOSEOPENRRP'); ?> <span id="rovervw-closeopen-rplan"></span> <span class="vbo-roverw-closeopenrp-arrow"><?php VikBookingIcons::e('chevron-down'); ?></span></h4>
<div class="vbo-roverw-closeopenrp-btns">
<button type="button" class="btn btn-danger" onclick="modRoomRatePlan('close');"><?php VikBookingIcons::e('lock'); ?> <?php echo JText::translate('VBRATESOVWCLOSERRP'); ?></button>
<button type="button" class="btn btn-success" onclick="modRoomRatePlan('open');"><?php VikBookingIcons::e('lock-open'); ?> <?php echo JText::translate('VBRATESOVWOPENRRP'); ?></button>
</div>
</div>
</div>
<div class="vbo-roverw-setnewrate-vcm-ota-pricing-alteration">
<div class="vbo-roverw-setnewrate-vcm-ota-alteration-elem">
<select data-alter-rule="rmodsop">
<option value="1">+</option>
<option value="0">-</option>
</select>
</div>
<div class="vbo-roverw-setnewrate-vcm-ota-alteration-elem">
<input type="number" value="" step="any" min="0" data-alter-rule="rmodsamount" />
</div>
<div class="vbo-roverw-setnewrate-vcm-ota-alteration-elem">
<select data-alter-rule="rmodsval">
<option value="1">%</option>
<option value="0"><?php echo $currencysymb; ?></option>
</select>
</div>
</div>
</div>
<form name="adminForm" id="adminForm" action="index.php" method="post">
<input type="hidden" name="task" value="">
<input type="hidden" name="option" value="com_vikbooking">
</form>
<a id="vbo-base-booknow-link" style="display: none;" href="index.php?option=com_vikbooking&task=calendar&cid[]=&checkin=&checkout=&adults=&children=&idprice=&booknow=1"></a>
<a class="vbo-basenavuri-details" href="index.php?option=com_vikbooking&task=editorder&goto=ratesoverv&cid[]=%d" style="display: none;"></a>
<script type="text/Javascript">
function vboFormatCalDate(elem, idc) {
var vb_period = elem.parent().find('.vbo-'+idc+'-val').val();
if (!vb_period || !vb_period.length) {
return false;
}
var vb_period_parts = vb_period.split("/");
if ('%d/%m/%Y' == '<?php echo $vbo_df; ?>') {
var period_date = new Date(vb_period_parts[2], (parseInt(vb_period_parts[1]) - 1), parseInt(vb_period_parts[0], 10), 0, 0, 0, 0);
var data = [parseInt(vb_period_parts[0], 10), parseInt(vb_period_parts[1]), vb_period_parts[2]];
} else if ('%m/%d/%Y' == '<?php echo $vbo_df; ?>') {
var period_date = new Date(vb_period_parts[2], (parseInt(vb_period_parts[0]) - 1), parseInt(vb_period_parts[1], 10), 0, 0, 0, 0);
var data = [parseInt(vb_period_parts[1], 10), parseInt(vb_period_parts[0]), vb_period_parts[2]];
} else {
var period_date = new Date(vb_period_parts[0], (parseInt(vb_period_parts[1]) - 1), parseInt(vb_period_parts[2], 10), 0, 0, 0, 0);
var data = [parseInt(vb_period_parts[2], 10), parseInt(vb_period_parts[1]), vb_period_parts[0]];
}
var elcont = elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-ratesoverview-'+idc);
elcont.find('.vbo-ratesoverview-period-wday').text(vboMapWdays[period_date.getDay()]);
elcont.find('.vbo-ratesoverview-period-mday').text(period_date.getDate());
elcont.find('.vbo-ratesoverview-period-month').text(vboMapMons[period_date.getMonth()]);
elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-ratesoverview-'+idc+'-icon').hide();
data.push(elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-selperiod-rplanid').val());
data.push(elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-selperiod-rplanid option:selected').text());
data.push(elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-selperiod-rplanid option:selected').attr('data-defrate'));
data.push(elem.attr('data-idroom'));
data.push(elem.attr('data-roomname'));
var struct = getPeriodStructure(data);
if (idc.indexOf('from') >= 0) {
//period from date selected
if (!vbolistener.pickFirst(struct)) {
//first already picked: update it
vbolistener.first = struct;
}
}
if (idc.indexOf('to') >= 0) {
//period to date selected
if (!vbolistener.pickFirst(struct)) {
//first already picked
if ((vbolistener.first.isBeforeThan(struct) || vbolistener.first.isSameDay(struct)) && vbolistener.first.isSameRplan(struct) && vbolistener.first.isSameRoom(struct)) {
//last > first: pick last
if (vbolistener.pickLast(struct)) {
showVboDialogPeriod();
}
}
}
}
}
function vbCalcNights() {
var vbcheckin = document.getElementById('checkindate').value;
var vbcheckout = document.getElementById('checkoutdate').value;
if (!vbcheckin.length || !vbcheckout.length) {
return;
}
var vbcheckinp = vbcheckin.split("-");
var vbcheckoutp = vbcheckout.split("-");
var vbinmonth = parseInt(vbcheckinp[1]);
vbinmonth = vbinmonth - 1;
var vbinday = parseInt(vbcheckinp[2], 10);
var vbcheckind = new Date(vbcheckinp[0], vbinmonth, vbinday);
var vboutmonth = parseInt(vbcheckoutp[1]);
vboutmonth = vboutmonth - 1;
var vboutday = parseInt(vbcheckoutp[2], 10);
var vbcheckoutd = new Date(vbcheckoutp[0], vboutmonth, vboutday);
var vbdivider = 1000 * 60 * 60 * 24;
var vbints = vbcheckind.getTime();
var vboutts = vbcheckoutd.getTime();
if (vboutts > vbints) {
var utc1 = Date.UTC(vbcheckind.getFullYear(), vbcheckind.getMonth(), vbcheckind.getDate());
var utc2 = Date.UTC(vbcheckoutd.getFullYear(), vbcheckoutd.getMonth(), vbcheckoutd.getDate());
var vbnights = Math.ceil((utc2 - utc1) / vbdivider);
if (vbnights > 0) {
jQuery('#vbo-numnights').val(vbnights);
}
}
}
/**
* Scrollable tables will show the arrows to navigate to the next N days.
*
* @since 1.15.0 (J) - 1.5.0 (WP)
*/
function vboDisplayNextDays(btn) {
var cell = jQuery(btn).closest('.vbo-roverv-gonext-cell');
if (!cell || !cell.length) {
return;
}
var rid = cell.attr('data-rid');
if (!rid || !rid.length) {
return;
}
var table = jQuery('table.vbratesoverviewtable[data-idroom="' + rid + '"]');
if (!table || !table.length) {
return;
}
// get the datepicker calendar instance for this room
var calendar = table.find('input.vbodatepicker');
try {
// calculate the new date
var cur_date = calendar.datepicker('getDate');
var dobj = new Date(cur_date);
dobj.setDate(dobj.getDate() + <?php echo $MAX_DAYS; ?>);
// set the new date
calendar.datepicker('setDate', dobj);
// populate hidden form fields
var parentform = calendar.closest('form');
var roomsids = jQuery('#roomsel').val();
if (roomsids) {
if (!Array.isArray(roomsids)) {
// if there is just one room type, the select is not multiple, so this is a string
roomsids = [jQuery('#roomsel').val()];
}
jQuery.each(roomsids, function(k, v) {
parentform.append('<input type="hidden" name="cid[]" value="' + v + '" />');
});
}
// auto-submit form with new date
parentform.submit();
} catch(e) {
console.error(e);
alert('Calendar not found. Please change date manually.');
}
}
jQuery(function() {
/**
* Calendar for start date of every room-rates table.
*/
jQuery('.vbodatepicker').datepicker({
showOn: 'focus',
dateFormat: '<?php echo $juidf; ?>',
minDate: '-1y',
numberOfMonths: 1,
changeMonth: true,
changeYear: true,
yearRange: '<?php echo (date('Y') - 1).':'.(date('Y') + 3); ?>',
onSelect: function(selectedDate) {
var parentform = jQuery(this).closest('form');
var roomsids = jQuery('#roomsel').val();
if (roomsids) {
if (!Array.isArray(roomsids)) {
// if there is just one room type, the select is not multiple, so this is a string
roomsids = [jQuery('#roomsel').val()];
}
jQuery.each(roomsids, function(k, v) {
parentform.append('<input type="hidden" name="cid[]" value="' + v + '" />');
});
}
parentform.submit();
}
});
/**
* Disable keyboard on regular datepicker input fields.
*/
jQuery('.vbodatepicker').on('focus', function() {
jQuery(this).blur();
});
/**
* Dates-Range-Picker calendar for Rates Calculator tool.
*/
jQuery('#checkindate').vboDatesRangePicker({
checkout: '#checkoutdate',
showOn: 'focus',
dateFormat: 'yy-mm-dd',
minDate: '0d',
numberOfMonths: <?php echo $is_mobile ? 1 : 2; ?>,
onSelect: {
checkin: (selectedDate) => {
var nownights = parseInt(jQuery('#vbo-numnights').val());
var nowcheckin = jQuery('#checkindate').vboDatesRangePicker('getCheckinDate');
var nowcheckindate = new Date(nowcheckin.getTime());
nowcheckindate.setDate(nowcheckindate.getDate() + nownights);
jQuery('#checkindate').vboDatesRangePicker('checkout', 'minDate', nowcheckindate);
vbCalcNights();
},
checkout: (selectedDate) => {
if (!jQuery('#checkindate').vboDatesRangePicker('getCheckoutDate')) {
return;
}
vbCalcNights();
},
},
labels: {
checkin: Joomla.JText._('VBPICKUPROOM'),
checkout: Joomla.JText._('VBRETURNROOM'),
},
bottomCommands: {
clear: Joomla.JText._('VBO_CLEAR_DATES'),
close: Joomla.JText._('VBO_CLOSE'),
onClear: () => {
vbCalcNights();
},
},
environment: {
section: 'admin',
autoHide: true,
},
});
jQuery('#checkindate-trig, #checkoutdate-trig').click(function() {
let dp = jQuery(this).prev('input');
if (!dp.length) {
return;
}
if (dp.hasClass('hasDatepicker')) {
dp.focus();
} else if (dp.attr('id') == 'checkoutdate') {
jQuery('#checkindate').focus();
}
});
jQuery('#vbo-numnights').on('change keyup', function() {
if (!jQuery('#checkindate').vboDatesRangePicker('getCheckinDate')) {
return;
}
var nownights = parseInt(jQuery(this).val());
var nowcheckin = jQuery('#checkindate').vboDatesRangePicker('getCheckinDate');
var nowcheckindate = new Date(nowcheckin.getTime());
nowcheckindate.setDate(nowcheckindate.getDate() + nownights);
// update checkout date
jQuery('#checkindate').vboDatesRangePicker('setCheckoutDate', nowcheckindate);
});
/**
* Dates-Range-Picker calendar for selecting a period of room dates.
*/
jQuery('.vbo-period-from').each(function(index, elem) {
jQuery(elem).vboDatesRangePicker({
checkout: jQuery(elem).closest('.vbo-ratesoverview-period-box-cals').find('.vbo-period-to'),
dateFormat: '<?php echo $juidf; ?>',
numberOfMonths: 1,
minDate: '0d',
altFields: {
checkin: '.vbo-period-from-val',
checkout: '.vbo-period-to-val',
},
onSelect: {
checkin: function(selectedDate) {
jQuery(this).parent().find('.vbo-period-from-val').val(selectedDate);
vboFormatCalDate(jQuery(this), 'period-from');
},
checkout: function(selectedDate) {
jQuery(this).parent().find('.vbo-period-to-val').val(selectedDate);
vboFormatCalDate(jQuery(this), 'period-to');
},
},
labels: {
checkin: Joomla.JText._('VBNEWRESTRICTIONDFROMRANGE'),
checkout: Joomla.JText._('VBNEWRESTRICTIONDTORANGE'),
},
environment: {
section: 'admin',
},
});
});
jQuery('.vbo-ratesoverview-period-box-left, .vbo-ratesoverview-period-box-right').click(function() {
let calbox = jQuery(this).closest('.vbo-ratesoverview-period-boxes').find('.vbo-ratesoverview-period-box-cals');
if (!calbox.is(':visible')) {
// unset current dates from DRP, if any
calbox.find('.vbo-period-from').vboDatesRangePicker('setDates', []);
}
calbox.toggle();
});
/**
* Render select2.
*/
jQuery("#roomsel").select2({
allowClear: true,
templateResult: (element) => {
if (typeof vboListingsMiniThumbnails !== 'undefined' && vboListingsMiniThumbnails.hasOwnProperty((element.id || 0))) {
return jQuery('<span class="vbo-sel2-element-img"><img src="' + vboListingsMiniThumbnails[element.id] + '" /> <span>' + element.text + '</span></span>');
} else {
return element.text;
}
},
});
jQuery("#roomselcalc").select2({
templateResult: (element) => {
if (typeof vboListingsMiniThumbnails !== 'undefined' && vboListingsMiniThumbnails.hasOwnProperty((element.id || 0))) {
return jQuery('<span class="vbo-sel2-element-img"><img src="' + vboListingsMiniThumbnails[element.id] + '" /> <span>' + element.text + '</span></span>');
} else {
return element.text;
}
},
});
});
<?php
if ($df == "Y/m/d") {
?>
Date.prototype.format = "yy/mm/dd";
<?php
} elseif ($df == "m/d/Y") {
?>
Date.prototype.format = "mm/dd/yy";
<?php
} else {
?>
Date.prototype.format = "dd/mm/yy";
<?php
}
?>
Date.prototype.datesep = "<?php echo addslashes(VikBooking::getDateSeparator()); ?>";
var currencysymb = '<?php echo $currencysymb; ?>';
var debug_mode = '<?php echo $pdebug; ?>';
var vcm_exists = <?php echo VikBooking::vcmAutoUpdate(); ?>;
var roverw_messages = {
"setNewRatesMissing": "<?php echo addslashes(JText::translate('VBRATESOVWERRNEWRATE')); ?>",
"modRplansMissing": "<?php echo addslashes(JText::translate('VBRATESOVWERRMODRPLANS')); ?>",
"openSpLink": "<?php echo addslashes(JText::translate('VBRATESOVWOPENSPL')); ?>",
"vcmRatesChanged": "<?php echo addslashes(JText::translate('VBRATESOVWVCMRCHANGED')); ?>",
"vcmRatesChangedOpen": "<?php echo addslashes(JText::translate('VBRATESOVWVCMRCHANGEDOPEN')); ?>",
"notesForRoom": "<?php echo addslashes(JText::translate('VBONOTESFORROOM')); ?>"
};
var vboFests = <?php echo json_encode($this->festivities); ?>;
var vboRdayNotes = <?php echo json_encode($this->rdaynotes); ?>;
</script>
<script type="text/Javascript">
/**
* Open a booking in a new tab.
*/
function vboRovervOpenBooking(bid) {
var open_url = jQuery('.vbo-basenavuri-details').attr('href');
open_url = open_url.replace('%d', bid);
// navigate in a new tab
window.open(open_url, '_blank');
}
/* Labels for months and weekdays */
var vbowdays = <?php echo json_encode($long_days_labels); ?>;
var vbomonths = <?php echo json_encode($long_months_labels); ?>;
/* Dates selection - Start */
var vbolistener = null;
jQuery(function() {
// fests
jQuery(document.body).on("click", "td.bluedays", function() {
if (jQuery(this).hasClass('skip-bluedays-click')) {
return;
}
var ymd = jQuery(this).attr('data-ymd');
var daytitle = jQuery(this).attr('data-readymd');
if (jQuery(this).hasClass('vbo-roverv-festcell')) {
// cell has fests
if (!vboFests.hasOwnProperty(ymd)) {
return;
}
vboRenderFests(ymd, daytitle);
} else {
// let the admin create a new fest
// define the modal buttons
let cancel_btn = jQuery('<button></button>')
.attr('type', 'button')
.addClass('btn')
.text(Joomla.JText._('VBANNULLA'))
.on('click', function() {
VBOCore.emitEvent('vbo-dismiss-modal-roverv-fests');
});
let save_btn = jQuery('<button></button>')
.attr('type', 'button')
.addClass('btn btn-success')
.text(Joomla.JText._('VBSAVE'))
.on('click', function() {
vboAddFest();
});
let modal_body = VBOCore.displayModal({
suffix: 'ratesoverv-fests',
extra_class: 'vbo-modal-rounded vbo-modal-tall',
title: '<?php VikBookingIcons::e('star'); ?> ' + daytitle,
footer_left: cancel_btn,
footer_right: save_btn,
dismiss_event: 'vbo-dismiss-modal-roverv-fests',
onDismiss: () => {
jQuery('.vbo-ratesoverview-fests-wrap').appendTo('.vbo-ratesoverview-fests-helper');
},
});
// update ymd key for the selected date, useful for adding new fests
jQuery('.vbo-overlay-fests-addnew').attr('data-ymd', ymd);
// unset content and display modal for just adding a new fest
jQuery('.vbo-overlay-fests-list').html('');
jQuery('.vbo-ratesoverview-fests-wrap').appendTo(modal_body);
}
if (jQuery(this).hasClass('vbo-roverw-roomdaynote-full')) {
// display the room-day notes
vboRenderRdayNotes(ymd, jQuery(this).attr('data-rid'));
}
});
// calendar-day selection listener
vbolistener = new CalendarListener();
jQuery('.day-block').click(function() {
pickBlock(jQuery(this).attr('id'));
});
jQuery('.day-block').hover(
function() {
if (vbolistener.isFirstPicked() && !vbolistener.isLastPicked()) {
var struct = initBlockStructure(jQuery(this).attr('id'));
var all_blocks = getAllBlocksBetween(vbolistener.first, struct, false);
if (all_blocks !== false) {
jQuery.each(all_blocks, function(k, v) {
if (!v.hasClass('block-picked-middle')) {
v.addClass('block-picked-middle');
}
});
jQuery(this).addClass('block-picked-end');
}
}
},
function() {
if (!vbolistener.isLastPicked()) {
jQuery('.day-block').removeClass('block-picked-middle block-picked-end');
}
}
);
jQuery("body").on("click", ".vbo-roverw-daymod-infospids", function() {
if (jQuery(this).hasClass('vbo-roverw-daymod-infospids-on')) {
// dismiss modal
VBOCore.emitEvent('vbo-ratesoverview-spids-details-dismiss');
} else {
// show modal
let spids_modal = VBOCore.displayModal({
suffix: 'vbo-ratesoverview-spids',
extra_class: 'vbo-modal-rounded vbo-modal-dialog vbo-modal-nofooter',
title: jQuery(this).attr('data-dt'),
dismiss_event: 'vbo-ratesoverview-spids-details-dismiss',
});
let spids_info = jQuery(this).next('.vbo-roverw-daymod-infospids-outcont').find('.vbo-roverw-daymod-infospids-incont').clone();
spids_info.appendTo(spids_modal);
}
});
jQuery('.vbo-roverw-closeopenrp h4').click(function() {
jQuery('.vbo-roverw-closeopenrp-btns').fadeToggle(400, function() {
if (jQuery(this).is(':visible')) {
jQuery('.vbo-roverw-closeopenrp-arrow').html('<?php VikBookingIcons::e('chevron-up'); ?>');
} else {
jQuery('.vbo-roverw-closeopenrp-arrow').html('<?php VikBookingIcons::e('chevron-down'); ?>');
}
});
});
jQuery(document.body).on('click', '.vbo-ratesoverview-vcmwarn-close', function() {
vcm_exists = 0;
jQuery('.vbo-ratesoverview-right-inner').hide().html('');
});
// show booking details
jQuery('.vbo-roverw-daybusy[data-bids]').click(function() {
var date_bids = jQuery(this).attr('data-bids');
if (!date_bids || !date_bids.length) {
return;
}
// get room name, date and day-bids
var rid = jQuery(this).closest('table').attr('data-idroom');
var room_name = jQuery('.vbo-ratesoverview-roomname[data-idroom="' + rid + '"]').text();
var date_read = jQuery(this).attr('data-vbodateread');
var def_bicon = '<?php VikBookingIcons::e('user', 'vbo-dashboard-guest-activity-avatar-icon'); ?>';
var closure_i = '<?php VikBookingIcons::e('ban', 'vbo-dashboard-guest-activity-avatar-icon'); ?>';
// display modal with booking details
var rday_bookings_modal_body = VBOCore.displayModal({
suffix: 'overv-rdaybookings',
extra_class: 'vbo-modal-rounded vbo-modal-tall',
title: room_name + ' - ' + date_read,
dismiss_event: 'vbo-dismiss-modal-roverv-rdaybookings',
loading_event: 'vbo-loading-modal-roverv-rdaybookings',
loading_body: '<?php VikBookingIcons::e('circle-notch', 'fa-spin fa-fw'); ?>',
});
// show loading
VBOCore.emitMultitaskEvent('vbo-loading-modal-roverv-rdaybookings');
// make the request to get the bookings information
VBOCore.doAjax(
"<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=getbookingsinfo'); ?>",
{
status: 'any',
idorders: date_bids,
tmpl: 'component'
},
(res) => {
// stop loading
VBOCore.emitMultitaskEvent('vbo-loading-modal-roverv-rdaybookings');
try {
var obj_res = typeof res === 'string' ? JSON.parse(res) : res;
// build the HTML response
var rday_bookings_html = '';
rday_bookings_html += '<div class="vbo-dashboard-guests-latest">' + "\n";
rday_bookings_html += ' <div class="vbo-dashboard-guest-messages-list">' + "\n";
for (var b in obj_res) {
if (!obj_res.hasOwnProperty(b)) {
continue;
}
// nights and guests
var nights_guests = [
obj_res[b]['roomsnum'] + ' ' + Joomla.JText._((obj_res[b]['roomsnum'] > 1 ? 'VBPVIEWORDERSTHREE' : 'VBEDITORDERTHREE')),
obj_res[b]['days'] + ' ' + Joomla.JText._((obj_res[b]['days'] > 1 ? 'VBDAYS' : 'VBDAY')),
obj_res[b]['tot_adults'] + ' ' + Joomla.JText._((obj_res[b]['tot_adults'] > 1 ? 'VBMAILADULTS' : 'VBMAILADULT'))
];
if (obj_res[b]['tot_children'] > 0) {
nights_guests.push(obj_res[b]['tot_children'] + ' ' + Joomla.JText._((obj_res[b]['tot_children'] > 1 ? 'VBMAILCHILDREN' : 'VBMAILCHILD')));
}
// build booking structure
rday_bookings_html += ' <div class="vbo-dashboard-guest-activity vbo-w-guestmessages-message" data-idorder="' + obj_res[b]['id'] + '" onclick="vboRovervOpenBooking(\'' + obj_res[b]['id'] + '\');">' + "\n";
rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-avatar">' + "\n";
if (obj_res[b]['avatar_src']) {
rday_bookings_html += '<img class="vbo-dashboard-guest-activity-avatar-profile" src="' + obj_res[b]['avatar_src'] + '" alt="' + obj_res[b]['avatar_alt'] + '" />' + "\n";
} else if (obj_res[b]['closure']) {
rday_bookings_html += closure_i + "\n";
} else {
rday_bookings_html += def_bicon + "\n";
}
rday_bookings_html += ' </div>' + "\n";
rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content">' + "\n";
rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-head">' + "\n";
rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-info-details">' + "\n";
rday_bookings_html += ' <h4 class="vbo-w-guestmessages-message-gtitle">' + (!obj_res[b]['closure'] ? obj_res[b]['cinfo'] : obj_res[b]['closure_txt']) + '</h4>' + "\n";
rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-info-icon">' + "\n";
rday_bookings_html += ' <span class="badge badge-info">' + obj_res[b]['id'] + '</span> ' + "\n";
rday_bookings_html += ' <span class="badge badge-' + (obj_res[b]['status'] == 'confirmed' ? 'success' : 'warning') + '">' + obj_res[b]['status_lbl'] + '</span>' + "\n";
rday_bookings_html += ' <span class="vbo-w-guestmessages-message-staydates">' + "\n";
rday_bookings_html += ' <?php VikBookingIcons::e('calendar-alt'); ?>' + "\n";
rday_bookings_html += ' <span class="vbo-w-guestmessages-message-staydates-in">' + obj_res[b]['checkin_short'] + '</span>' + "\n";
rday_bookings_html += ' <span class="vbo-w-guestmessages-message-staydates-sep">-</span>' + "\n";
rday_bookings_html += ' <span class="vbo-w-guestmessages-message-staydates-out">' + obj_res[b]['checkout_short'] + '</span>' + "\n";
rday_bookings_html += ' </span>' + "\n";
rday_bookings_html += ' </div>' + "\n";
rday_bookings_html += ' </div>' + "\n";
rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-info-date">' + "\n";
rday_bookings_html += ' <span>' + obj_res[b]['book_date'] + '</span>' + "\n";
rday_bookings_html += ' <span>' + obj_res[b]['book_time'] + '</span>' + "\n";
rday_bookings_html += ' </div>' + "\n";
rday_bookings_html += ' </div>' + "\n";
rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-info-msg">' + "\n";
rday_bookings_html += ' <div><?php VikBookingIcons::e('bed'); ?> ' + nights_guests.join(', ') + '</div>' + "\n";
if (obj_res[b].hasOwnProperty('sub_units_data')) {
rday_bookings_html += ' <div class="vbo-rdaybooking-subunits">' + "\n";
for (let sub_rname in obj_res[b]['sub_units_data']) {
if (!obj_res[b]['sub_units_data'].hasOwnProperty(sub_rname)) {
continue;
}
rday_bookings_html += '<span class="label label-success">' + (obj_res[b]['roomsnum'] > 1 ? sub_rname + ' ' : '') + '#' + obj_res[b]['sub_units_data'][sub_rname] + '</span>' + "\n";
}
rday_bookings_html += ' </div>' + "\n";
}
rday_bookings_html += ' </div>' + "\n";
rday_bookings_html += ' </div>' + "\n";
rday_bookings_html += ' </div>' + "\n";
}
rday_bookings_html += ' </div>' + "\n";
rday_bookings_html += '</div>' + "\n";
// append the response
rday_bookings_modal_body.html(rday_bookings_html);
} catch(err) {
console.error('could not parse JSON response', err, res);
alert('Could not parse JSON response');
}
},
(err) => {
// stop loading and display alert message
VBOCore.emitMultitaskEvent('vbo-loading-modal-roverv-rdaybookings');
console.error(err);
alert(err.responseText);
}
);
});
// register listener for the "input" event on the "set new rate" input field of type number
document.querySelector('#roverw-newrate').addEventListener('input', VBOCore.debounceEvent((e) => {
// dispatch the event to calculate the new OTA pricing value
VBOCore.emitEvent('vbo-roverv-setnewrate-calc-ota-pricing', {rate: e.target.value});
}, 200));
// register listener for when a new rate is set to update what will be the OTA pricing value
document.addEventListener('vbo-roverv-setnewrate-calc-ota-pricing', VBOCore.debounceEvent((e) => {
if (!e || !e.detail || !e.detail.rate) {
// invalid event data
return;
}
// get the new PMS rate
let rate_amount = parseFloat(e.detail.rate);
// access the currency object
let currencyObj = VBOCore.getCurrency({
symbol: vbo_currency_symbol,
digits: vbo_currency_digits,
decimals: vbo_currency_decimals,
thousands: vbo_currency_thousands,
noDecimals: 1,
});
// scan all OTA alteration rules, if any
document.querySelectorAll('.vbo-roverw-setnewrate-ota-pricing-currentvalue[data-alteration]').forEach((elem) => {
// channel alteration string
let alter_string = elem.getAttribute('data-alteration');
if (!alter_string) {
alter_string = '+0%';
}
// default alteration factors (no pricing alteration rules)
let alter_op = alter_string.substr(0, 1);
let alter_val = alter_string.substr(-1, 1);
let alter_amount = parseFloat(alter_string.replace(alter_op, '').replace(alter_val, ''));
// calculate what the rate will be on the OTA
let ota_rate_amount = rate_amount;
if (!isNaN(alter_amount) && Math.abs(alter_amount) > 0) {
if (alter_op == '+') {
// increase rate
if (alter_val == '%') {
// percent
let amount_inc = currencyObj.multiply(alter_amount, 0.01);
amount_inc = currencyObj.multiply(rate_amount, amount_inc);
ota_rate_amount = currencyObj.sum(rate_amount, amount_inc);
} else {
// absolute
ota_rate_amount = currencyObj.sum(rate_amount, alter_amount);
}
} else {
// discount rate
if (alter_val == '%') {
// percent
let amount_inc = currencyObj.multiply(alter_amount, 0.01);
amount_inc = currencyObj.multiply(rate_amount, amount_inc);
ota_rate_amount = currencyObj.diff(rate_amount, amount_inc);
} else {
// absolute
ota_rate_amount = currencyObj.diff(rate_amount, alter_amount);
}
}
}
// get the element containing the calculated ota pricing
let will_alter_elem = elem
.closest('.vbo-roverw-setnewrate-vcm-ota-pricing-startvalue')
.querySelector('.vbo-roverw-setnewrate-ota-pricing-willvalue');
// define the currency options
let ota_currency_options = {};
// check if the channel requires a specific currency
let ota_currency_data = will_alter_elem.getAttribute('data-currency');
if (ota_currency_data) {
// decode currency data instructions
try {
ota_currency_data = JSON.parse(ota_currency_data);
} catch (e) {
ota_currency_data = {};
}
// set custom currency options
if (ota_currency_data['symbol']) {
ota_currency_options['symbol'] = ota_currency_data['symbol'];
}
if (ota_currency_data['decimals']) {
ota_currency_options['digits'] = ota_currency_data['decimals'];
}
if (ota_currency_data['decimals_sep']) {
ota_currency_options['decimals'] = ota_currency_data['decimals_sep'];
}
if (ota_currency_data['thousands_sep']) {
ota_currency_options['thousands'] = ota_currency_data['thousands_sep'];
}
}
// set calculated OTA rate value
will_alter_elem.innerHTML = currencyObj.format(ota_rate_amount, ota_currency_options);
});
}, 200));
});
/**
* Room-day notes
*/
function vboRenderRdayNotes(day, rid) {
// compose room-day notes information (no sub-units)
var notes_html = '';
var keyid = day + '_' + rid + '_0';
if (vboRdayNotes.hasOwnProperty(keyid) && vboRdayNotes[keyid]['info'] && vboRdayNotes[keyid]['info'].length) {
for (var i = 0; i < vboRdayNotes[keyid]['info'].length; i++) {
var note_data = vboRdayNotes[keyid]['info'][i];
notes_html += '<div class="vbo-overlay-fest-details vbo-roverv-roomdaynotes-note-details">';
notes_html += ' <div class="vbo-fest-info vbo-roverv-roomdaynotes-note-info">';
notes_html += ' <div class="vbo-fest-name vbo-roverv-roomdaynotes-note-name">' + note_data['name'] + '</div>';
notes_html += ' <div class="vbo-fest-desc vbo-roverv-roomdaynotes-note-desc">' + note_data['descr'].replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br />' + '$2') + '</div>';
notes_html += ' </div>';
notes_html += '</div>';
}
}
// append room-day notes to the list of festivities
if (notes_html.length) {
notes_html = '<h4 class="vbo-roverw-roomdaynotes-title">' + roverw_messages.notesForRoom + '</h4>' + notes_html;
jQuery('.vbo-overlay-fests-list').append(notes_html);
}
}
/**
* Fests
*/
function vboRenderFests(day, daytitle) {
// compose fests information
let fests_html = '';
if (vboFests[day] && vboFests[day]['festinfo'] && vboFests[day]['festinfo'].length) {
for (var i = 0; i < vboFests[day]['festinfo'].length; i++) {
let fest = vboFests[day]['festinfo'][i];
fests_html += '<div class="vbo-overlay-fest-details">';
fests_html += ' <div class="vbo-fest-info">';
fests_html += ' <div class="vbo-fest-name">' + fest['trans_name'] + '</div>';
fests_html += ' <div class="vbo-fest-desc">' + fest['descr'].replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br />' + '$2') + '</div>';
fests_html += ' </div>';
fests_html += ' <div class="vbo-fest-cmds">';
fests_html += ' <button type="button" class="btn btn-danger" onclick="vboRemoveFest(\'' + day + '\', \'' + i + '\', \'' + fest['type'] + '\', this);"><?php VikBookingIcons::e('trash-alt', 'icn-nomargin'); ?></button>';
fests_html += ' </div>';
fests_html += '</div>';
}
}
// update ymd key for the selected date, useful for adding new fests
jQuery('.vbo-overlay-fests-addnew').attr('data-ymd', day);
// set content
jQuery('.vbo-overlay-fests-list').html(fests_html);
if (daytitle) {
// define the modal buttons
let cancel_btn = jQuery('<button></button>')
.attr('type', 'button')
.addClass('btn')
.text(Joomla.JText._('VBANNULLA'))
.on('click', function() {
VBOCore.emitEvent('vbo-dismiss-modal-roverv-fests');
});
let save_btn = jQuery('<button></button>')
.attr('type', 'button')
.addClass('btn btn-success')
.text(Joomla.JText._('VBSAVE'))
.on('click', function() {
vboAddFest();
});
let modal_body = VBOCore.displayModal({
suffix: 'ratesoverv-fests',
extra_class: 'vbo-modal-rounded vbo-modal-tall',
title: '<?php VikBookingIcons::e('star'); ?> ' + daytitle,
footer_left: cancel_btn,
footer_right: save_btn,
dismiss_event: 'vbo-dismiss-modal-roverv-fests',
onDismiss: () => {
jQuery('.vbo-ratesoverview-fests-wrap').appendTo('.vbo-ratesoverview-fests-helper');
},
});
jQuery('.vbo-ratesoverview-fests-wrap').appendTo(modal_body);
}
}
function vboRemoveFest(day, index, fest_type, that) {
if (!confirm('<?php echo addslashes(JText::translate('VBDELCONFIRM')); ?>')) {
return false;
}
var elem = jQuery(that);
// make the AJAX request to the controller to remove this fest from the DB
VBOCore.doAjax(
"<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=remove_fest'); ?>",
{
tmpl: "component",
dt: day,
ind: index,
type: fest_type
},
(res) => {
if (res.indexOf('e4j.ok') >= 0) {
// delete fest also from the json-decode array of objects
if (vboFests[day] && vboFests[day]['festinfo']) {
// use splice to remove the desired index from array, or delete would not make the length of the array change
vboFests[day]['festinfo'].splice(index, 1);
// re-build indexes of delete buttons, fundamental for removing the right index at next click
vboRenderFests(day);
if (!vboFests[day]['festinfo'].length) {
// delete also this date object from fests
delete vboFests[day];
// no more fests, remove the class for this date from all cells
jQuery('td.bluedays[data-ymd="'+day+'"]').removeClass('vbo-roverv-festcell');
}
}
elem.closest('.vbo-overlay-fest-details').remove();
} else {
console.log(res);
alert('Invalid response');
}
},
(err) => {
alert('Request failed');
}
);
}
function vboAddFest() {
var ymd = jQuery('.vbo-overlay-fests-addnew').attr('data-ymd');
var fest_name = jQuery('#vbo-newfest-name').val();
var fest_descr = jQuery('#vbo-newfest-descr').val();
if (!fest_name.length) {
alert(Joomla.JText._('VBO_PLEASE_FILL_FIELDS'));
return false;
}
// make the AJAX request to the controller to add the festivity to the DB
VBOCore.doAjax(
"<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=add_fest'); ?>",
{
tmpl: "component",
dt: ymd,
type: "custom",
name: fest_name,
descr: fest_descr
},
(res) => {
// parse the JSON response that contains the fest object for the passed date
try {
var stored_fest = JSON.parse(res);
if (!vboFests.hasOwnProperty(stored_fest['dt'])) {
// we need to add the proper class to all cells to show that there is a fest
jQuery('td.bluedays[data-ymd="'+stored_fest['dt']+'"]').addClass('vbo-roverv-festcell');
}
vboFests[stored_fest['dt']] = stored_fest;
hideVboDialogFests();
// reset input fields
jQuery('#vbo-newfest-name').val('');
jQuery('#vbo-newfest-descr').val('');
} catch (e) {
console.log(res);
alert('Invalid response');
return false;
}
},
(err) => {
alert('Request failed');
}
);
}
/**
* Fests dialog
*/
function hideVboDialogFests() {
VBOCore.emitEvent('vbo-dismiss-modal-roverv-fests');
}
function checkInvokeVcm() {
// trigger restriction and related checks
vboCheckVcmRestrictions();
if (!vbolistener || !vbolistener.first || !vbolistener.first.rplan) {
return;
}
var rplanid = vbolistener.first.rplan;
var idroom = vbolistener.first.idroom;
var curval = document.querySelector('input[name="roverw-newrate-vcm"]').value;
if (parseInt(curval) < 0) {
return;
}
var buiscuits = document.cookie;
if (!buiscuits.length) {
return;
}
var vcmmatch = "vboVcmRov"+idroom+rplanid+"=";
if (buiscuits.indexOf(vcmmatch) >= 0) {
// last cookie does not terminate with ; so just use 0 to compare
vcmmatch += "0";
if (buiscuits.indexOf(vcmmatch) >= 0) {
jQuery('input[name="roverw-newrate-vcm"]').prop('checked', false);
} else {
jQuery('input[name="roverw-newrate-vcm"]').prop('checked', true);
}
// re-trigger elements update
vboCheckVcmRestrictions();
}
}
/**
* Restrictions can be updated only if VCM is available and toggled ON, because
* the creation and transmission is made through the Connector Class of VCM.
* On top of that, the OTA pricing alteration rule overrides will toggle a status class.
*
* @since 1.11
*/
function vboCheckVcmRestrictions() {
if (!jQuery('input[name="roverw-newrate-vcm"]').prop('disabled') && jQuery('input[name="roverw-newrate-vcm"]').prop('checked')) {
jQuery('#roverw-newrestr').val('');
jQuery('.vbo-roverw-newrestr-wrap').show();
jQuery('.vbo-roverw-setnewrate-vcm-ota-relation').removeClass('vbo-roverw-setnewrate-vcm-ota-relation-disabled');
} else {
jQuery('.vbo-roverw-newrestr-wrap').hide();
jQuery('.vbo-roverw-setnewrate-vcm-ota-relation').addClass('vbo-roverw-setnewrate-vcm-ota-relation-disabled');
}
}
function showVboDialog() {
var format = new Date().format;
format = format.replace(new RegExp("/", 'g'), new Date().datesep);
jQuery("#rovervw-roomname").html('<?php VikBookingIcons::e('building'); ?> ' + vbolistener.first.roomName);
jQuery("#rovervw-rplan").html(vbolistener.first.rplanName);
jQuery("#rovervw-closeopen-rplan").html('"'+vbolistener.first.rplanName+'"');
jQuery("#rovervw-fromdate").html(vbolistener.first.toDate(format));
jQuery("#rovervw-todate").html(vbolistener.last.toDate(format));
jQuery(".vbo-roverw-alldays-inner").html("");
var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, true);
if (all_blocks !== false) {
var newdayscont = '';
var highestrate = vbolistener.first.defRate;
var allblocksclosed = true;
jQuery.each(all_blocks, function(k, v) {
let date_read = jQuery(v).attr('data-vbodateread');
if (!v.hasClass('vbo-roverw-rplan-off')) {
allblocksclosed = false;
}
var spids = jQuery(v).attr("data-vbospids").split("-");
var spids_det = '';
if (jQuery(v).attr("data-vbospids").length > 0 && spids.length > 0) {
spids_det += "<div class=\"vbo-roverw-daymod-infospids\" data-dt=\"" + date_read + "\"><span><i class=\"<?php echo VikBookingIcons::i('info-circle'); ?>\"></i></span></div>";
spids_det += "<div class=\"vbo-roverw-daymod-infospids-outcont\">";
spids_det += "<div class=\"vbo-roverw-daymod-infospids-incont\"><ul>";
for (var x = 0; x < spids.length; x++) {
spids_det += "<li><a target=\"_blank\" href=\"<?php echo VBOPlatformDetection::isWordPress() ? 'admin.php' : 'index.php'; ?>?option=com_vikbooking&task=editseason&cid[]="+spids[x]+"\">"+roverw_messages.openSpLink.replace("%d", spids[x])+"</a></li>";
}
spids_det += "</ul></div></div>";
}
var dayrate = parseFloat(v.find('.vbo-rplan-price').text());
if (!isNaN(dayrate) && dayrate > highestrate) {
highestrate = dayrate;
}
let date_parts = date_read.split(',');
let wday = date_parts[0].trim();
let mon = date_parts[1].replace(/[^a-z]/ig, '');
let mday = date_parts[1].replace(/[^0-9]/g, '');
newdayscont += "<div class=\"vbo-roverw-daymod\">";
newdayscont += " <div class=\"vbo-roverw-daymod-inner\">";
newdayscont += " <div class=\"vbo-roverw-daymod-innercell\">";
newdayscont += " <span class=\"vbo-roverw-daydate\">";
newdayscont += " <span class=\"vbo-roverw-daydate-wdaymday\">";
newdayscont += " <span class=\"vbo-roverw-daydate-wday\">" + wday + "</span>";
newdayscont += " <span class=\"vbo-roverw-daydate-mday\">" + mday + "</span>";
newdayscont += " </span>";
newdayscont += " <span class=\"vbo-roverw-daydate-month\">" + mon + "</span>";
newdayscont += " </span>";
newdayscont += " <span class=\"vbo-roverw-dayprice\">" + v.html() + "</span>" + spids_det;
newdayscont += " </div>";
newdayscont += " </div>";
newdayscont += "</div>";
});
jQuery(".vbo-roverw-alldays-inner").html(newdayscont);
jQuery("#roverw-newrate").attr("placeholder", vbolistener.first.defRate).val(highestrate);
// if all selected blocks have a closed rate plan, show it in red in the name of the rate plan because this will be triggered to VCM if "Apply" is clicked
if (allblocksclosed) {
jQuery("#rovervw-rplan").html('<span style="color: #f00"><i class="<?php echo VikBookingIcons::i('ban'); ?>"></i> '+vbolistener.first.rplanName+'</span>');
}
}
// choose whether to suggest to skip derived rate plans
let parentPlanRow = jQuery('.vbo-roverv-rplan[data-room-plan="' + vbolistener.first.idroom + '-' + vbolistener.first.rplan + '"][data-has-derived-rates="1"]');
if (parentPlanRow.length && parentPlanRow.closest('.vbratesoverviewtable').find('.vbo-roverv-rplan').length > 1) {
// parent rate plan selected among multiple room rate plans
jQuery('.vbo-roverw-setnewrate-skip-derived').show();
} else {
// either a derived rate plan selected, or single rate plan available
jQuery('.vbo-roverw-setnewrate-skip-derived').hide();
// turn off the flag to skip the derived rate plans from being updated
jQuery('input[name="roverw-skip-derived"]').prop('checked', false);
}
// populate OTA relations
vboRatesOvervSetRoomOtaRelations(vbolistener.first.idroom, vbolistener.first.rplan);
// VCM check
checkInvokeVcm();
// define the modal buttons
let cancel_btn = jQuery('<button></button>')
.attr('type', 'button')
.addClass('btn')
.text(Joomla.JText._('VBANNULLA'))
.on('click', function() {
VBOCore.emitEvent('vbo-dismiss-modal-roverv-newratesrestr');
});
let save_btn = jQuery('<button></button>')
.attr('type', 'button')
.addClass('btn btn-success')
.html('<?php VikBookingIcons::e('check-circle'); ?>' + Joomla.JText._('VBAPPLY'))
.on('click', function() {
setNewRates();
});
// display modal
let modal_body = VBOCore.displayModal({
suffix: 'ratesoverv-newratesrestr',
extra_class: 'vbo-modal-rounded vbo-modal-tall',
title: Joomla.JText._('VBO_RATES_AND_RESTR'),
lock_scroll: true,
draggable: true,
footer_left: cancel_btn,
footer_right: save_btn,
dismiss_event: 'vbo-dismiss-modal-roverv-newratesrestr',
loading_event: 'vbo-loading-modal-roverv-newratesrestr',
loading_body: '<?php VikBookingIcons::e('refresh', 'fa-spin fa-3x fa-fw'); ?>',
onDismiss: () => {
// cancel dates selection
vbolistener.clear();
jQuery('.day-block').removeClass('block-picked-start block-picked-middle block-picked-end');
// reset period selection
jQuery('.vbo-ratesoverview-period-from').find('span').text('');
jQuery('.vbo-ratesoverview-period-from-icon').show();
jQuery('.vbo-ratesoverview-period-to').find('span').text('');
jQuery('.vbo-ratesoverview-period-to-icon').show();
// reset room-ota relations
jQuery('.vbo-roverw-setnewrate-vcm-otas').html('');
// move the element back to its original position
jQuery('.vbo-ratesoverview-newratesrestr-wrap').appendTo('.vbo-ratesoverview-newratesrestr-helper');
},
});
jQuery('.vbo-ratesoverview-newratesrestr-wrap').appendTo(modal_body);
}
function showVboDialogPeriod() {
var format = new Date().format;
format = format.replace(new RegExp("/", 'g'), new Date().datesep);
jQuery('.vbo-ratesoverview-period-box-cals').hide();
jQuery("#rovervw-roomname").html('<?php VikBookingIcons::e('building'); ?> ' + vbolistener.first.roomName);
jQuery("#rovervw-rplan").html(vbolistener.first.rplanName);
jQuery("#rovervw-closeopen-rplan").html('"'+vbolistener.first.rplanName+'"');
jQuery("#rovervw-fromdate").html(vbolistener.first.toDate(format));
jQuery("#rovervw-todate").html(vbolistener.last.toDate(format));
jQuery(".vbo-roverw-alldays-inner").html("");
// reset default new price and placeholder
jQuery("#roverw-newrate").attr("placeholder", "").val("");
// check if all selected blocks are closed
var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, true);
if (all_blocks !== false) {
var allblocksclosed = true;
jQuery.each(all_blocks, function(k, v) {
if (!v.hasClass('vbo-roverw-rplan-off')) {
allblocksclosed = false;
return false;
}
});
if (allblocksclosed) {
jQuery("#rovervw-rplan").html('<span style="color: #f00"><i class="<?php echo VikBookingIcons::i('ban'); ?>"></i> '+vbolistener.first.rplanName+'</span>');
}
}
// choose whether to suggest to skip derived rate plans
let parentPlanRow = jQuery('.vbo-roverv-rplan[data-room-plan="' + vbolistener.first.idroom + '-' + vbolistener.first.rplan + '"][data-has-derived-rates="1"]');
if (parentPlanRow.length && parentPlanRow.closest('.vbratesoverviewtable').find('.vbo-roverv-rplan').length > 1) {
// parent rate plan selected among multiple room rate plans
jQuery('.vbo-roverw-setnewrate-skip-derived').show();
} else {
// either a derived rate plan selected, or single rate plan available
jQuery('.vbo-roverw-setnewrate-skip-derived').hide();
// turn off the flag to skip the derived rate plans from being updated
jQuery('input[name="roverw-skip-derived"]').prop('checked', false);
}
// populate OTA relations
vboRatesOvervSetRoomOtaRelations(vbolistener.first.idroom, vbolistener.first.rplan);
// VCM check
checkInvokeVcm();
// define the modal buttons
let cancel_btn = jQuery('<button></button>')
.attr('type', 'button')
.addClass('btn')
.text(Joomla.JText._('VBANNULLA'))
.on('click', function() {
VBOCore.emitEvent('vbo-dismiss-modal-roverv-newratesrestr');
});
let save_btn = jQuery('<button></button>')
.attr('type', 'button')
.addClass('btn btn-success')
.html('<?php VikBookingIcons::e('check-circle'); ?>' + Joomla.JText._('VBAPPLY'))
.on('click', function() {
setNewRates();
});
// display modal
let modal_body = VBOCore.displayModal({
suffix: 'ratesoverv-newratesrestr',
extra_class: 'vbo-modal-rounded vbo-modal-tall',
title: Joomla.JText._('VBO_RATES_AND_RESTR'),
lock_scroll: true,
draggable: true,
footer_left: cancel_btn,
footer_right: save_btn,
dismiss_event: 'vbo-dismiss-modal-roverv-newratesrestr',
loading_event: 'vbo-loading-modal-roverv-newratesrestr',
loading_body: '<?php VikBookingIcons::e('refresh', 'fa-spin fa-3x fa-fw'); ?>',
onDismiss: () => {
// cancel dates selection
vbolistener.clear();
jQuery('.day-block').removeClass('block-picked-start block-picked-middle block-picked-end');
// reset period selection
jQuery('.vbo-ratesoverview-period-from').find('span').text('');
jQuery('.vbo-ratesoverview-period-from-icon').show();
jQuery('.vbo-ratesoverview-period-to').find('span').text('');
jQuery('.vbo-ratesoverview-period-to-icon').show();
// reset room-ota relations
jQuery('.vbo-roverw-setnewrate-vcm-otas').html('');
// move the element back to its original position
jQuery('.vbo-ratesoverview-newratesrestr-wrap').appendTo('.vbo-ratesoverview-newratesrestr-helper');
},
});
jQuery('.vbo-ratesoverview-newratesrestr-wrap').appendTo(modal_body);
}
function vboCheckVcmRatesChanges() {
if (vcm_exists < 1) {
return false;
}
VBOCore.doAjax(
"<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=checkvcmrateschanges'); ?>",
{
tmpl: "component",
e4j_debug: debug_mode
},
(res) => {
if (res.indexOf('e4j.error') >= 0 ) {
console.log(res);
alert(res.replace("e4j.error.", ""));
jQuery('.vbo-ratesoverview-right-inner').hide();
} else {
//display the VCM link for updating the rates on the OTAs
var obj_res = JSON.parse(res);
var esitcont = "";
if (obj_res.changesCount > 0 && obj_res.hasOwnProperty('changesData') && obj_res.changesData.hasOwnProperty('dfrom')) {
esitcont += "<span class=\"vbo-ratesoverview-vcmwarn-close\"> <i class=\"vboicn-cancel-circle\"></i></span>";
esitcont += "<span class=\"vbo-ratesoverview-vcmwarn-count\"><i class=\"vboicn-notification\"></i> <span>"+roverw_messages.vcmRatesChanged.replace("%d", obj_res.changesCount)+"</span></span>";
esitcont += "<span class=\"vbo-ratesoverview-vcmwarn-open\"><a href=\"index.php?option=com_vikchannelmanager&task=ratespush&vbosess=1\" class=\"btn btn-primary\">"+roverw_messages.vcmRatesChangedOpen+"</a></span>";
jQuery('.vbo-ratesoverview-right-inner').html(esitcont).fadeIn();
} else {
jQuery('.vbo-ratesoverview-right-inner').hide().html('');
}
}
},
(err) => {
console.error(err);
jQuery('.vbo-ratesoverview-right-inner').hide();
}
);
}
/* Delay and launch the check VCM rates modification function, when the page loads */
setTimeout(function() {
vboCheckVcmRatesChanges();
}, 1000);
/* - */
/**
* Displays the results of the Channel Manager update request for rates/restrictions.
* Supports multiple rate plans due to derived/linkage rules.
*/
function renderChannelManagerResult(vcm_response) {
if (!Array.isArray(vcm_response)) {
// make sure the result is a list of result objects
vcm_response = [vcm_response];
}
// compose modal body
var htmlres = '<div class="vbo-vcm-rates-res-container">';
vcm_response.forEach((obj) => {
htmlres += '<div class="vbo-vcm-rates-res-rplan-wrap">';
if (obj.hasOwnProperty('rplan_name')) {
htmlres += '<div class="vbo-vcm-rates-res-rplan-data">';
htmlres += '<strong>' + obj['rplan_name'] + '</strong>';
if (obj.hasOwnProperty('is_derived') && obj['is_derived']) {
htmlres += ' <span class="label label-info">' + Joomla.JText._('VBO_IS_DERIVED_RATE') + '</span>';
}
htmlres += '</div>';
}
if (obj.hasOwnProperty('channels_success')) {
htmlres += '<div class="vbo-vcm-rates-res-success">';
for (var ch_id in obj['channels_success']) {
htmlres += '<div class="vbo-vcm-rates-res-channel">';
htmlres += ' <div class="vbo-vcm-rates-res-channel-esit">';
htmlres += ' <i class="<?php echo VikBookingIcons::i('check'); ?>"></i>';
htmlres += ' </div>';
htmlres += ' <div class="vbo-vcm-rates-res-channel-logo">';
if (obj['channels_updated'].hasOwnProperty(ch_id) && obj['channels_updated'][ch_id]['logo'].length) {
htmlres += '<img src="'+obj['channels_updated'][ch_id]['logo']+'" />';
} else {
htmlres += '<span>'+obj['channels_success'][ch_id]+'</span>';
}
htmlres += ' </div>';
htmlres += '</div>';
}
if (obj.hasOwnProperty('channels_bkdown')) {
htmlres += '<div class="vbo-vcm-rates-res-bkdown">';
htmlres += ' <div><pre>'+obj['channels_bkdown']+'</pre></div>';
htmlres += '</div>';
}
htmlres += '</div>';
}
if (obj.hasOwnProperty('channels_warnings')) {
htmlres += '<div class="vbo-vcm-rates-res-warning">';
for (var ch_id in obj['channels_warnings']) {
htmlres += '<div class="vbo-vcm-rates-res-channel">';
htmlres += ' <div class="vbo-vcm-rates-res-channel-esit">';
htmlres += ' <i class="<?php echo VikBookingIcons::i('exclamation-triangle'); ?>"></i>';
htmlres += ' </div>';
htmlres += ' <div class="vbo-vcm-rates-res-channel-logo">';
if (obj['channels_updated'].hasOwnProperty(ch_id) && obj['channels_updated'][ch_id]['logo'].length) {
htmlres += '<img src="'+obj['channels_updated'][ch_id]['logo']+'" />';
} else if (obj['channels_updated'].hasOwnProperty(ch_id)) {
htmlres += '<span>'+obj['channels_updated'][ch_id]['name']+'</span>';
}
htmlres += ' </div>';
htmlres += ' <div class="vbo-vcm-rates-res-channel-det">';
htmlres += ' <pre>'+obj['channels_warnings'][ch_id]+'</pre>';
htmlres += ' </div>';
htmlres += '</div>';
}
htmlres += '</div>';
}
if (obj.hasOwnProperty('channels_errors')) {
htmlres += '<div class="vbo-vcm-rates-res-error">';
for (var ch_id in obj['channels_errors']) {
htmlres += '<div class="vbo-vcm-rates-res-channel">';
htmlres += ' <div class="vbo-vcm-rates-res-channel-esit">';
htmlres += ' <i class="<?php echo VikBookingIcons::i('times'); ?>"></i>';
htmlres += ' </div>';
htmlres += ' <div class="vbo-vcm-rates-res-channel-logo">';
if (obj['channels_updated'].hasOwnProperty(ch_id) && obj['channels_updated'][ch_id]['logo'].length) {
htmlres += ' <img src="'+obj['channels_updated'][ch_id]['logo']+'" />';
} else if (obj['channels_updated'].hasOwnProperty(ch_id)) {
htmlres += ' <span>'+obj['channels_updated'][ch_id]['name']+'</span>';
}
htmlres += ' </div>';
htmlres += ' <div class="vbo-vcm-rates-res-channel-det">';
htmlres += ' <pre>'+obj['channels_errors'][ch_id]+'</pre>';
htmlres += ' </div>';
htmlres += '</div>';
}
htmlres += '</div>';
}
htmlres += '</div>';
});
// close container
htmlres += '</div>';
// display results within a modal window
VBOCore.displayModal({
suffix: 'vbo-vcm-rates-res',
extra_class: 'vbo-modal-rounded vbo-modal-tall',
title: Joomla.JText._('VBOVCMRATESRES'),
body: htmlres,
draggable: true,
});
}
function vboRatesOvervSetRoomOtaRelations(room_id, rplan_id) {
// the room-ota relations wrapper
let wrapper = jQuery('.vbo-roverw-setnewrate-vcm-otas');
// always empty the wrapper
wrapper.html('');
if (!room_id || !rplan_id || !vboRoomOtaRels.hasOwnProperty(room_id)) {
// nothing to render
return;
}
// start counter
let ota_ch_counter = 0;
// build and append room-OTA relations
for (const ota_name in vboRoomOtaRels[room_id]['channels']) {
// build ota readable name
let ota_read_name = ota_name;
ota_read_name = ota_read_name.replace(/api$/, '');
ota_read_name = ota_read_name.replace(/^(google)(hotel|vr)$/i, '$1 $2');
// build room-ota relation block and elements
let ota_block = jQuery('<div></div>');
ota_block.addClass('vbo-roverw-setnewrate-vcm-ota-relation');
let ota_block_inner = jQuery('<div></div>');
ota_block_inner
.addClass('vbo-roverw-setnewrate-vcm-ota-relation-pricing')
.attr('data-ota', (ota_name + '').toLowerCase());
let ota_block_channel = jQuery('<div></div>');
ota_block_channel
.addClass('vbo-roverw-setnewrate-vcm-ota-relation-channel')
.attr('data-otaid', vboRoomOtaRels[room_id]['accounts'][ota_ch_counter]['idchannel'])
.append('<img src="' + vboRoomOtaRels[room_id]['channels'][ota_name] + '" />')
.append('<span>' + ota_read_name + '</span>');
let ota_pricing_value = jQuery('<span></span>');
ota_pricing_value
.addClass('vbo-roverw-setnewrate-vcm-ota-pricing-startvalue')
.html('<?php VikBookingIcons::e('circle-notch', 'fa-spin fa-fw'); ?>')
.on('click', function() {
jQuery(this)
.closest('.vbo-roverw-setnewrate-vcm-ota-relation-pricing')
.find('.vbo-roverw-setnewrate-vcm-ota-channel-pricing')
.toggle();
});
let ota_block_pricing = jQuery('<div></div>');
ota_block_pricing
.addClass('vbo-roverw-setnewrate-vcm-ota-channel-pricing')
.css('display', 'none')
.append(jQuery('.vbo-roverw-setnewrate-vcm-ota-pricing-alteration').first().clone());
// register "input" event for select/input elements to control the channel alteration rule overrides
ota_block_pricing.find('select, input').on('input', function() {
let input_elem = jQuery(this);
// get the current channel alteration command
let ota_alteration_command = input_elem
.closest('.vbo-roverw-setnewrate-vcm-ota-relation-pricing')
.find('.vbo-roverw-setnewrate-ota-pricing-currentvalue[data-alteration]')
.attr('data-alteration');
// access alteration rule and input value
let rmod_type = input_elem.attr('data-alter-rule');
let rmod_value = input_elem.val();
if (!ota_alteration_command || !rmod_type || !(rmod_value + '').length) {
return;
}
// check what pricing factor was changed
if (rmod_type == 'rmodsop') {
// increase or decrease rate
let command_old_val = ota_alteration_command.substr(0, 1);
let command_new_val = parseInt(rmod_value) == 1 ? '+' : '-';
ota_alteration_command = ota_alteration_command.replace(command_old_val, command_new_val);
} else if (rmod_type == 'rmodsamount') {
// amount
let command_op = ota_alteration_command.substr(0, 1);
let command_val = ota_alteration_command.substr(-1, 1);
let command_old_val = ota_alteration_command.replace(command_op, '').replace(command_val, '');
let command_new_val = parseFloat(rmod_value);
ota_alteration_command = ota_alteration_command.replace(command_old_val, command_new_val);
} else if (rmod_type == 'rmodsval') {
// percent or absolute
let command_old_val = ota_alteration_command.substr(-1, 1);
let command_new_val = parseInt(rmod_value) == 1 ? '%' : '*';
ota_alteration_command = ota_alteration_command.replace(command_old_val, command_new_val);
}
// get current currency options
let currencyObj = VBOCore.getCurrency();
let orig_currency_options = currencyObj.getOptions();
// check if the channel requires a specific currency
let ota_currency_data = input_elem
.closest('.vbo-roverw-setnewrate-vcm-ota-relation-pricing')
.find('.vbo-roverw-setnewrate-ota-pricing-willvalue')
.attr('data-currency');
if (ota_currency_data) {
// decode currency data instructions
try {
ota_currency_data = JSON.parse(ota_currency_data);
} catch (e) {
ota_currency_data = {};
}
}
// define the current channel alteration string (readable)
let ota_alteration_string = ota_alteration_command;
// finalize the current channel alteration string (readable)
let ota_alteration_val = ota_alteration_string.substr(-1, 1);
if (ota_alteration_val != '%') {
ota_alteration_string = ota_alteration_string.replace(ota_alteration_val, '') + ((ota_currency_data && ota_currency_data?.symbol ? ota_currency_data.symbol : '') || vbo_currency_symbol);
}
// update the alteration rule command attribute
input_elem
.closest('.vbo-roverw-setnewrate-vcm-ota-relation-pricing')
.find('.vbo-roverw-setnewrate-ota-pricing-currentvalue[data-alteration]')
.attr('data-alteration', ota_alteration_command);
// update the alteration rule string tag text
input_elem
.closest('.vbo-roverw-setnewrate-vcm-ota-relation-pricing')
.find('.vbo-roverw-setnewrate-ota-pricing-currentvalue[data-alteration]')
.html(ota_alteration_string);
// get the current rate to set
let current_room_rate = jQuery('#roverw-newrate').val();
if (current_room_rate) {
// dispatch the event to trigger the re-calculation of the OTA rates
VBOCore.emitEvent('vbo-roverv-setnewrate-calc-ota-pricing', {
rate: current_room_rate,
});
}
});
// append elements to wrapper
ota_block_channel.append(ota_pricing_value);
ota_block_inner.append(ota_block_channel);
ota_block_inner.append(ota_block_pricing);
ota_block.append(ota_block_inner);
wrapper.append(ota_block);
// increase OTA channel counter
ota_ch_counter++;
}
// trigger an AJAX request to load the current alteration rules, if any
VBOCore.doAjax(
"<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=pricing.loadOtaAlterationRules'); ?>",
{
room_id: room_id,
rate_id: rplan_id,
},
(res) => {
var obj_res = typeof res === 'string' ? JSON.parse(res) : res;
let alter_room_rates = obj_res['rmod'] == '1' || obj_res['rmod'] == 1;
// scan all room OTAs
jQuery('.vbo-roverw-setnewrate-vcm-otas').find('.vbo-roverw-setnewrate-vcm-ota-relation').each(function(key, elem) {
// get the current OTA identifier and whether pricing is altered
let ota_wrap = jQuery(elem);
let ota_id = ota_wrap.find('.vbo-roverw-setnewrate-vcm-ota-relation-channel').attr('data-otaid');
let alter_ota_rates = alter_room_rates && obj_res['channels'] && (obj_res['channels'].includes(ota_id) || obj_res['channels'].includes(parseInt(ota_id)));
if (!alter_ota_rates && alter_room_rates && obj_res.hasOwnProperty('rmod_channels') && obj_res['rmod_channels'].hasOwnProperty(ota_id)) {
alter_ota_rates = true;
}
// check if the current channel is using a different currency
let ota_currency_data = {};
if (obj_res.hasOwnProperty('cur_rplans') && obj_res['cur_rplans'].hasOwnProperty(ota_id)) {
let ota_check_currency = obj_res['cur_rplans'][ota_id];
if (obj_res.hasOwnProperty('currency_data_options') && obj_res['currency_data_options'].hasOwnProperty(ota_check_currency)) {
// set custom currency data returned
ota_currency_data = obj_res['currency_data_options'][ota_check_currency];
}
}
// build pricing alteration strings
let alteration_command = '';
let alteration_string = '';
// default alteration factors (no pricing alteration rules)
let alter_op = '+';
let alter_amount = '0';
let alter_val = '%';
if (alter_ota_rates) {
// check how rates are altered for this channel
if (obj_res.hasOwnProperty('rmod_channels') && obj_res['rmod_channels'].hasOwnProperty(ota_id)) {
// ota-level pricing alteration rule
if (parseInt(obj_res['rmod_channels'][ota_id]['rmod']) == 1) {
alter_op = parseInt(obj_res['rmod_channels'][ota_id]['rmodop']) == 1 ? '+' : '-';
alter_amount = obj_res['rmod_channels'][ota_id]['rmodamount'];
alter_val = parseInt(obj_res['rmod_channels'][ota_id]['rmodval']) == 1 ? '%' : '*';
}
} else {
// room-level pricing alteration rule
alter_op = parseInt(obj_res['rmodop']) == 1 ? '+' : '-';
alter_amount = obj_res['rmodamount'] || '0';
alter_val = parseInt(obj_res['rmodval']) == 1 ? '%' : '*';
}
}
// construct alteration strings
alteration_command = alter_op + (alter_amount + '') + (alter_val + '');
alteration_string = alter_op + (alter_amount + '') + (alter_val == '%' ? '%' : (ota_currency_data?.symbol || vbo_currency_symbol));
// stop room-ota loading and set alteration string
let alteration_elem = jQuery('<span></span>');
alteration_elem
.addClass('vbo-roverw-setnewrate-ota-pricing-currentvalue')
.attr('data-alteration', alteration_command)
.html(alteration_string);
let will_alter_elem = jQuery('<span></span>').addClass('vbo-roverw-setnewrate-ota-pricing-willvalue');
if (ota_currency_data.symbol) {
// set currency data object
will_alter_elem.attr('data-currency', JSON.stringify(ota_currency_data));
}
// set elements
ota_wrap
.find('.vbo-roverw-setnewrate-vcm-ota-pricing-startvalue')
.html('')
.append(will_alter_elem)
.append(alteration_elem)
.append('<?php VikBookingIcons::e('edit', 'edit-ota-pricing'); ?>');
// populate default values for input element overrides
ota_wrap.find('select[data-alter-rule="rmodsop"]').val(alter_op == '+' ? 1 : 0);
ota_wrap.find('input[data-alter-rule="rmodsamount"]').val(parseInt(alter_amount) > 0 ? alter_amount : '');
ota_wrap.find('select[data-alter-rule="rmodsval"]').val(alter_val == '%' ? 1 : 0);
});
// check the current rate value
let current_room_rate = jQuery('#roverw-newrate').val();
if (current_room_rate) {
// dispatch the event to allow the actual calculation of the OTA rate
VBOCore.emitEvent('vbo-roverv-setnewrate-calc-ota-pricing', {
rate: current_room_rate,
room_id: room_id,
rate_id: rplan_id,
});
}
},
(err) => {
alert(err.responseText || 'Request Failed');
}
);
}
function setNewRates() {
var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, true);
var toval = jQuery("#roverw-newrate").val();
var tovalint = parseFloat(toval);
var invoke_vcm = jQuery('input[name="roverw-newrate-vcm"]').is(':checked') ? 1 : 0;
var setminlos = jQuery('#roverw-newrestr').val();
var closerplan = 0;
if (all_blocks === false || !toval.length || isNaN(tovalint) || tovalint <= 0) {
alert(roverw_messages.setNewRatesMissing);
return false;
}
// set cookie to remember the action to invoke VCM for this combination of room-rateplan
var nd = new Date();
nd.setTime(nd.getTime() + (365*24*60*60*1000));
document.cookie = "vboVcmRov"+vbolistener.first.idroom+vbolistener.first.rplan+"="+invoke_vcm+"; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
// check whether all blocks have closed the rate plan
var allblocksclosed = true;
jQuery.each(all_blocks, function(k, v) {
if (!v.hasClass('vbo-roverw-rplan-off')) {
allblocksclosed = false;
// break
return false;
}
});
closerplan = allblocksclosed ? 1 : closerplan;
// check the OTA pricing alteration rules, if any
let ota_pricing = {};
if (invoke_vcm) {
// scan all OTA alteration rules, if any
document.querySelectorAll('.vbo-roverw-setnewrate-ota-pricing-currentvalue[data-alteration]').forEach((elem) => {
// channel alteration string
let alter_string = elem.getAttribute('data-alteration');
if (!alter_string) {
alter_string = '';
}
// access the parent node to get the OTA channel identifier
let ota_id = elem
.closest('.vbo-roverw-setnewrate-vcm-ota-relation-channel[data-otaid]')
.getAttribute('data-otaid');
if (!ota_id || !alter_string || alter_string == '+0%' || alter_string == '+0*') {
// avoid pushing an empty alteration command
return;
}
// push OTA pricing alteration command
ota_pricing[ota_id] = alter_string;
});
}
if (!Object.keys(ota_pricing).length) {
// unset the object for the request
ota_pricing = null;
}
// show loading
VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
VBOCore.doAjax(
"<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=pricing.setnewrates'); ?>",
{
tmpl: "component",
e4j_debug: debug_mode,
id_room: vbolistener.first.idroom,
id_price: vbolistener.first.rplan,
rate: toval,
vcm: invoke_vcm,
minlos: setminlos,
fromdate: vbolistener.first.toDate("yy-mm-dd"),
todate: vbolistener.last.toDate("yy-mm-dd"),
rateclosed: closerplan,
ota_pricing: ota_pricing,
skip_derived: (jQuery('input[name="roverw-skip-derived"]').prop('checked') ? 1 : 0),
},
(res) => {
if (typeof res === 'string' && res.indexOf('e4j.error') === 0) {
alert(res.replace('e4j.error.', ''));
// stop loading
VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
// abort
return;
}
try {
// display new rates in all_blocks IDs
var restr_set = false;
var obj_res = typeof res === 'string' ? JSON.parse(res) : res;
jQuery.each(obj_res, function(k, v) {
if (k == 'vcm') {
return true;
}
var elem = jQuery("#cell-"+k+"-"+vbolistener.first.idroom);
if (elem.length) {
elem.find(".vbo-rplan-price").html(v.cost);
var spids = '';
if (v.hasOwnProperty('spids')) {
jQuery.each(v.spids, function(spk, spv) {
spids += spv+'-';
});
//right trim dash
spids = spids.replace(/-+$/, '');
}
elem.attr('data-vbospids', spids);
// check if restrictions were set
if (v.hasOwnProperty('newminlos')) {
// always convert v.newminlos to a string to avoid errors with indexOf
var newminlos = v.newminlos+'';
if (newminlos.indexOf('e4j.error') >= 0) {
// an error occurred
alert(newminlos.replace("e4j.error.", ""));
} else {
// get cell identifier part
restr_set = true;
var cell_parts = k.split('-');
var restr_elem = jQuery('#cell-'+cell_parts[0]+'-'+cell_parts[1]+'-'+cell_parts[2]+'-'+vbolistener.first.idroom+'-restr');
if (restr_elem.length) {
var restr_cont = restr_elem.find('.vbo-roverw-curminlos');
restr_cont.html(newminlos);
if (parseInt(newminlos) > 1) {
restr_cont.addClass('vbo-roverw-curminlos-active');
} else {
restr_cont.removeClass('vbo-roverw-curminlos-active');
}
}
// attempt to remove an eventual orphan list
var orphan_elem = jQuery('.vbo-ratesoverview-orphan-dt[data-dt="'+cell_parts[0]+'-'+cell_parts[1]+'-'+cell_parts[2]+'-'+vbolistener.first.idroom+'"]');
if (orphan_elem.length) {
if (orphan_elem.length < 2) {
jQuery('#vbo-ratesoverview-orphans-wrapper-'+vbolistener.first.idroom).fadeOut(400, function() {
orphan_elem.remove();
});
} else {
orphan_elem.remove();
}
}
}
}
//
}
});
// stop loading
VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
// dismiss modal
VBOCore.emitEvent('vbo-dismiss-modal-roverv-newratesrestr');
if (obj_res.hasOwnProperty('vcm')) {
// display CM results
renderChannelManagerResult(obj_res['vcm']);
} else {
setTimeout(function() {
vboCheckVcmRatesChanges();
}, 500);
}
if (restr_set) {
// re-calculate orphans after setting the restriction
setTimeout(function() {
vboCheckOrphans();
}, 200);
}
} catch(err) {
throw new Error(err);
}
},
(err) => {
alert(err.responseText || 'Request Failed');
// stop loading
VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
}
);
}
function modRoomRatePlan(mode) {
var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, true);
if (all_blocks !== false && mode.length > 0) {
// start loading
VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
VBOCore.doAjax(
"<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=modroomrateplans'); ?>",
{
tmpl: "component",
e4j_debug: debug_mode,
id_room: vbolistener.first.idroom,
id_price: vbolistener.first.rplan,
type: mode,
fromdate: vbolistener.first.toDate("yy-mm-dd"),
todate: vbolistener.last.toDate("yy-mm-dd")
},
(res) => {
if (res.indexOf('e4j.error') >= 0 ) {
console.log(res);
alert(res.replace("e4j.error.", ""));
// stop loading
VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
} else {
// apply new classes in all_blocks IDs
var obj_res = JSON.parse(res);
jQuery.each(obj_res, function(k, v) {
var elem = jQuery("#cell-"+k+"-"+vbolistener.first.idroom);
if (elem.length) {
elem.removeClass(v.oldcls).addClass(v.newcls);
}
});
// stop loading
VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
// dismiss modal
VBOCore.emitEvent('vbo-dismiss-modal-roverv-newratesrestr');
setTimeout(function() {
vboCheckVcmRatesChanges();
}, 500);
}
},
(err) => {
alert("Request Failed");
// stop loading
VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
}
);
} else {
alert(roverw_messages.modRplansMissing);
return false;
}
}
function vboUpdateRplan(that) {
if (vbolistener === null || vbolistener.first === null) {
return true;
}
vbolistener.first.rplan = jQuery(that).val();
vbolistener.first.rplanName = jQuery(that).find('option:selected').text();
vbolistener.first.defRate = jQuery(that).find('option:selected').attr('data-defrate');
}
function pickBlock(id) {
var struct = initBlockStructure(id);
if (!vbolistener.pickFirst(struct)) {
// first already picked
if ((vbolistener.first.isBeforeThan(struct) || vbolistener.first.isSameDay(struct)) && vbolistener.first.isSameRplan(struct) && vbolistener.first.isSameRoom(struct)) {
// last > first : pick last
if (vbolistener.pickLast(struct)) {
var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, false);
if (all_blocks !== false) {
jQuery.each(all_blocks, function(k, v){
if ( !v.hasClass('block-picked-middle') ) {
v.addClass('block-picked-middle');
}
});
jQuery('#'+vbolistener.last.id).addClass('block-picked-end');
showVboDialog();
}
}
} else {
// last < first : clear selection
vbolistener.clear();
jQuery('.day-block').removeClass('block-picked-start block-picked-middle block-picked-end');
}
} else {
// first picked
jQuery('#'+vbolistener.first.id).addClass('block-picked-start');
}
}
function getAllBlocksBetween(start, end, outers_included) {
if (!start.isSameRplan(end) || !start.isSameRoom(end)) {
return false;
}
if (start.isAfterThan(end)) {
return false;
}
var queue = new Array();
if (outers_included) {
queue.push(jQuery('#'+start.id));
}
if (start.isSameDay(end)) {
return queue;
}
var node = jQuery('#'+start.id).next();
var end_id = jQuery('#'+end.id).attr('id');
while (node.length > 0 && node.attr('id') != end_id) {
queue.push(node);
node = node.next();
}
if (outers_included) {
queue.push(jQuery('#'+end.id));
}
return queue;
}
function getPeriodStructure(data) {
return {
"day": parseInt(data[0]),
"month": parseInt(data[1]),
"year": parseInt(data[2]),
"rplan": data[3],
"idroom": data[6],
"roomName": data[7],
"rplanName": data[4],
"defRate": data[5],
"id": "cell-"+parseInt(data[0])+"-"+parseInt(data[1])+"-"+parseInt(data[2])+"-"+data[3]+"-"+data[6],
"isSameDay": function(block) {
return (this.month == block.month && this.day == block.day && this.year == block.year);
},
"isBeforeThan": function(block) {
return (
(this.year < block.year) ||
(this.year == block.year && this.month < block.month) ||
(this.year == block.year && this.month == block.month && this.day < block.day)
);
},
"isAfterThan": function(block) {
return (
(this.year > block.year) ||
(this.year == block.year && this.month > block.month) ||
(this.year == block.year && this.month == block.month && this.day > block.day)
);
},
"isSameRplan": function(block) {
return (this.rplan == block.rplan);
},
"isSameRoom": function(block) {
return (this.idroom == block.idroom);
},
"toDate": function(format) {
return format.replace(
'dd', (this.day < 10 ? '0' : '' ) + this.day
).replace(
'mm', (this.month < 10 ? '0' : '') + this.month
).replace(
'yy', this.year
);
}
};
}
function initBlockStructure(id) {
var s = id.split("-");
if (s.length != 6) {
return {};
}
var elem = jQuery("#"+id);
return {
"day": parseInt(s[1]),
"month": parseInt(s[2]),
"year": parseInt(s[3]),
"rplan": s[4],
"idroom": s[5],
"roomName": elem.parent("tr").find("td").first().attr("data-roomname"),
"rplanName": elem.parent("tr").find("td").first().find(".vbo-rplan-name").text(),
"defRate": elem.parent("tr").find("td").first().attr("data-defrate"),
"id": id,
"isSameDay": function(block) {
return (this.month == block.month && this.day == block.day && this.year == block.year);
},
"isBeforeThan": function(block) {
return (
(this.year < block.year) ||
(this.year == block.year && this.month < block.month) ||
(this.year == block.year && this.month == block.month && this.day < block.day)
);
},
"isAfterThan": function(block) {
return (
(this.year > block.year) ||
(this.year == block.year && this.month > block.month) ||
(this.year == block.year && this.month == block.month && this.day > block.day)
);
},
"isSameRplan": function(block) {
return (this.rplan == block.rplan);
},
"isSameRoom": function(block) {
return (this.idroom == block.idroom);
},
"toDate": function(format) {
return format.replace(
'dd', (this.day < 10 ? '0' : '') + this.day
).replace(
'mm', (this.month < 10 ? '0' : '') + this.month
).replace(
'yy', this.year
);
}
};
}
function CalendarListener() {
this.first = null;
this.last = null;
}
CalendarListener.prototype.pickFirst = function(struct) {
if (!this.isFirstPicked()) {
this.first = struct;
return true;
}
return false;
}
CalendarListener.prototype.pickLast = function(struct) {
if (!this.isLastPicked() && this.isFirstPicked()) {
this.last = struct;
return true;
}
return false;
}
CalendarListener.prototype.clear = function() {
this.first = null;
this.last = null;
}
CalendarListener.prototype.isFirstPicked = function() {
return this.first != null;
}
CalendarListener.prototype.isLastPicked = function() {
return this.last != null;
}
/* Dates selection - End */
function vboToggleOBPRows() {
jQuery('tr.vbo-roverviewtablerow-occupancy').toggle();
var newcookieval = 0;
if (jQuery('tr.vbo-roverviewtablerow-occupancy').length && jQuery('tr.vbo-roverviewtablerow-occupancy').is(':visible')) {
newcookieval = 1;
}
var nd = new Date();
nd.setTime(nd.getTime() + (365*24*60*60*1000));
document.cookie = "vboRovwObp=" + newcookieval + "; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
}
function vboToggleCollapse() {
var expand = jQuery('input[name="vbo_collapse"]').is(':checked');
var collapse = expand ? 0 : 1;
if (expand) {
jQuery('.vbo-ratesoverview-roomsel-entry-calc-inner, .vbo-roverv-forecast-inner, .vbo-ratesoverview-period-container').show();
jQuery('.vbo-ratesoverview-top-container').removeClass('collapsed');
} else {
jQuery('.vbo-ratesoverview-roomsel-entry-calc-inner, .vbo-roverv-forecast-inner, .vbo-ratesoverview-period-container').hide();
jQuery('.vbo-ratesoverview-top-container').addClass('collapsed');
}
var nd = new Date();
nd.setTime(nd.getTime() + (365*24*60*60*1000));
document.cookie = "vboRovwColl=" + collapse + "; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
}
function vboCheckCollapse() {
if (jQuery('.vbo-ratesoverview-roomsel-entry-calc-inner').is(':visible') && jQuery('.vbo-roverv-forecast-inner').is(':visible')) {
// all elements are visible, expanded
return;
}
jQuery('input[name="vbo_collapse"]').trigger('click');
}
function vboSelectAllRooms(btn) {
var sel_elem = jQuery('#roomsel');
sel_elem.find('option').prop('selected', true);
sel_elem.trigger('change');
// hide button
jQuery(btn).parent().remove();
// auto-submit form
document.vboratesovwform.submit();
}
var timeline_height_set = false;
jQuery(function() {
// register to the event emitted when a new booking is created through an admin widget
document.addEventListener('vbo_new_booking_created', (e) => {
if (!e || !e.detail || !e.detail.hasOwnProperty('bid') || !e.detail['bid']) {
// do nothing
return;
}
// reload the page to display the new booking just created
location.reload();
});
// toggle OBP rows
if (jQuery('.vbo-ratesoverview-obp-toggle').length && jQuery('tr.vbo-roverviewtablerow-occupancy').length) {
jQuery('.vbo-ratesoverview-obp-toggle').show();
var initial = jQuery('.vbo-ratesoverview-obp-toggle').attr('data-obpstartstatus');
if (initial == '0') {
jQuery('tr.vbo-roverviewtablerow-occupancy').hide();
}
}
//
jQuery(".vbo-ratesoverview-tab-los").click(function() {
var nd = new Date();
nd.setTime(nd.getTime() + (365*24*60*60*1000));
document.cookie = "vboRovwRab=los; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
jQuery(this).removeClass("vbo-ratesoverview-tab-unactive").addClass("vbo-ratesoverview-tab-active");
jQuery(".vbo-ratesoverview-tab-cal").removeClass("vbo-ratesoverview-tab-active").addClass("vbo-ratesoverview-tab-unactive");
jQuery(".vbo-ratesoverview-roomsel-entry-los").show();
jQuery(".vbo-ratesoverview-roomsel-entry-forecast").hide();
jQuery(".vbo-ratesoverview-caltab-cont").hide();
jQuery(".vbo-ratesoverview-lostab-cont").fadeIn();
if (!timeline_height_set) {
jQuery('.vbo-timeline-container').css('min-height', (jQuery('.vbo-timeline-container').outerHeight() + 20));
timeline_height_set = true;
}
});
jQuery(".vbo-ratesoverview-tab-cal").click(function() {
var nd = new Date();
nd.setTime(nd.getTime() + (365*24*60*60*1000));
document.cookie = "vboRovwRab=cal; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
jQuery(this).removeClass("vbo-ratesoverview-tab-unactive").addClass("vbo-ratesoverview-tab-active");
jQuery(".vbo-ratesoverview-tab-los").removeClass("vbo-ratesoverview-tab-active").addClass("vbo-ratesoverview-tab-unactive");
jQuery(".vbo-ratesoverview-roomsel-entry-los").hide();
jQuery(".vbo-ratesoverview-roomsel-entry-forecast").show();
jQuery(".vbo-ratesoverview-lostab-cont").hide();
jQuery(".vbo-ratesoverview-caltab-cont").fadeIn();
});
if (window.location.hash == '#tabcal') {
jQuery(".vbo-ratesoverview-tab-cal").trigger("click");
}
jQuery("body").on("click", ".vbo-ratesoverview-numnight", function() {
var inpnight = jQuery(this).attr('id');
if (jQuery('.vbo-ratesoverview-numnight').length > 1) {
jQuery('#inp'+inpnight).remove();
jQuery(this).remove();
}
});
jQuery("body").on("dblclick", ".vbo-calcrates-rateblock", function() {
if (jQuery(this).parent('.vbo-ratesoverview-calculation-response-room').find('.vbo-calcrates-rateblock').length < 2) {
// remove the whole container as there is just one rate plan
jQuery(this).parent('.vbo-ratesoverview-calculation-response-room').remove();
} else {
// remove only this rate plan
jQuery(this).remove();
}
});
jQuery('#vbo-addnumnight-act').click(function() {
var setnights = jQuery('#vbo-addnumnight').val();
if (parseInt(setnights) > 0) {
var los_exists = false;
jQuery('.vbo-ratesoverview-numnight').each(function() {
if (parseInt(jQuery(this).text()) == parseInt(setnights)) {
los_exists = true;
}
});
if (!los_exists) {
jQuery('.vbo-ratesoverview-numnight').last().after("<span class=\"vbo-ratesoverview-numnight\" id=\"numnights"+setnights+"\">"+setnights+"</span><input type=\"hidden\" name=\"nights_cal[]\" id=\"inpnumnights"+setnights+"\" value=\""+setnights+"\" />");
} else {
jQuery('#vbo-addnumnight').val((parseInt(setnights) + 1));
}
}
});
jQuery('#vbo-ratesoverview-calculate').click(function() {
jQuery(this).text(Joomla.JText._('VBRATESOVWRATESCALCULATORCALCING')).prop('disabled', true);
var checkindate = jQuery("#checkindate").val();
if (!(checkindate.length > 0)) {
checkindate = '<?php echo date('Y-m-d') ?>';
jQuery("#checkindate").val(checkindate);
}
var nights = jQuery("#vbo-numnights").val();
var adults = jQuery("#vbo-numadults").val();
var children = jQuery("#vbo-numchildren").val();
var idroom = jQuery("#roomselcalc").val();
// always remove warning messages
jQuery(".vbo-ratesoverview-calculation-response").find('.vbo-warning').remove();
if (jQuery("#vbo-ratesoverview-calculation-response-room"+idroom).length) {
// remove previous containers for this room
jQuery("#vbo-ratesoverview-calculation-response-room"+idroom).remove();
}
if (!jQuery(".vbo-ratesoverview-calculation-response-room").length) {
// if no rooms responses, empty the whole container
jQuery('.vbo-ratesoverview-calculation-response').html('');
}
VBOCore.doAjax(
"<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=calc_rates'); ?>",
{
tmpl: "component",
id_room: idroom,
checkin: checkindate,
num_nights: nights,
num_adults: adults,
num_children: children
},
(res) => {
res = JSON.parse(res);
res = res[0];
if (res.indexOf('e4j.error') >= 0 ) {
jQuery(".vbo-ratesoverview-calculation-response").html("<p class='vbo-warning'>" + res.replace("e4j.error.", "") + "</p>").fadeIn();
} else {
var titlecont = '<span class="vbo-ratesoverview-calculation-response-room-name">'+jQuery("#roomselcalc option:selected").text() + '</span> ' + checkindate + ' - ' + jQuery("#checkoutdate").val() + ', ' + nights + ' <?php echo addslashes(JText::translate('VBRATESOVWRATESCALCNUMNIGHTS')); ?>, ' + adults + ' <?php echo addslashes(JText::translate('VBRATESOVWRATESCALCNUMADULTS')); ?>';
var newcont = '<div class="vbo-ratesoverview-calculation-response-room" id="vbo-ratesoverview-calculation-response-room'+idroom+'"><h4>'+titlecont+'</h4>'+res+'</div>';
// check whether the content should be appended
if (jQuery(".vbo-ratesoverview-calculation-response").find('.vbo-ratesoverview-calculation-response-room').length) {
newcont = jQuery(".vbo-ratesoverview-calculation-response").html() + newcont;
}
//
jQuery(".vbo-ratesoverview-calculation-response").html(newcont).fadeIn();
// loop over every room response and pricing to append the book-now button for the page calendar
var base_booknow_link_orig = jQuery('#vbo-base-booknow-link').attr('href');
jQuery('.vbo-calcrates-rateblock').each(function(k, v) {
var elem = jQuery(v);
var base_booknow_link = base_booknow_link_orig;
// remove existing button
elem.find('.vbo-room-booknow-rct').remove();
//
var b_idprice = elem.attr('data-idprice');
base_booknow_link = base_booknow_link.replace('idprice=', 'idprice=' + b_idprice);
var b_idroom = elem.attr('data-idroom');
base_booknow_link = base_booknow_link.replace('cid[]=', 'cid[]=' + b_idroom);
var b_checkin = elem.attr('data-checkin');
base_booknow_link = base_booknow_link.replace('checkin=', 'checkin=' + b_checkin);
var b_checkout = elem.attr('data-checkout');
base_booknow_link = base_booknow_link.replace('checkout=', 'checkout=' + b_checkout);
var b_adults = elem.attr('data-adults');
base_booknow_link = base_booknow_link.replace('adults=', 'adults=' + b_adults);
var b_children = elem.attr('data-children');
base_booknow_link = base_booknow_link.replace('children=', 'children=' + b_children);
var booknow = '<a href="' + base_booknow_link + '" class="btn btn-primary vbo-room-booknow-rct" target="_blank">' + Joomla.JText._('VBO_BOOKNOW') + '</a>';
elem.append(booknow);
});
//
}
jQuery('#vbo-ratesoverview-calculate').text(Joomla.JText._('VBRATESOVWRATESCALCULATORCALC')).prop('disabled', false);
},
(err) => {
console.error(err);
jQuery(".vbo-ratesoverview-calculation-response").fadeOut();
jQuery('#vbo-ratesoverview-calculate').text(Joomla.JText._('VBRATESOVWRATESCALCULATORCALC')).prop('disabled', false);
alert("Error Performing Ajax Request");
}
);
});
/* Orphans Calculation */
vboCheckOrphans();
//
});
function vboCheckOrphans() {
/* Orphans Calculation - Start */
var calc_method = '<?php echo VikBooking::orphansCalculation(); ?>';
jQuery('table.vbratesoverviewtable').each(function() {
var current_room = jQuery(this).attr('data-idroom');
var orphans_pool = new Array;
var avcells = jQuery(this).find('tr.vbo-roverviewtableavrow').find('td');
var restrcells = jQuery(this).find('tr.vbo-roverviewtablerow-restrs').find('td');
avcells.each(function(k, v) {
if (!jQuery(v).attr('data-curunits')) {
// continue
return true;
}
var todayav = parseInt(jQuery(v).attr('data-curunits'));
if (!restrcells.hasOwnProperty(k) || isNaN(todayav) || todayav < 1) {
// continue, no restriction cell found or no availability for this day
return true;
}
var todayminlos = parseInt(jQuery(restrcells[k]).find('.vbo-roverw-curminlos').text());
if (isNaN(todayminlos) || todayminlos < 2) {
// continue, no min los > 1 set for this day
return true;
}
// check if any night after today, until min los, is fully booked
var cell_queue = new Array;
var hasorphans = false;
var forward_count = 0;
cell_queue.push(v);
for (var i = 1; i < todayminlos; i++) {
if (!avcells.hasOwnProperty((k + i))) {
// break loop, no info for this day after
break;
}
var tomorrowav = parseInt(jQuery(avcells[(k + i)]).attr('data-curunits'));
if (isNaN(tomorrowav) || tomorrowav != 0) {
// continue, availability found for tomorrow, we need a non available next-day
continue;
}
// orphan found for this day
hasorphans = true;
forward_count = i;
break;
}
// backward calculation method only if "prevnext".
var backward_count = 0;
for (var i = 1; i <= todayminlos; i++) {
if (!avcells.hasOwnProperty((k - i))) {
// break loop, no info for this prev day
break;
}
var yesterdayav = parseInt(jQuery(avcells[(k - i)]).attr('data-curunits'));
if (isNaN(yesterdayav) || yesterdayav != 0) {
// increase free nights going backward
backward_count++;
}
}
if (calc_method == 'prevnext' && hasorphans && backward_count > 0 && (backward_count >= todayminlos || (backward_count + forward_count) >= todayminlos)) {
// this should not be an orphan date because of enough free days back, or enough free days in between
hasorphans = false;
}
if (hasorphans && cell_queue.length) {
for (var i in cell_queue) {
if (cell_queue.hasOwnProperty(i)) {
// push the cell
orphans_pool.push(cell_queue[i]);
}
}
}
});
if (orphans_pool.length) {
var orphans_list = '';
for (var i in orphans_pool) {
if (!orphans_pool.hasOwnProperty(i)) {
continue;
}
var idparts = jQuery(orphans_pool[i]).attr('id').split('-');
orphans_list += '<div class="vbo-ratesoverview-orphan-dt" data-dt="'+idparts[1]+'-'+idparts[2]+'-'+idparts[3]+'-'+current_room+'">'+vbowdays[idparts[4]]+', '+vbomonths[(parseInt(idparts[2]) - 1)]+' '+idparts[1]+' '+idparts[3]+'</div>';
}
jQuery('#vbo-ratesoverview-orphans-list-'+current_room).html(orphans_list);
jQuery('#vbo-ratesoverview-orphans-wrapper-'+current_room).fadeIn();
}
});
/* Orphans Calculation - End */
}
</script>
<div class="vbo-ratesoverview-fests-helper" style="display: none;">
<div class="vbo-ratesoverview-fests-wrap">
<div class="vbo-overlay-fests-list"></div>
<div class="vbo-overlay-fests-addnew" data-ymd="">
<h4><?php echo JText::translate('VBOADDCUSTOMFESTTODAY'); ?></h4>
<div class="vbo-overlay-fests-addnew-elem">
<label for="vbo-newfest-name"><?php echo JText::translate('VBPVIEWPLACESONE'); ?></label>
<input type="text" id="vbo-newfest-name" value="" />
</div>
<div class="vbo-overlay-fests-addnew-elem">
<label for="vbo-newfest-descr"><?php echo JText::translate('VBPLACEDESCR'); ?></label>
<textarea id="vbo-newfest-descr"></textarea>
</div>
</div>
</div>
</div>