PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.1
VikBooking Hotel Booking Engine & PMS v1.7.1
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / admin / views / ratesoverv / tmpl / default.php

default.php in VikBooking Hotel Booking Engine & PMS 1.7.1, at admin/views/ratesoverv/tmpl/default.php

2,968 lines 116.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 $all_rooms = $this->all_rooms;
14 $categories = $this->categories;
15 $roomrows = $this->roomrows;
16 $seasoncal_nights = $this->seasons_cal_nights;
17 $seasons_cal = $this->seasons_cal;
18 $tsstart = $this->tsstart;
19 $roomrates = $this->roomrates;
20
21 // JS lang defs
22 JText::script('VBO_BOOKNOW');
23 JText::script('VBPVIEWORDERSTHREE');
24 JText::script('VBEDITORDERTHREE');
25 JText::script('VBDAYS');
26 JText::script('VBDAY');
27 JText::script('VBMAILADULTS');
28 JText::script('VBMAILADULT');
29 JText::script('VBMAILCHILDREN');
30 JText::script('VBMAILCHILD');
31 JText::script('VBO_MISSING_SUBUNIT');
32 JText::script('VBRATESOVWRATESCALCULATORCALC');
33 JText::script('VBRATESOVWRATESCALCULATORCALCING');
34 JText::script('VBOVCMRATESRES');
35 JText::script('VBO_IS_DERIVED_RATE');
36 JText::script('VBO_PLEASE_FILL_FIELDS');
37 JText::script('VBO_RATES_AND_RESTR');
38 JText::script('VBSAVE');
39 JText::script('VBANNULLA');
40 JText::script('VBAPPLY');
41
42 $document = JFactory::getDocument();
43
44 $vbo_app = VikBooking::getVboApplication();
45 $vbo_app->loadSelect2();
46 $vbo_app->loadDatePicker();
47
48 $pdebug = VikRequest::getint('e4j_debug', '', 'request');
49
50 $currencysymb = VikBooking::getCurrencySymb();
51 $vbo_df = VikBooking::getDateFormat();
52 $datesep = VikBooking::getDateSeparator();
53 $df = $vbo_df == "%d/%m/%Y" ? 'd/m/Y' : ($vbo_df == "%m/%d/%Y" ? 'm/d/Y' : 'Y/m/d');
54 $juidf = $vbo_df == "%d/%m/%Y" ? 'dd/mm/yy' : ($vbo_df == "%m/%d/%Y" ? 'mm/dd/yy' : 'yy/mm/dd');
55
56 $MAX_DAYS = $this->max_days;
57 $pcheckinh = 0;
58 $pcheckinm = 0;
59 $pcheckouth = 0;
60 $pcheckoutm = 0;
61 $timeopst = VikBooking::getTimeOpenStore();
62 if (is_array($timeopst)) {
63 $opent = VikBooking::getHoursMinutes($timeopst[0]);
64 $closet = VikBooking::getHoursMinutes($timeopst[1]);
65 $pcheckinh = $opent[0];
66 $pcheckinm = $opent[1];
67 $pcheckouth = $closet[0];
68 $pcheckoutm = $closet[1];
69 }
70
71 /**
72 * Check if season records should be pre-cached. Be aware
73 * of the hundreds of MBs of server's memory that could be used.
74 *
75 * @since 1.16.10 (J) - 1.6.10 (WP)
76 */
77 $cached_seasons = [];
78 $cmd_precache_seasons = JFactory::getApplication()->input->getInt('pre_cache_seasons');
79 $can_precache_seasons = $cmd_precache_seasons === 1 ? 1 : VBOFactory::getConfig()->getInt('pre_cache_seasons', 0);
80 if ($cmd_precache_seasons === 0 || $cmd_precache_seasons === 1) {
81 // update configuration record
82 VBOFactory::getConfig()->set('pre_cache_seasons', $cmd_precache_seasons);
83 $can_precache_seasons = $cmd_precache_seasons;
84 }
85 if ($can_precache_seasons) {
86 $from_info = getdate($tsstart);
87 $season_from_ts = mktime($pcheckinh, $pcheckinm, 0, $from_info['mon'], $from_info['mday'], $from_info['year']);
88 $season_to_ts = mktime($pcheckouth, $pcheckoutm, 0, $from_info['mon'], $from_info['mday'] + $MAX_DAYS, $from_info['year']);
89 $cached_seasons = VikBooking::getDateSeasonRecords($season_from_ts, $season_to_ts, $this->req_room_ids);
90 }
91
92 $mb_support = function_exists('mb_substr');
93 $short_wdays = [
94 JText::translate('VBSUNDAY'),
95 JText::translate('VBMONDAY'),
96 JText::translate('VBTUESDAY'),
97 JText::translate('VBWEDNESDAY'),
98 JText::translate('VBTHURSDAY'),
99 JText::translate('VBFRIDAY'),
100 JText::translate('VBSATURDAY'),
101 ];
102 $short_mons = [
103 JText::translate('VBMONTHONE'),
104 JText::translate('VBMONTHTWO'),
105 JText::translate('VBMONTHTHREE'),
106 JText::translate('VBMONTHFOUR'),
107 JText::translate('VBMONTHFIVE'),
108 JText::translate('VBMONTHSIX'),
109 JText::translate('VBMONTHSEVEN'),
110 JText::translate('VBMONTHEIGHT'),
111 JText::translate('VBMONTHNINE'),
112 JText::translate('VBMONTHTEN'),
113 JText::translate('VBMONTHELEVEN'),
114 JText::translate('VBMONTHTWELVE'),
115 ];
116 foreach ($short_wdays as $k => $v) {
117 if ($mb_support) {
118 $short_wdays[$k] = mb_substr($v, 0, 3, 'UTF-8');
119 } else {
120 $short_wdays[$k] = substr($v, 0, 3);
121 }
122 }
123 foreach ($short_mons as $k => $v) {
124 if ($mb_support) {
125 $short_mons[$k] = mb_substr($v, 0, 3, 'UTF-8');
126 } else {
127 $short_mons[$k] = substr($v, 0, 3);
128 }
129 }
130 $json_short_wdays = json_encode($short_wdays);
131 $json_short_mons = json_encode($short_mons);
132
133 $document->addScriptDeclaration(
134 <<<JS
135 var vboMapWdays = $json_short_wdays;
136 var vboMapMons = $json_short_mons;
137 JS
138 );
139
140 $price_types_show = true;
141 $los_show = true;
142 $cookie = JFactory::getApplication()->input->cookie;
143 $cookie_tab = $cookie->get('vboRovwRab', 'cal', 'string');
144 $collapse_status = $cookie->get('vboRovwColl', 0, 'int');
145
146 // access room helper to detect LOS rates
147 $room_helper = VBORoomHelper::getInstance();
148
149 // derived rate plans data
150 $derived_rates_info = [];
151 foreach (VikBooking::getAvailabilityInstance()->loadRatePlans() as $rate_plan) {
152 if ($rate_plan['derived_id'] && $rate_plan['derived_data']) {
153 $derived_rates_info[$rate_plan['id']] = $rate_plan;
154 }
155 }
156
157 ?>
158
159 <div class="vbo-ratesoverview-top-outer">
160 <div class="vbo-ratesoverview-top-outer-inner vbo-toggle-small">
161 <?php echo $vbo_app->printYesNoButtons('vbo_collapse', JText::translate('VBYES'), JText::translate('VBNO'), (!$collapse_status ? 1 : 0), 1, 0, "vboToggleCollapse();"); ?>
162 <span onclick="jQuery(this).parent().find('input').trigger('click');"><?php echo JText::translate('VBO_EXPAND'); ?></span>
163 </div>
164 </div>
165
166 <div class="vbo-ratesoverview-top-container<?php echo $collapse_status ? ' collapsed' : ''; ?>">
167 <div class="vbo-ratesoverview-roomsel-block">
168 <form method="get" action="index.php?option=com_vikbooking" name="vboratesovwform">
169 <input type="hidden" name="option" value="com_vikbooking" />
170 <input type="hidden" name="task" value="ratesoverv" />
171 <div class="vbo-ratesoverview-roomsel-entry vbo-ratesoverview-roomsel-entry-chrooms">
172 <label for="roomsel"><?php VikBookingIcons::e('bed'); ?> <?php echo JText::translate('VBPVIEWORDERSTHREE'); ?></label>
173 <select name="cid[]" <?php echo count($all_rooms) > 1 ? 'multiple="multiple"' : 'onchange="document.vboratesovwform.submit();"' ?> id="roomsel" style="min-width: 160px; max-width: 250px;">
174 <?php
175 foreach ($all_rooms as $room) {
176 ?>
177 <option value="<?php echo $room['id']; ?>"<?php echo in_array($room['id'], $this->req_room_ids) ? ' selected="selected"' : ''; ?>><?php echo $room['name']; ?></option>
178 <?php
179 }
180
181 /**
182 * Use the optgroup to separate rooms from categories in the
183 * drop down menu, only if all_rooms > 1 e categories > 1.
184 *
185 * @since 1.13
186 */
187 if (count($all_rooms) > 1 && count($categories) > 1) {
188 ?>
189 <optgroup label="<?php echo addslashes(JText::translate('VBOCATEGORYFILTER')); ?>">
190 <?php
191 foreach ($categories as $cat) {
192 // we use negative values for the IDs of the categories
193 $cat_id = ($cat['id'] - ($cat['id'] * 2));
194 ?>
195 <option value="<?php echo $cat_id; ?>"><?php echo (in_array($cat['id'], $this->reqcats) ? '- ' : '') . $cat['name']; ?></option>
196 <?php
197 }
198 ?>
199 </optgroup>
200 <?php
201 }
202 //
203 ?>
204 </select>
205 <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>
206 <?php
207 if (count($all_rooms) > 1 && count($all_rooms) < 50 && count($this->req_room_ids) < count($all_rooms)) {
208 // display select all rooms button
209 ?>
210 <div class="vbo-roverview-selall-rooms">
211 <button type="button" class="btn vbo-config-btn" onclick="vboSelectAllRooms(this);"><?php VikBookingIcons::e('layer-group'); ?> <?php echo JText::translate('VBOSELECTALL'); ?></button>
212 </div>
213 <?php
214 }
215 ?>
216 </div>
217 <div class="vbo-ratesoverview-roomsel-entry vbo-ratesoverview-roomsel-entry-calc">
218 <label for="checkindate" onclick="vboCheckCollapse();"><?php VikBookingIcons::e('calculator'); ?> <?php echo JText::translate('VBRATESOVWRATESCALCULATOR'); ?></label>
219 <div class="vbo-ratesoverview-roomsel-entry-calc-inner"<?php echo $collapse_status ? ' style="display: none;"' : ''; ?>>
220 <span class="vbo-ratesoverview-entryinline vbo-ratesoverview-rcalc-srooms">
221 <select name="roomselcalc" id="roomselcalc" style="max-width: 250px;">
222 <?php
223 foreach ($all_rooms as $room) {
224 ?>
225 <option value="<?php echo $room['id']; ?>"<?php echo $room['id'] == $roomrows[$this->firstroom]['id'] ? ' selected="selected"' : ''; ?>><?php echo $room['name']; ?></option>
226 <?php
227 }
228 ?>
229 </select>
230 </span>
231 <span class="vbo-ratesoverview-entryinline">
232 <div class="vbo-field-calendar">
233 <div class="input-append">
234 <input type="text" autocomplete="off" value="" class="vbo-roverv-rcalc-cal" size="10" id="checkindate" name="checkindate" placeholder="<?php echo JText::translate('VBPICKUPAT'); ?>" />
235 <button type="button" class="btn btn-secondary" id="checkindate-trig"><?php VikBookingIcons::e('calendar', 'icn-nomargin'); ?></button>
236 </div>
237 </div>
238 </span>
239 <span class="vbo-ratesoverview-entryinline">
240 <div class="vbo-field-calendar">
241 <div class="input-append">
242 <input type="text" autocomplete="off" value="" class="vbo-roverv-rcalc-cal" size="10" id="checkoutdate" name="checkoutdate" placeholder="<?php echo JText::translate('VBRELEASEAT'); ?>" />
243 <button type="button" class="btn btn-secondary" id="checkoutdate-trig"><?php VikBookingIcons::e('calendar', 'icn-nomargin'); ?></button>
244 </div>
245 </div>
246 </span>
247 <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>
248 <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>
249 <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>
250 <span class="vbo-ratesoverview-entryinline"><button type="button" class="btn vbo-config-btn" id="vbo-ratesoverview-calculate"><?php echo JText::translate('VBRATESOVWRATESCALCULATORCALC'); ?></button></span>
251 </div>
252
253 <div class="vbo-ratesoverview-calculation-response"></div>
254
255 </div>
256 <div class="vbo-ratesoverview-roomsel-entry vbo-ratesoverview-roomsel-entry-forecast"<?php echo (!empty($cookie_tab) && $cookie_tab != 'cal' ? ' style="display: none;"' : ''); ?>>
257 <label onclick="vboCheckCollapse();"><?php VikBookingIcons::e('cloud-sun-rain'); ?> <?php echo JText::translate('VBOFORECAST'); ?></label>
258 <div class="vbo-roverv-forecast-inner"<?php echo $collapse_status ? ' style="display: none;"' : ''; ?>>
259 <?php echo JLayoutHelper::render('reports.occupancy', array('vbo_page' => 'ratesoverv', 'room_ids' => $this->req_room_ids)); ?>
260 </div>
261 </div>
262 <div class="vbo-ratesoverview-roomsel-entry vbo-ratesoverview-roomsel-entry-los"<?php echo (!empty($cookie_tab) && $cookie_tab == 'cal' ? ' style="display: none;"' : ''); ?>>
263 <label><?php echo JText::translate('VBRATESOVWNUMNIGHTSACT'); ?></label>
264 <?php
265 foreach ($seasoncal_nights as $numnights) {
266 ?>
267 <span class="vbo-ratesoverview-numnight" id="numnights<?php echo $numnights; ?>"><?php echo $numnights; ?></span>
268 <input type="hidden" name="nights_cal[]" id="inpnumnights<?php echo $numnights; ?>" value="<?php echo $numnights; ?>" />
269 <?php
270 }
271 ?>
272 <input type="number" id="vbo-addnumnight" value="<?php echo isset($numnights) ? ($numnights + 1) : 1; ?>" min="1"/>
273 <span id="vbo-addnumnight-act"><?php VikBookingIcons::e('plus-square'); ?></span>
274 <button type="button" class="btn vbo-config-btn vbo-apply-los-btn" onclick="document.vboratesovwform.submit();"><?php echo JText::translate('VBRATESOVWAPPLYLOS'); ?></button>
275 </div>
276 </form>
277 </div>
278 <div class="vbo-ratesoverview-right-block">
279 <div class="vbo-ratesoverview-right-inner"></div>
280 </div>
281 </div>
282
283 <div class="vbo-ratesoverview-bottom-container">
284 <?php
285 foreach ($roomrows as $rid => $roomrow) {
286 if (count($this->req_room_ids) < 2) {
287 ?>
288 <div class="vbo-ratesoverview-bottom-head">
289 <div class="vbo-ratesoverview-roomdetails">
290 <h3 class="vbo-ratesoverview-roomname"><?php echo $roomrow['name']; ?></h3>
291 </div>
292 <div class="vbo-ratesoverview-tabscont">
293 <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>
294 <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>
295 </div>
296 </div>
297 <?php
298 }
299 ?>
300
301 <div class="vbo-ratesoverview-caltab-cont" style="display: <?php echo count($this->req_room_ids) > 1 || (!empty($cookie_tab) && $cookie_tab == 'cal') ? 'block' : 'none'; ?>;">
302 <?php
303 if (count($this->req_room_ids) > 1) {
304 // display room name here when multiple rooms as well as the OBP toggle
305 if (!isset($vbo_show_toggle_obp)) {
306 // toggle button for showing/hiding the occupancy based pricing rules
307 $vbo_show_toggle_obp = 1;
308 $obp_status = $cookie->get('vboRovwObp', 1, 'int');
309 ?>
310 <div class="vbo-ratesoverview-obp-toggle" data-obpstartstatus="<?php echo $obp_status; ?>" style="display: none;">
311 <div class="vbo-ratesoverview-obp-toggle-inner vbo-toggle-small">
312 <?php echo $vbo_app->printYesNoButtons('show_obp', JText::translate('VBYES'), JText::translate('VBNO'), $obp_status, 1, 0, "vboToggleOBPRows();"); ?>
313 <span class="vbo-ratesoverview-obp-toggle-txt" onclick="jQuery(this).parent().find('input').trigger('click');"><?php echo JText::translate('VBOROVERVOBP'); ?></span>
314 </div>
315 </div>
316 <?php
317 }
318 ?>
319 <div class="vbo-ratesoverview-roomdetails">
320 <h3 class="vbo-ratesoverview-roomname" data-idroom="<?php echo $roomrow['id']; ?>"><?php echo $roomrow['name']; ?></h3>
321 </div>
322 <?php
323 } else {
324 // room name node is needed for JS
325 ?>
326 <div class="vbo-ratesoverview-roomdetails" style="display: none;">
327 <h3 class="vbo-ratesoverview-roomname" data-idroom="<?php echo $roomrow['id']; ?>"><?php echo $roomrow['name']; ?></h3>
328 </div>
329 <?php
330 }
331 ?>
332 <div class="vbo-ratesoverview-caltab-wrapper">
333 <div class="vbo-table-responsive">
334 <table class="vboverviewtable vbratesoverviewtable vbo-table" data-idroom="<?php echo $rid; ?>">
335 <tbody>
336 <tr class="vbo-roverviewrowone">
337 <td class="bluedays skip-bluedays-click">
338 <form name="vbratesoverview" method="post" action="index.php?option=com_vikbooking&amp;task=ratesoverv">
339 <div class="vbo-roverview-datecmd-top">
340 <div class="vbo-roverview-datecmd-date">
341 <span>
342 <?php VikBookingIcons::e('calendar'); ?>
343 <input type="text" autocomplete="off" value="<?php echo date($df, $tsstart); ?>" class="vbodatepicker" name="startdate" />
344 </span>
345 </div>
346 </div>
347 </form>
348 </td>
349 <?php
350 $nowts = getdate($tsstart);
351 $days_labels = array(
352 JText::translate('VBSUN'),
353 JText::translate('VBMON'),
354 JText::translate('VBTUE'),
355 JText::translate('VBWED'),
356 JText::translate('VBTHU'),
357 JText::translate('VBFRI'),
358 JText::translate('VBSAT')
359 );
360 $long_days_labels = array(
361 JText::translate('VBSUNDAY'),
362 JText::translate('VBMONDAY'),
363 JText::translate('VBTUESDAY'),
364 JText::translate('VBWEDNESDAY'),
365 JText::translate('VBTHURSDAY'),
366 JText::translate('VBFRIDAY'),
367 JText::translate('VBSATURDAY')
368 );
369 $months_labels = array(
370 JText::translate('VBMONTHONE'),
371 JText::translate('VBMONTHTWO'),
372 JText::translate('VBMONTHTHREE'),
373 JText::translate('VBMONTHFOUR'),
374 JText::translate('VBMONTHFIVE'),
375 JText::translate('VBMONTHSIX'),
376 JText::translate('VBMONTHSEVEN'),
377 JText::translate('VBMONTHEIGHT'),
378 JText::translate('VBMONTHNINE'),
379 JText::translate('VBMONTHTEN'),
380 JText::translate('VBMONTHELEVEN'),
381 JText::translate('VBMONTHTWELVE')
382 );
383 $long_months_labels = $months_labels;
384 foreach ($months_labels as $i => $v) {
385 $months_labels[$i] = function_exists('mb_substr') ? mb_substr($v, 0, 3, 'UTF-8') : substr($v, 0, 3);
386 }
387 $cell_count = 0;
388 $weekend_arr = array(0, 6);
389 while ($cell_count < $MAX_DAYS) {
390 $style = '';
391 $curdayymd = date('Y-m-d', $nowts[0]);
392 $read_day = $days_labels[$nowts['wday']] . ' ' . $nowts['mday'] . ' ' . $months_labels[$nowts['mon']-1] . ' ' . $nowts['year'];
393
394 $cell_classes = array(
395 'bluedays',
396 'cell-' . $nowts['mday'] . '-' . $nowts['mon'],
397 );
398
399 /**
400 * Critical dates defined at room-day level.
401 *
402 * @since 1.13.5
403 */
404 $rdaynote_keyid = $curdayymd . '_' . $rid . '_0';
405 $rdaynote_icn = '';
406 if (isset($this->rdaynotes[$rdaynote_keyid])) {
407 // note exists for this combination of date, room ID and subunit
408 array_push($cell_classes, 'vbo-roverw-roomdaynote-full');
409 $rdaynote_icn = '<i class="' . VikBookingIcons::i('sticky-note') . '"></i>';
410 }
411 //
412
413 if (in_array((int)$nowts['wday'], $weekend_arr)) {
414 array_push($cell_classes, 'vbo-roverw-tablewday-wend');
415 }
416 if (isset($this->festivities[$curdayymd])) {
417 array_push($cell_classes, 'vbo-roverv-festcell');
418 }
419 ?>
420 <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; ?>>
421 <?php
422 if (!empty($rdaynote_icn)) {
423 ?>
424 <span class="vbo-roverw-roomdaynote-icn"><?php echo $rdaynote_icn; ?></span>
425 <?php
426 }
427 ?>
428 <span class="vbo-roverw-tablewday"><?php echo $days_labels[$nowts['wday']]; ?></span>
429 <span class="vbo-roverw-tablemday"><?php echo $nowts['mday']; ?></span>
430 <span class="vbo-roverw-tablemonth"><?php echo $months_labels[$nowts['mon']-1]; ?></span>
431 </td>
432 <?php
433 $next = $nowts['mday'] + 1;
434 $dayts = mktime(0, 0, 0, $nowts['mon'], $next, $nowts['year']);
435 $nowts = getdate($dayts);
436 $cell_count++;
437 }
438 ?>
439 <td class="vbo-roverv-gonext-cell" data-rid="<?php echo $rid; ?>" rowspan="<?php echo count($roomrates[$rid]) + 3; ?>">
440 <div class="vbo-roverv-gonext-cell-inner">
441 <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>
442 </div>
443 </td>
444 </tr>
445 <?php
446 $room_obp_overrides = [];
447 $closed_roomrateplans = VikBooking::getRoomRplansClosingDates($roomrow['id']);
448 foreach ($roomrates[$rid] as $roomrate) {
449 $nowts = getdate($tsstart);
450 $cell_count = 0;
451 $rplan_minlos = !empty($roomrate['minlos']) && $roomrate['minlos'] > 0 ? $roomrate['minlos'] : 0;
452 $rplan_haslos = $room_helper->hasLosRecords($roomrate['idroom'], $roomrate['idprice'], true);
453
454 // check for derived rate plans
455 $derived_str = '';
456 $derived_icn = '';
457 if (isset($derived_rates_info[$roomrate['idprice']])) {
458 // build derived info string
459 $derived_data = $derived_rates_info[$roomrate['idprice']]['derived_data'] ?? [];
460 $derived_str .= ($derived_rates_info[$roomrate['idprice']]['parent_rate_name'] ?? '') . ' ';
461 $derived_str .= ($derived_data['type'] ?? 'percent') == 'absolute' ? $currencysymb . ' ' : '';
462 $derived_str .= ($derived_data['mode'] ?? 'discount') == 'discount' ? '-' : '+';
463 $derived_str .= $derived_data['value'] ?? 0;
464 $derived_str .= ($derived_data['type'] ?? 'percent') == 'percent' ? ' %' : '';
465 // set derived icon
466 $derived_icn = '<span class="badge badge-warning"><i class="' . VikBookingIcons::i('link') . '"></i></span> ';
467 }
468 ?>
469 <tr class="vbo-roverviewtablerow" id="vbo-roverw-<?php echo $roomrate['id'].'-'.$roomrate['idroom']; ?>">
470 <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']); ?>">
471 <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>
472 <?php
473 if ($rplan_minlos || $rplan_haslos) {
474 ?>
475 <div class="vbo-roverv-rplan-restrictions<?php echo $rplan_haslos ? ' vbo-roverv-rplan-haslosrates' : ''; ?>">
476 <?php
477 if ($rplan_haslos) {
478 ?>
479 <span class="badge badge-info vbo-roverv-rplan-restrictions-los">LOS</span>
480 <?php
481 }
482 if ($rplan_minlos) {
483 ?>
484 <span class="vbo-roverv-rplan-restrictions-lbl"><?php echo JText::translate('VBOMINIMUMSTAY'); ?></span>
485 <span class="vbo-roverv-rplan-restrictions-val"><?php echo $rplan_minlos; ?></span>
486 <?php
487 }
488 ?>
489 </div>
490 <?php
491 }
492 ?>
493 </td>
494 <?php
495 while ($cell_count < $MAX_DAYS) {
496 $style = '';
497 $dclass = "vbo-roverw-rplan-on";
498 if (count($closed_roomrateplans) > 0 && array_key_exists($roomrate['idprice'], $closed_roomrateplans) && in_array(date('Y-m-d', $nowts[0]), $closed_roomrateplans[$roomrate['idprice']])) {
499 $dclass = "vbo-roverw-rplan-off";
500 }
501 $id_block = "cell-".$nowts['mday'].'-'.$nowts['mon']."-".$nowts['year']."-".$roomrate['idprice']."-".$roomrate['idroom'];
502 $dclass .= ' day-block';
503
504 $today_tsin = mktime($pcheckinh, $pcheckinm, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
505 $today_tsout = mktime($pcheckouth, $pcheckoutm, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
506
507 $tars = VikBooking::applySeasonsRoom([$roomrate], $today_tsin, $today_tsout, [], $cached_seasons);
508
509 // store the OBP overrides for this day and rate plan
510 if (!empty($tars[0]['occupancy_ovr'])) {
511 if (!isset($room_obp_overrides[$nowts[0]])) {
512 $room_obp_overrides[$nowts[0]] = [];
513 }
514 $room_obp_overrides[$nowts[0]][] = [
515 'idprice' => $roomrate['idprice'],
516 'obp' => $tars[0]['occupancy_ovr'],
517 ];
518 }
519
520 ?>
521 <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; ?>>
522 <span class="vbo-rplan-currency"><?php echo $currencysymb; ?></span>
523 <span class="vbo-rplan-price"><?php echo $tars[0]['cost']; ?></span>
524 </td>
525 <?php
526
527 $next = $nowts['mday'] + 1;
528 $dayts = mktime(0, 0, 0, $nowts['mon'], $next, $nowts['year']);
529 $nowts = getdate($dayts);
530
531 $cell_count++;
532 }
533 ?>
534 </tr>
535 <?php
536 }
537
538 // Occupancy Based Pricing rules
539 $adultsdiff = array_reverse(VikBooking::loadRoomAdultsDiff($roomrow['id']), true);
540
541 // display the room OBP rules (must be defined at room-level or no overrides will be displayed)
542 foreach ($adultsdiff as $adults => $diffusageprice) {
543 $base_obp_rules = $diffusageprice;
544 $nowts = getdate($tsstart);
545 $cell_count = 0;
546 ?>
547 <tr class="vbo-roverviewtablerow-occupancy">
548 <td>
549 <span class="vbo-rplan-name vbo-rplan-name-occ">
550 <span><?php echo JText::translate('VBPVIEWOPTIONALSTHREE'); ?></span>
551 <span class="vbo-occ-label"><?php VikBookingIcons::e('male'); ?> x <?php echo $adults ?></span>
552 </span>
553 </td>
554 <?php
555 while ($cell_count < $MAX_DAYS) {
556 $style = '';
557 $dclass = "vbo-roverw-rplan-occ";
558
559 // check for OBP overrides
560 $compare_obp_ovr = [];
561 if (isset($room_obp_overrides[$nowts[0]]) && count($room_obp_overrides[$nowts[0]]) === count($roomrates[$rid])) {
562 // the OBP overrides affect all room rate plans, make sure the overrides are identical though
563 $compare_obp_ovr = $room_obp_overrides[$nowts[0]][0]['obp'];
564 foreach ($room_obp_overrides[$nowts[0]] as $room_obp_override) {
565 if ($compare_obp_ovr != $room_obp_override['obp']) {
566 // this OBP override does not match the first one
567 $compare_obp_ovr = [];
568 break;
569 }
570 }
571 }
572 if ($compare_obp_ovr && isset($compare_obp_ovr[$adults])) {
573 // display the OBP override value for this day
574 $diffusageprice = $compare_obp_ovr[$adults];
575 } else {
576 // display the OBP rules at room-level
577 $diffusageprice = $base_obp_rules;
578 }
579
580 if (($diffusageprice['value'] - floor($diffusageprice['value'])) <= 0) {
581 $diffusageprice['value'] = intval($diffusageprice['value']);
582 }
583
584 if ($diffusageprice['chdisc'] == 1) {
585 // charge
586 if ($diffusageprice['valpcent'] == 1) {
587 // fixed value
588 $occ_diff = '+ ' . $currencysymb . ' ' . $diffusageprice['value'];
589 } else {
590 // percentage value
591 $occ_diff = '+ ' . $diffusageprice['value'] . '%';
592 }
593 } else {
594 // discount
595 if ($diffusageprice['valpcent'] == 1) {
596 // fixed value
597 $occ_diff = '- ' . $currencysymb . ' ' . $diffusageprice['value'];
598 } else {
599 // percentage value
600 $occ_diff = '- ' . $diffusageprice['value'] . '%';
601 }
602 }
603
604 ?>
605 <td align="center" class="<?php echo $dclass; ?>"<?php echo $style; ?>>
606 <span class="vbo-roverv-priceoccdiff"><?php echo $occ_diff; ?></span>
607 </td>
608 <?php
609
610 $next = $nowts['mday'] + 1;
611 $dayts = mktime(0, 0, 0, $nowts['mon'], $next, $nowts['year']);
612 $nowts = getdate($dayts);
613
614 $cell_count++;
615 }
616 ?>
617 </tr>
618 <?php
619 }
620 ?>
621 <tr class="vbo-roverviewtableavrow">
622 <td><span class="vbo-roverview-roomunits"><?php echo $roomrow['units']; ?></span><span class="vbo-roverview-uleftlbl"><?php echo JText::translate('VBPCHOOSEBUSYCAVAIL'); ?></span></td>
623 <?php
624 $nowts = getdate($tsstart);
625 $cell_count = 0;
626 $last_booking_info = [];
627 $last_booking_tag = [];
628 while ($cell_count < $MAX_DAYS) {
629 $style = '';
630 $dclass = "vbo-roverw-daynotbusy";
631 $id_block = "cell-".$nowts['mday'].'-'.$nowts['mon']."-".$nowts['year']."-".$nowts['wday']."-".$rid."-avail";
632
633 $totfound = 0;
634 $last_bid = 0;
635 $bids_pool = [];
636
637 if (isset($this->booked_dates[$roomrow['id']]) && $this->booked_dates[$roomrow['id']]) {
638 foreach ($this->booked_dates[$roomrow['id']] as $b) {
639 $tmpone = getdate($b['checkin']);
640 $ritts = mktime(0, 0, 0, $tmpone['mon'], $tmpone['mday'], $tmpone['year']);
641 $tmptwo = getdate($b['checkout']);
642 $conts = mktime(0, 0, 0, $tmptwo['mon'], $tmptwo['mday'], $tmptwo['year']);
643 if ($nowts[0] >= $ritts && $nowts[0] < $conts) {
644 $dclass = "vbo-roverw-daybusy";
645 $last_bid = $b['idorder'];
646 $totfound++;
647 // push bid to pool
648 $bid_str = '-' . $b['idorder'] . '-';
649 if (!in_array($bid_str, $bids_pool)) {
650 $bids_pool[] = $bid_str;
651 }
652 }
653 }
654 }
655
656 $units_remaining = $roomrow['units'] - $totfound;
657 if ($units_remaining > 0 && $units_remaining < $roomrow['units'] && $roomrow['units'] > 1) {
658 $dclass .= " vbo-roverw-daybusypartially";
659 } elseif ($units_remaining <= 0 && $roomrow['units'] <= 1 && !empty($last_bid)) {
660 // Booking color tag
661 $btag_style = '';
662 $binfo = ($last_booking_info['data'] ?? null) && ($last_booking_info['id'] ?? null) == $last_bid ? $last_booking_info['data'] : VikBooking::getBookingInfoFromID($last_bid);
663 if ($binfo) {
664 $bcolortag = ($last_booking_tag['data'] ?? null) && ($last_booking_tag['id'] ?? null) == $last_bid ? $last_booking_tag['data'] : VikBooking::applyBookingColorTag($binfo);
665 if ($bcolortag) {
666 // set values
667 $bcolortag['name'] = JText::translate($bcolortag['name']);
668 $btag_style = "background-color: ".$bcolortag['color']."; color: ".(array_key_exists('fontcolor', $bcolortag) ? $bcolortag['fontcolor'] : '#ffffff').";";
669 $dclass .= ' vbo-roverw-hascolortag';
670 // cache data to avoid duplicate queries
671 $last_booking_info = [
672 'id' => $last_bid,
673 'data' => $binfo,
674 ];
675 $last_booking_tag = [
676 'id' => $last_bid,
677 'data' => $bcolortag,
678 ];
679 }
680 }
681 if (!empty($btag_style)) {
682 $style = !empty($style) ? ' style="display: none; '.$btag_style.'"' : ' style="'.$btag_style.'"';
683 $style .= ' title="'.addslashes($bcolortag['name']).'"';
684 }
685 }
686
687 ?>
688 <td align="center" class="<?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']; ?>"<?php echo $style; ?>>
689 <span class="vbo-roverw-curunits"><?php echo $units_remaining; ?></span>
690 </td>
691 <?php
692
693 $next = $nowts['mday'] + 1;
694 $dayts = mktime(0, 0, 0, ($nowts['mon'] < 10 ? "0".$nowts['mon'] : $nowts['mon']), ($next < 10 ? "0".$next : $next), $nowts['year']);
695 $nowts = getdate($dayts);
696
697 $cell_count++;
698 }
699 ?>
700 </tr>
701 <?php
702 // VBO 1.11 - MinLOS restrictions row
703 ?>
704 <tr class="vbo-roverviewtablerow-restrs">
705 <td><span class="vbo-roverview-restrs"><?php echo JText::translate('VBOMINIMUMSTAY'); ?></span></td>
706 <?php
707 $nowts = getdate($tsstart);
708 $cell_count = 0;
709 $glob_minlos = VikBooking::getDefaultNightsCalendar();
710 $glob_minlos = $glob_minlos < 1 ? 1 : $glob_minlos;
711 while ($cell_count < $MAX_DAYS) {
712 $style = '';
713 $dclass = "vbo-roverw-rplan-restr";
714
715 $id_block = "cell-".$nowts['mday'].'-'.$nowts['mon']."-".$nowts['year']."-".$rid."-restr";
716
717 $today_tsin = mktime(0, 0, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
718 $today_tsout = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
719
720 $restr = VikBooking::parseSeasonRestrictions($today_tsin, $today_tsout, 1, (isset($this->all_restrictions[$rid]) ? $this->all_restrictions[$rid] : array()));
721 $minlos = count($restr) ? $restr['minlos'] : $glob_minlos;
722
723 ?>
724 <td align="center" class="<?php echo $dclass; ?>" id="<?php echo $id_block; ?>"<?php echo $style; ?>>
725 <span class="vbo-roverw-curminlos<?php echo $minlos > 1 ? ' vbo-roverw-curminlos-active' : ''; ?>"><?php echo $minlos; ?></span>
726 </td>
727 <?php
728
729 $next = $nowts['mday'] + 1;
730 $dayts = mktime(0, 0, 0, ($nowts['mon'] < 10 ? "0".$nowts['mon'] : $nowts['mon']), ($next < 10 ? "0".$next : $next), $nowts['year']);
731 $nowts = getdate($dayts);
732
733 $cell_count++;
734 }
735 ?>
736 </tr>
737 <?php
738 //
739 ?>
740 </tbody>
741 </table>
742 </div>
743 <div class="vbo-ratesoverview-period-container">
744 <div class="vbo-ratesoverview-period-inner">
745 <div class="vbo-ratesoverview-period-lbl">
746 <span><?php echo JText::translate('VBOROVWSELPERIOD'); ?></span>
747 </div>
748 <div class="vbo-ratesoverview-period-boxes">
749 <div class="vbo-ratesoverview-period-boxes-inner">
750 <div class="vbo-ratesoverview-period-box-left">
751 <div class="vbo-ratesoverview-period-box-lbl">
752 <span><?php echo JText::translate('VBOROVWSELPERIODFROM'); ?></span>
753 </div>
754 <div class="vbo-ratesoverview-period-box-val">
755 <div class="vbo-ratesoverview-period-from">
756 <span class="vbo-ratesoverview-period-wday"></span>
757 <span class="vbo-ratesoverview-period-mday"></span>
758 <span class="vbo-ratesoverview-period-month"></span>
759 </div>
760 <span class="vbo-ratesoverview-period-from-icon"><?php VikBookingIcons::e('calendar'); ?></span>
761 </div>
762 </div>
763 <div class="vbo-ratesoverview-period-box-right">
764 <div class="vbo-ratesoverview-period-box-lbl">
765 <span><?php echo JText::translate('VBOROVWSELPERIODTO'); ?></span>
766 </div>
767 <div class="vbo-ratesoverview-period-box-val">
768 <div class="vbo-ratesoverview-period-to">
769 <span class="vbo-ratesoverview-period-wday"></span>
770 <span class="vbo-ratesoverview-period-mday"></span>
771 <span class="vbo-ratesoverview-period-month"></span>
772 </div>
773 <span class="vbo-ratesoverview-period-to-icon"><?php VikBookingIcons::e('calendar'); ?></span>
774 </div>
775 </div>
776 </div>
777 <div class="vbo-ratesoverview-period-box-cals" style="display: none;">
778 <div class="vbo-ratesoverview-period-box-cals-inner">
779 <div class="vbo-ratesoverview-period-cal-left">
780 <h4><?php echo JText::translate('VBOROVWSELPERIODFROM'); ?></h4>
781 <div class="vbo-period-from" data-idroom="<?php echo $rid; ?>" data-roomname="<?php echo htmlspecialchars($roomrow['name']); ?>"></div>
782 <input type="hidden" class="vbo-period-from-val" value="" />
783 </div>
784 <div class="vbo-ratesoverview-period-cal-right">
785 <h4><?php echo JText::translate('VBOROVWSELPERIODTO'); ?></h4>
786 <div class="vbo-period-to" data-idroom="<?php echo $rid; ?>" data-roomname="<?php echo htmlspecialchars($roomrow['name']); ?>"></div>
787 <input type="hidden" class="vbo-period-to-val" value="" />
788 </div>
789 <div class="vbo-ratesoverview-period-cal-cmd">
790 <h4><?php echo JText::translate('VBOROVWSELRPLAN'); ?></h4>
791 <div class="vbo-ratesoverview-period-cal-cmd-inner">
792 <select class="vbo-selperiod-rplanid" onchange="vboUpdateRplan(this);">
793 <?php
794 foreach ($roomrates[$rid] as $krr => $roomrate) {
795 ?>
796 <option value="<?php echo $roomrate['idprice']; ?>" data-defrate="<?php echo $roomrate['cost']; ?>"<?php echo $krr < 1 ? ' selected="selected"' : ''; ?>><?php echo $roomrate['name']; ?></option>
797 <?php
798 }
799 ?>
800 </select>
801 </div>
802 </div>
803 </div>
804 </div>
805 </div>
806 </div>
807 <div class="vbo-ratesoverview-orphans-wrapper" id="vbo-ratesoverview-orphans-wrapper-<?php echo $rid; ?>" style="display: none;">
808 <div class="vbo-ratesoverview-orphans-lbl">
809 <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>
810 </div>
811 <div class="vbo-ratesoverview-orphans-list" id="vbo-ratesoverview-orphans-list-<?php echo $rid; ?>"></div>
812 </div>
813 </div>
814 </div>
815 </div>
816
817 <?php
818 // start los pricing overview IF statement for just 1 room
819 if (count($this->req_room_ids) < 2) :
820 ?>
821 <div class="vbo-ratesoverview-lostab-cont"<?php echo (!empty($cookie_tab) && $cookie_tab == 'cal' ? ' style="display: none;"' : ''); ?>>
822 <?php
823 if (count($seasons_cal) > 0) {
824 //Special Prices Timeline
825 if (isset($seasons_cal['seasons']) && count($seasons_cal['seasons'])) {
826 ?>
827 <div class="vbo-timeline-container">
828 <ul id="vbo-timeline">
829 <?php
830 foreach ($seasons_cal['seasons'] as $ks => $timeseason) {
831 $s_val_diff = '';
832 if ($timeseason['val_pcent'] == 2) {
833 //percentage
834 $s_val_diff = (($timeseason['diffcost'] - abs($timeseason['diffcost'])) > 0.00 ? VikBooking::numberFormat($timeseason['diffcost']) : intval($timeseason['diffcost']))." %";
835 } else {
836 //absolute
837 $s_val_diff = $currencysymb.''.VikBooking::numberFormat($timeseason['diffcost']);
838 }
839 $s_explanation = array();
840 if (empty($timeseason['year'])) {
841 $s_explanation[] = JText::translate('VBSEASONANYYEARS');
842 }
843 if (!empty($timeseason['losoverride'])) {
844 $s_explanation[] = JText::translate('VBSEASONBASEDLOS');
845 }
846 ?>
847 <li data-fromts="<?php echo $timeseason['from_ts']; ?>" data-tots="<?php echo $timeseason['to_ts']; ?>">
848 <input type="radio" name="timeline" class="vbo-timeline-radio" id="vbo-timeline-dot<?php echo $ks; ?>" <?php echo $ks === 0 ? 'checked="checked"' : ''; ?>/>
849 <div class="vbo-timeline-relative">
850 <label class="vbo-timeline-label" for="vbo-timeline-dot<?php echo $ks; ?>"><?php echo $timeseason['spname']; ?></label>
851 <span class="vbo-timeline-date"><?php echo VikBooking::formatSeasonDates($timeseason['from_ts'], $timeseason['to_ts']); ?></span>
852 <span class="vbo-timeline-circle" onclick="Javascript: jQuery('#vbo-timeline-dot<?php echo $ks; ?>').trigger('click');"></span>
853 </div>
854 <div class="vbo-timeline-content">
855 <p>
856 <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>
857 <br/>
858 <?php
859 if (count($s_explanation) > 0) {
860 echo implode(' - ', $s_explanation);
861 }
862 ?>
863 </p>
864 </div>
865 </li>
866 <?php
867 }
868 ?>
869 </ul>
870 </div>
871
872 <script>
873 jQuery(function() {
874 jQuery('.vbo-timeline-container').css('min-height', (jQuery('.vbo-timeline-container').outerHeight() + 20));
875 });
876 </script>
877 <?php
878 }
879 //
880 //Begin Seasons Calendar
881 ?>
882 <div class="table-responsive">
883 <table class="table vbo-seasons-calendar-table">
884 <tr class="vbo-seasons-calendar-nightsrow">
885 <td>&nbsp;</td>
886 <?php
887 foreach ($seasons_cal['offseason'] as $numnights => $ntars) {
888 ?>
889 <td><span><?php echo JText::sprintf(($numnights > 1 ? 'VBOSEASONCALNUMNIGHTS' : 'VBOSEASONCALNUMNIGHT'), $numnights); ?></span></td>
890 <?php
891 }
892 ?>
893 </tr>
894 <tr class="vbo-seasons-calendar-offseasonrow">
895 <td>
896 <span class="vbo-seasons-calendar-offseasonname"><?php echo JText::translate('VBOSEASONSCALOFFSEASONPRICES'); ?></span>
897 </td>
898 <?php
899 foreach ($seasons_cal['offseason'] as $numnights => $tars) {
900 ?>
901 <td>
902 <div class="vbo-seasons-calendar-offseasoncosts">
903 <?php
904 foreach ($tars as $tar) {
905 ?>
906 <div class="vbo-seasons-calendar-offseasoncost">
907 <?php
908 if ($price_types_show) {
909 ?>
910 <span class="vbo-seasons-calendar-pricename"><?php echo $tar['name']; ?></span>
911 <?php
912 }
913 ?>
914 <span class="vbo-seasons-calendar-pricecost">
915 <span class="vbo_currency"><?php echo $currencysymb; ?></span><span class="vbo_price"><?php echo VikBooking::numberFormat($tar['cost']); ?></span>
916 </span>
917 </div>
918 <?php
919 if (!$price_types_show) {
920 break;
921 }
922 }
923 ?>
924 </div>
925 </td>
926 <?php
927 }
928 ?>
929 </tr>
930 <?php
931 if (!isset($seasons_cal['seasons'])) {
932 $seasons_cal['seasons'] = array();
933 }
934 foreach ($seasons_cal['seasons'] as $s_id => $s) {
935 $restr_diff_nights = array();
936 if ($los_show && array_key_exists($s_id, $seasons_cal['restrictions'])) {
937 $restr_diff_nights = VikBooking::compareSeasonRestrictionsNights($seasons_cal['restrictions'][$s_id]);
938 }
939 $s_val_diff = '';
940 if ($s['val_pcent'] == 2) {
941 //percentage
942 $s_val_diff = (($s['diffcost'] - abs($s['diffcost'])) > 0.00 ? VikBooking::numberFormat($s['diffcost']) : intval($s['diffcost']))." %";
943 } else {
944 //absolute
945 $s_val_diff = $currencysymb.''.VikBooking::numberFormat($s['diffcost']);
946 }
947 ?>
948 <tr class="vbo-seasons-calendar-seasonrow">
949 <td>
950 <div class="vbo-seasons-calendar-seasondates">
951 <span class="vbo-seasons-calendar-seasonfrom"><?php echo date(str_replace("/", $datesep, $df), $s['from_ts']); ?></span>
952 <span class="vbo-seasons-calendar-seasondates-separe">-</span>
953 <span class="vbo-seasons-calendar-seasonto"><?php echo date(str_replace("/", $datesep, $df), $s['to_ts']); ?></span>
954 </div>
955 <div class="vbo-seasons-calendar-seasonchargedisc">
956 <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>
957 </div>
958 <span class="vbo-seasons-calendar-seasonname"><a href="index.php?option=com_vikbooking&amp;task=editseason&amp;cid[]=<?php echo $s['id']; ?>" target="_blank"><?php echo $s['spname']; ?></a></span>
959 <?php
960 if ($los_show && array_key_exists($s_id, $seasons_cal['restrictions']) && count($restr_diff_nights) == 0) {
961 //Season Restrictions
962 $season_restrictions = array();
963 foreach ($seasons_cal['restrictions'][$s_id] as $restr) {
964 $season_restrictions = $restr;
965 break;
966 }
967 ?>
968 <div class="vbo-seasons-calendar-restrictions">
969 <?php
970 if ($season_restrictions['minlos'] > 1) {
971 ?>
972 <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>
973 <?php
974 }
975 if (array_key_exists('maxlos', $season_restrictions) && $season_restrictions['maxlos'] > 1) {
976 ?>
977 <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>
978 <?php
979 }
980 if (array_key_exists('wdays', $season_restrictions) && count($season_restrictions['wdays']) > 0) {
981 ?>
982 <div class="vbo-seasons-calendar-restriction-wdays">
983 <label><?php echo JText::translate((count($season_restrictions['wdays']) > 1 ? 'VBORESTRARRIVWDAYS' : 'VBORESTRARRIVWDAY')); ?></label>
984 <?php
985 foreach ($season_restrictions['wdays'] as $wday) {
986 ?>
987 <span class="vbo-seasons-calendar-restriction-wday"><?php echo VikBooking::sayWeekDay($wday); ?></span>
988 <?php
989 }
990 ?>
991 </div>
992 <?php
993 } elseif ((array_key_exists('cta', $season_restrictions) && count($season_restrictions['cta']) > 0) || (array_key_exists('ctd', $season_restrictions) && count($season_restrictions['ctd']) > 0)) {
994 if (array_key_exists('cta', $season_restrictions) && count($season_restrictions['cta']) > 0) {
995 ?>
996 <div class="vbo-seasons-calendar-restriction-wdays vbo-seasons-calendar-restriction-cta">
997 <label><?php echo JText::translate('VBORESTRWDAYSCTA'); ?></label>
998 <?php
999 foreach ($season_restrictions['cta'] as $wday) {
1000 ?>
1001 <span class="vbo-seasons-calendar-restriction-wday"><?php echo VikBooking::sayWeekDay(str_replace('-', '', $wday)); ?></span>
1002 <?php
1003 }
1004 ?>
1005 </div>
1006 <?php
1007 }
1008 if (array_key_exists('ctd', $season_restrictions) && count($season_restrictions['ctd']) > 0) {
1009 ?>
1010 <div class="vbo-seasons-calendar-restriction-wdays vbo-seasons-calendar-restriction-ctd">
1011 <label><?php echo JText::translate('VBORESTRWDAYSCTD'); ?></label>
1012 <?php
1013 foreach ($season_restrictions['ctd'] as $wday) {
1014 ?>
1015 <span class="vbo-seasons-calendar-restriction-wday"><?php echo VikBooking::sayWeekDay(str_replace('-', '', $wday)); ?></span>
1016 <?php
1017 }
1018 ?>
1019 </div>
1020 <?php
1021 }
1022 }
1023 ?>
1024 </div>
1025 <?php
1026 }
1027 ?>
1028 </td>
1029 <?php
1030 if (array_key_exists($s_id, $seasons_cal['season_prices']) && count($seasons_cal['season_prices'][$s_id]) > 0) {
1031 foreach ($seasons_cal['season_prices'][$s_id] as $numnights => $tars) {
1032 $show_day_cost = true;
1033 if ($los_show && array_key_exists($s_id, $seasons_cal['restrictions']) && array_key_exists($numnights, $seasons_cal['restrictions'][$s_id])) {
1034 if ($seasons_cal['restrictions'][$s_id][$numnights]['allowed'] === false) {
1035 $show_day_cost = false;
1036 }
1037 }
1038 ?>
1039 <td>
1040 <?php
1041 if ($show_day_cost) {
1042 ?>
1043 <div class="vbo-seasons-calendar-seasoncosts">
1044 <?php
1045 foreach ($tars as $tar) {
1046 //print the types of price that are not being modified by this special price with opacity
1047 $not_affected = (!array_key_exists('origdailycost', $tar));
1048 //
1049 ?>
1050 <div class="vbo-seasons-calendar-seasoncost<?php echo ($not_affected ? ' vbo-seasons-calendar-seasoncost-notaffected' : ''); ?>">
1051 <?php
1052 if ($price_types_show) {
1053 ?>
1054 <span class="vbo-seasons-calendar-pricename"><?php echo $tar['name']; ?></span>
1055 <?php
1056 }
1057 ?>
1058 <span class="vbo-seasons-calendar-pricecost">
1059 <span class="vbo_currency"><?php echo $currencysymb; ?></span><span class="vbo_price"><?php echo VikBooking::numberFormat($tar['cost']); ?></span>
1060 </span>
1061 </div>
1062 <?php
1063 if (!$price_types_show) {
1064 break;
1065 }
1066 }
1067 ?>
1068 </div>
1069 <?php
1070 } else {
1071 ?>
1072 <div class="vbo-seasons-calendar-seasoncosts-disabled"></div>
1073 <?php
1074 }
1075 ?>
1076 </td>
1077 <?php
1078 }
1079 }
1080 ?>
1081 </tr>
1082 <?php
1083 }
1084 ?>
1085 </table>
1086 </div>
1087 <?php
1088 //End Seasons Calendar
1089 } else {
1090 ?>
1091 <p class="vbo-warning"><?php echo JText::translate('VBOWARNNORATESROOM'); ?></p>
1092 <?php
1093 }
1094 ?>
1095 </div>
1096 <?php
1097 // end los pricing overview IF statement for just 1 room
1098 endif;
1099 }
1100 ?>
1101 </div>
1102 <?php
1103
1104 // overlay modal to change rates, restrictions etc..
1105 $vcm_enabled = VikBooking::vcmAutoUpdate();
1106 ?>
1107 <div class="vbo-ratesoverview-newratesrestr-helper" style="display: none;">
1108 <div class="vbo-ratesoverview-newratesrestr-wrap">
1109 <div class="vbo-roverw-infoblock">
1110 <span id="rovervw-roomname"></span>
1111 <div class="vbo-roverw-inforates">
1112 <span id="rovervw-rplan"></span>
1113 <span id="rovervw-fromdate"></span> - <span id="rovervw-todate"></span>
1114 </div>
1115 </div>
1116 <div class="vbo-roverw-alldays">
1117 <div class="vbo-roverw-alldays-inner"></div>
1118 </div>
1119 <div class="vbo-roverw-setnewrate">
1120 <div class="vbo-roverw-setnewrate-title">
1121 <h4><?php VikBookingIcons::e('calculator'); ?> <?php echo JText::translate('VBO_RATES_AND_RESTR'); ?></h4>
1122 </div>
1123 <div class="vbo-roverw-flexnew">
1124 <div class="vbo-roverw-newrwrap">
1125 <h4><?php VikBookingIcons::e('edit'); ?> <?php echo JText::translate('VBRATESOVWSETNEWRATE'); ?></h4>
1126 <div class="vbo-roverw-newrcont">
1127 <label for="roverw-newrate" class="vbo-roverw-setnewrate-currency"><?php echo $currencysymb; ?></label>
1128 <input type="number" step="any" min="0" id="roverw-newrate" value="" placeholder="" size="7" />
1129 </div>
1130 </div>
1131 <div class="vbo-roverw-newrestr-wrap" style="display: none;">
1132 <div class="vbo-roverw-newrestrcont">
1133 <h4><?php VikBookingIcons::e('ban'); ?> <?php echo JText::translate('VBOMINIMUMSTAYSET'); ?></h4>
1134 <div class="vbo-roverw-newrestrcont-inner">
1135 <label for="roverw-newrestr" class="vbo-roverw-setnewrestr-lbl"><?php echo JText::translate('VBDAYS'); ?></label>
1136 <input type="number" step="1" min="0" id="roverw-newrestr" value="" size="7" />
1137 </div>
1138 </div>
1139 </div>
1140 </div>
1141 <div class="vbo-roverw-setnewrate-inner">
1142 <div class="vbo-roverw-setnewrate-vcm">
1143 <div class="vbo-roverw-setnewrate-vcm-head">
1144 <span class="<?php echo $vcm_enabled < 0 ? 'vbo-vcm-notinstalled' : 'vbo-vcm-installed'; ?>">
1145 <?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'))); ?>
1146 <?php echo JText::translate('VBOUPDRATESONCHANNELS'); ?>
1147 </span>
1148 </div>
1149 <div class="vbo-roverw-setnewrate-vcm-body">
1150 <label class="vbo-switch">
1151 <input type="checkbox" id="roverw-newrate-vcm" onchange="vboCheckVcmRestrictions();" value="1" <?php echo $vcm_enabled < 0 ? 'disabled="disabled"' : ($vcm_enabled > 0 ? 'checked="checked"' : ''); ?>/>
1152 <span class="vbo-slider<?php echo $vcm_enabled < 0 ? ' vbo-slider-disabled' : ''; ?> vbo-round"></span>
1153 </label>
1154 </div>
1155 </div>
1156 </div>
1157 </div>
1158 <div class="vbo-roverw-closeopenrp">
1159 <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>
1160 <div class="vbo-roverw-closeopenrp-btns">
1161 <button type="button" class="btn btn-danger" onclick="modRoomRatePlan('close');"><?php VikBookingIcons::e('lock'); ?> <?php echo JText::translate('VBRATESOVWCLOSERRP'); ?></button>
1162 <button type="button" class="btn btn-success" onclick="modRoomRatePlan('open');"><?php VikBookingIcons::e('lock-open'); ?> <?php echo JText::translate('VBRATESOVWOPENRRP'); ?></button>
1163 </div>
1164 </div>
1165 </div>
1166 </div>
1167
1168 <form name="adminForm" id="adminForm" action="index.php" method="post">
1169 <input type="hidden" name="task" value="">
1170 <input type="hidden" name="option" value="com_vikbooking">
1171 </form>
1172
1173 <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>
1174 <a class="vbo-basenavuri-details" href="index.php?option=com_vikbooking&task=editorder&goto=ratesoverv&cid[]=%d" style="display: none;"></a>
1175
1176 <script type="text/Javascript">
1177 function vboFormatCalDate(elem, idc) {
1178 var vb_period = elem.parent().find('.vbo-'+idc+'-val').val();
1179 if (!vb_period || !vb_period.length) {
1180 return false;
1181 }
1182 var vb_period_parts = vb_period.split("/");
1183 if ('%d/%m/%Y' == '<?php echo $vbo_df; ?>') {
1184 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);
1185 var data = [parseInt(vb_period_parts[0], 10), parseInt(vb_period_parts[1]), vb_period_parts[2]];
1186 } else if ('%m/%d/%Y' == '<?php echo $vbo_df; ?>') {
1187 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);
1188 var data = [parseInt(vb_period_parts[1], 10), parseInt(vb_period_parts[0]), vb_period_parts[2]];
1189 } else {
1190 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);
1191 var data = [parseInt(vb_period_parts[2], 10), parseInt(vb_period_parts[1]), vb_period_parts[0]];
1192 }
1193 var elcont = elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-ratesoverview-'+idc);
1194 elcont.find('.vbo-ratesoverview-period-wday').text(vboMapWdays[period_date.getDay()]);
1195 elcont.find('.vbo-ratesoverview-period-mday').text(period_date.getDate());
1196 elcont.find('.vbo-ratesoverview-period-month').text(vboMapMons[period_date.getMonth()]);
1197 elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-ratesoverview-'+idc+'-icon').hide();
1198 data.push(elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-selperiod-rplanid').val());
1199 data.push(elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-selperiod-rplanid option:selected').text());
1200 data.push(elem.closest('.vbo-ratesoverview-period-boxes').find('.vbo-selperiod-rplanid option:selected').attr('data-defrate'));
1201 data.push(elem.attr('data-idroom'));
1202 data.push(elem.attr('data-roomname'));
1203 var struct = getPeriodStructure(data);
1204 if (idc.indexOf('from') >= 0) {
1205 //period from date selected
1206 if (!vbolistener.pickFirst(struct)) {
1207 //first already picked: update it
1208 vbolistener.first = struct;
1209 }
1210 }
1211 if (idc.indexOf('to') >= 0) {
1212 //period to date selected
1213 if (!vbolistener.pickFirst(struct)) {
1214 //first already picked
1215 if ((vbolistener.first.isBeforeThan(struct) || vbolistener.first.isSameDay(struct)) && vbolistener.first.isSameRplan(struct) && vbolistener.first.isSameRoom(struct)) {
1216 //last > first: pick last
1217 if (vbolistener.pickLast(struct)) {
1218 showVboDialogPeriod();
1219 }
1220 }
1221 }
1222 }
1223 }
1224 function vbCalcNights() {
1225 var vbcheckin = document.getElementById('checkindate').value;
1226 var vbcheckout = document.getElementById('checkoutdate').value;
1227 if (!vbcheckin.length || !vbcheckout.length) {
1228 return;
1229 }
1230 var vbcheckinp = vbcheckin.split("-");
1231 var vbcheckoutp = vbcheckout.split("-");
1232 var vbinmonth = parseInt(vbcheckinp[1]);
1233 vbinmonth = vbinmonth - 1;
1234 var vbinday = parseInt(vbcheckinp[2], 10);
1235 var vbcheckind = new Date(vbcheckinp[0], vbinmonth, vbinday);
1236 var vboutmonth = parseInt(vbcheckoutp[1]);
1237 vboutmonth = vboutmonth - 1;
1238 var vboutday = parseInt(vbcheckoutp[2], 10);
1239 var vbcheckoutd = new Date(vbcheckoutp[0], vboutmonth, vboutday);
1240 var vbdivider = 1000 * 60 * 60 * 24;
1241 var vbints = vbcheckind.getTime();
1242 var vboutts = vbcheckoutd.getTime();
1243 if (vboutts > vbints) {
1244 var utc1 = Date.UTC(vbcheckind.getFullYear(), vbcheckind.getMonth(), vbcheckind.getDate());
1245 var utc2 = Date.UTC(vbcheckoutd.getFullYear(), vbcheckoutd.getMonth(), vbcheckoutd.getDate());
1246 var vbnights = Math.ceil((utc2 - utc1) / vbdivider);
1247 if (vbnights > 0) {
1248 jQuery('#vbo-numnights').val(vbnights);
1249 }
1250 }
1251 }
1252
1253 /**
1254 * Scrollable tables will show the arrows to navigate to the next N days.
1255 *
1256 * @since 1.15.0 (J) - 1.5.0 (WP)
1257 */
1258 function vboDisplayNextDays(btn) {
1259 var cell = jQuery(btn).closest('.vbo-roverv-gonext-cell');
1260 if (!cell || !cell.length) {
1261 return;
1262 }
1263 var rid = cell.attr('data-rid');
1264 if (!rid || !rid.length) {
1265 return;
1266 }
1267 var table = jQuery('table.vbratesoverviewtable[data-idroom="' + rid + '"]');
1268 if (!table || !table.length) {
1269 return;
1270 }
1271 // get the datepicker calendar instance for this room
1272 var calendar = table.find('input.vbodatepicker');
1273 try {
1274 // calculate the new date
1275 var cur_date = calendar.datepicker('getDate');
1276 var dobj = new Date(cur_date);
1277 dobj.setDate(dobj.getDate() + <?php echo $MAX_DAYS; ?>);
1278 // set the new date
1279 calendar.datepicker('setDate', dobj);
1280 // populate hidden form fields
1281 var parentform = calendar.closest('form');
1282 var roomsids = jQuery('#roomsel').val();
1283 if (roomsids) {
1284 if (!Array.isArray(roomsids)) {
1285 // if there is just one room type, the select is not multiple, so this is a string
1286 roomsids = [jQuery('#roomsel').val()];
1287 }
1288 jQuery.each(roomsids, function(k, v) {
1289 parentform.append('<input type="hidden" name="cid[]" value="' + v + '" />');
1290 });
1291 }
1292 // auto-submit form with new date
1293 parentform.submit();
1294 } catch(e) {
1295 console.error(e);
1296 alert('Calendar not found. Please change date manually.');
1297 }
1298 }
1299
1300 jQuery(function() {
1301 jQuery('.vbodatepicker').datepicker({
1302 showOn: 'focus',
1303 dateFormat: '<?php echo $juidf; ?>',
1304 minDate: '-1y',
1305 numberOfMonths: 2,
1306 changeMonth: true,
1307 changeYear: true,
1308 yearRange: '<?php echo (date('Y') - 1).':'.(date('Y') + 3); ?>',
1309 onSelect: function(selectedDate) {
1310 var parentform = jQuery(this).closest('form');
1311 var roomsids = jQuery('#roomsel').val();
1312 if (roomsids) {
1313 if (!Array.isArray(roomsids)) {
1314 // if there is just one room type, the select is not multiple, so this is a string
1315 roomsids = [jQuery('#roomsel').val()];
1316 }
1317 jQuery.each(roomsids, function(k, v) {
1318 parentform.append('<input type="hidden" name="cid[]" value="' + v + '" />');
1319 });
1320 }
1321 parentform.submit();
1322 }
1323 });
1324 jQuery('#checkindate').datepicker({
1325 showOn: 'focus',
1326 dateFormat: 'yy-mm-dd',
1327 minDate: '0d',
1328 numberOfMonths: 2,
1329 onSelect: function(selectedDate) {
1330 var nownights = parseInt(jQuery('#vbo-numnights').val());
1331 var nowcheckin = jQuery('#checkindate').datepicker('getDate');
1332 var nowcheckindate = new Date(nowcheckin.getTime());
1333 nowcheckindate.setDate(nowcheckindate.getDate() + nownights);
1334 jQuery('#checkoutdate').datepicker( 'option', 'minDate', nowcheckindate );
1335 jQuery('#checkoutdate').datepicker( 'setDate', nowcheckindate );
1336 vbCalcNights();
1337 }
1338 });
1339 jQuery('#checkoutdate').datepicker({
1340 showOn: 'focus',
1341 dateFormat: 'yy-mm-dd',
1342 minDate: '0d',
1343 numberOfMonths: 2,
1344 onSelect: function(selectedDate) {
1345 if (!jQuery('#checkoutdate').val().length) {
1346 return;
1347 }
1348 vbCalcNights();
1349 }
1350 });
1351 jQuery('#checkindate-trig, #checkoutdate-trig').click(function() {
1352 var jdp = jQuery(this).prev('input.hasDatepicker');
1353 if (jdp.length) {
1354 jdp.focus();
1355 }
1356 });
1357 jQuery('#vbo-numnights').on('change keyup', function() {
1358 if (!jQuery('#checkindate').length) {
1359 return;
1360 }
1361 var nownights = parseInt(jQuery(this).val());
1362 var nowcheckin = jQuery('#checkindate').datepicker('getDate');
1363 var nowcheckindate = new Date(nowcheckin.getTime());
1364 nowcheckindate.setDate(nowcheckindate.getDate() + nownights);
1365 jQuery('#checkoutdate').datepicker( 'option', 'minDate', nowcheckindate );
1366 jQuery('#checkoutdate').datepicker( 'setDate', nowcheckindate );
1367 });
1368 jQuery('.vbo-period-from').datepicker({
1369 dateFormat: '<?php echo $juidf; ?>',
1370 minDate: '0d',
1371 altField: '.vbo-period-from-val',
1372 onSelect: function(selectedDate) {
1373 jQuery(this).parent().find('.vbo-period-from-val').val(selectedDate);
1374 jQuery(this).closest('.vbo-ratesoverview-period-box-cals').find('.vbo-period-to').datepicker("option", "minDate", selectedDate);
1375 vboFormatCalDate(jQuery(this), 'period-from');
1376 }
1377 });
1378 jQuery('.vbo-period-to').datepicker({
1379 dateFormat: '<?php echo $juidf; ?>',
1380 minDate: '0d',
1381 altField: '.vbo-period-to-val',
1382 onSelect: function(selectedDate) {
1383 jQuery(this).parent().find('.vbo-period-to-val').val(selectedDate);
1384 jQuery(this).closest('.vbo-ratesoverview-period-box-cals').find('.vbo-period-from').datepicker("option", "maxDate", selectedDate);
1385 vboFormatCalDate(jQuery(this), 'period-to');
1386 }
1387 });
1388 jQuery('.vbo-ratesoverview-period-box-left, .vbo-ratesoverview-period-box-right').click(function() {
1389 jQuery(this).closest('.vbo-ratesoverview-period-boxes').find('.vbo-ratesoverview-period-box-cals').fadeToggle();
1390 });
1391 jQuery("#roomsel, #roomselcalc").select2();
1392 });
1393 <?php
1394 if ($df == "Y/m/d") {
1395 ?>
1396 Date.prototype.format = "yy/mm/dd";
1397 <?php
1398 } elseif ($df == "m/d/Y") {
1399 ?>
1400 Date.prototype.format = "mm/dd/yy";
1401 <?php
1402 } else {
1403 ?>
1404 Date.prototype.format = "dd/mm/yy";
1405 <?php
1406 }
1407 ?>
1408 Date.prototype.datesep = "<?php echo addslashes(VikBooking::getDateSeparator()); ?>";
1409 var currencysymb = '<?php echo $currencysymb; ?>';
1410 var debug_mode = '<?php echo $pdebug; ?>';
1411 var vcm_exists = <?php echo VikBooking::vcmAutoUpdate(); ?>;
1412 var roverw_messages = {
1413 "setNewRatesMissing": "<?php echo addslashes(JText::translate('VBRATESOVWERRNEWRATE')); ?>",
1414 "modRplansMissing": "<?php echo addslashes(JText::translate('VBRATESOVWERRMODRPLANS')); ?>",
1415 "openSpLink": "<?php echo addslashes(JText::translate('VBRATESOVWOPENSPL')); ?>",
1416 "vcmRatesChanged": "<?php echo addslashes(JText::translate('VBRATESOVWVCMRCHANGED')); ?>",
1417 "vcmRatesChangedOpen": "<?php echo addslashes(JText::translate('VBRATESOVWVCMRCHANGEDOPEN')); ?>",
1418 "notesForRoom": "<?php echo addslashes(JText::translate('VBONOTESFORROOM')); ?>"
1419 };
1420 var vboFests = <?php echo json_encode($this->festivities); ?>;
1421 var vboRdayNotes = <?php echo json_encode($this->rdaynotes); ?>;
1422 </script>
1423
1424 <script type="text/Javascript">
1425 /**
1426 * Open a booking in a new tab.
1427 */
1428 function vboRovervOpenBooking(bid) {
1429 var open_url = jQuery('.vbo-basenavuri-details').attr('href');
1430 open_url = open_url.replace('%d', bid);
1431 // navigate in a new tab
1432 window.open(open_url, '_blank');
1433 }
1434
1435 /* Labels for months and weekdays */
1436 var vbowdays = <?php echo json_encode($long_days_labels); ?>;
1437 var vbomonths = <?php echo json_encode($long_months_labels); ?>;
1438 /* Dates selection - Start */
1439 var vbolistener = null;
1440
1441 jQuery(function() {
1442 // fests
1443 jQuery(document.body).on("click", "td.bluedays", function() {
1444 if (jQuery(this).hasClass('skip-bluedays-click')) {
1445 return;
1446 }
1447 var ymd = jQuery(this).attr('data-ymd');
1448 var daytitle = jQuery(this).attr('data-readymd');
1449 if (jQuery(this).hasClass('vbo-roverv-festcell')) {
1450 // cell has fests
1451 if (!vboFests.hasOwnProperty(ymd)) {
1452 return;
1453 }
1454 vboRenderFests(ymd, daytitle);
1455 } else {
1456 // let the admin create a new fest
1457
1458 // define the modal buttons
1459 let cancel_btn = jQuery('<button></button>')
1460 .attr('type', 'button')
1461 .addClass('btn')
1462 .text(Joomla.JText._('VBANNULLA'))
1463 .on('click', function() {
1464 VBOCore.emitEvent('vbo-dismiss-modal-roverv-fests');
1465 });
1466
1467 let save_btn = jQuery('<button></button>')
1468 .attr('type', 'button')
1469 .addClass('btn btn-success')
1470 .text(Joomla.JText._('VBSAVE'))
1471 .on('click', function() {
1472 vboAddFest();
1473 });
1474
1475 let modal_body = VBOCore.displayModal({
1476 suffix: 'ratesoverv-fests',
1477 extra_class: 'vbo-modal-rounded vbo-modal-tall',
1478 title: '<?php VikBookingIcons::e('star'); ?> ' + daytitle,
1479 footer_left: cancel_btn,
1480 footer_right: save_btn,
1481 dismiss_event: 'vbo-dismiss-modal-roverv-fests',
1482 onDismiss: () => {
1483 jQuery('.vbo-ratesoverview-fests-wrap').appendTo('.vbo-ratesoverview-fests-helper');
1484 },
1485 });
1486
1487 // update ymd key for the selected date, useful for adding new fests
1488 jQuery('.vbo-overlay-fests-addnew').attr('data-ymd', ymd);
1489
1490 // unset content and display modal for just adding a new fest
1491 jQuery('.vbo-overlay-fests-list').html('');
1492 jQuery('.vbo-ratesoverview-fests-wrap').appendTo(modal_body);
1493 }
1494 if (jQuery(this).hasClass('vbo-roverw-roomdaynote-full')) {
1495 // display the room-day notes
1496 vboRenderRdayNotes(ymd, jQuery(this).attr('data-rid'));
1497 }
1498 });
1499 //
1500 vbolistener = new CalendarListener();
1501 jQuery('.day-block').click(function() {
1502 pickBlock(jQuery(this).attr('id'));
1503 });
1504 jQuery('.day-block').hover(
1505 function() {
1506 if (vbolistener.isFirstPicked() && !vbolistener.isLastPicked()) {
1507 var struct = initBlockStructure(jQuery(this).attr('id'));
1508 var all_blocks = getAllBlocksBetween(vbolistener.first, struct, false);
1509 if (all_blocks !== false) {
1510 jQuery.each(all_blocks, function(k, v) {
1511 if (!v.hasClass('block-picked-middle')) {
1512 v.addClass('block-picked-middle');
1513 }
1514 });
1515 jQuery(this).addClass('block-picked-end');
1516 }
1517 }
1518 },
1519 function() {
1520 if (!vbolistener.isLastPicked()) {
1521 jQuery('.day-block').removeClass('block-picked-middle block-picked-end');
1522 }
1523 }
1524 );
1525 jQuery("body").on("click", ".vbo-roverw-daymod-infospids", function() {
1526 if (jQuery(this).hasClass('vbo-roverw-daymod-infospids-on')) {
1527 // dismiss modal
1528 VBOCore.emitEvent('vbo-ratesoverview-spids-details-dismiss');
1529 } else {
1530 // show modal
1531 let spids_modal = VBOCore.displayModal({
1532 suffix: 'vbo-ratesoverview-spids',
1533 extra_class: 'vbo-modal-rounded vbo-modal-dialog vbo-modal-nofooter',
1534 title: jQuery(this).attr('data-dt'),
1535 dismiss_event: 'vbo-ratesoverview-spids-details-dismiss',
1536 });
1537
1538 let spids_info = jQuery(this).next('.vbo-roverw-daymod-infospids-outcont').find('.vbo-roverw-daymod-infospids-incont').clone();
1539 spids_info.appendTo(spids_modal);
1540 }
1541 });
1542 jQuery('.vbo-roverw-closeopenrp h4').click(function() {
1543 jQuery('.vbo-roverw-closeopenrp-btns').fadeToggle(400, function() {
1544 if (jQuery(this).is(':visible')) {
1545 jQuery('.vbo-roverw-closeopenrp-arrow').html('<?php VikBookingIcons::e('chevron-up'); ?>');
1546 } else {
1547 jQuery('.vbo-roverw-closeopenrp-arrow').html('<?php VikBookingIcons::e('chevron-down'); ?>');
1548 }
1549 });
1550 });
1551 jQuery(document.body).on('click', '.vbo-ratesoverview-vcmwarn-close', function() {
1552 vcm_exists = 0;
1553 jQuery('.vbo-ratesoverview-right-inner').hide().html('');
1554 });
1555
1556 // show booking details
1557 jQuery('.vbo-roverw-daybusy[data-bids]').click(function() {
1558 var date_bids = jQuery(this).attr('data-bids');
1559 if (!date_bids || !date_bids.length) {
1560 return;
1561 }
1562
1563 // get room name, date and day-bids
1564 var rid = jQuery(this).closest('table').attr('data-idroom');
1565 var room_name = jQuery('.vbo-ratesoverview-roomname[data-idroom="' + rid + '"]').text();
1566 var date_read = jQuery(this).attr('data-vbodateread');
1567 var def_bicon = '<?php VikBookingIcons::e('user', 'vbo-dashboard-guest-activity-avatar-icon'); ?>';
1568 var closure_i = '<?php VikBookingIcons::e('ban', 'vbo-dashboard-guest-activity-avatar-icon'); ?>';
1569
1570 // display modal with booking details
1571 var rday_bookings_modal_body = VBOCore.displayModal({
1572 suffix: 'overv-rdaybookings',
1573 extra_class: 'vbo-modal-rounded vbo-modal-tall',
1574 title: room_name + ' - ' + date_read,
1575 dismiss_event: 'vbo-dismiss-modal-roverv-rdaybookings',
1576 loading_event: 'vbo-loading-modal-roverv-rdaybookings',
1577 loading_body: '<?php VikBookingIcons::e('circle-notch', 'fa-spin fa-fw'); ?>',
1578 });
1579
1580 // show loading
1581 VBOCore.emitMultitaskEvent('vbo-loading-modal-roverv-rdaybookings');
1582
1583 // make the request to get the bookings information
1584 VBOCore.doAjax(
1585 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=getbookingsinfo'); ?>",
1586 {
1587 status: 'any',
1588 idorders: date_bids,
1589 tmpl: 'component'
1590 },
1591 (res) => {
1592 // stop loading
1593 VBOCore.emitMultitaskEvent('vbo-loading-modal-roverv-rdaybookings');
1594 try {
1595 var obj_res = typeof res === 'string' ? JSON.parse(res) : res;
1596 // build the HTML response
1597 var rday_bookings_html = '';
1598 rday_bookings_html += '<div class="vbo-dashboard-guests-latest">' + "\n";
1599 rday_bookings_html += ' <div class="vbo-dashboard-guest-messages-list">' + "\n";
1600 for (var b in obj_res) {
1601 if (!obj_res.hasOwnProperty(b)) {
1602 continue;
1603 }
1604 // nights and guests
1605 var nights_guests = [
1606 obj_res[b]['roomsnum'] + ' ' + Joomla.JText._((obj_res[b]['roomsnum'] > 1 ? 'VBPVIEWORDERSTHREE' : 'VBEDITORDERTHREE')),
1607 obj_res[b]['days'] + ' ' + Joomla.JText._((obj_res[b]['days'] > 1 ? 'VBDAYS' : 'VBDAY')),
1608 obj_res[b]['tot_adults'] + ' ' + Joomla.JText._((obj_res[b]['tot_adults'] > 1 ? 'VBMAILADULTS' : 'VBMAILADULT'))
1609 ];
1610 if (obj_res[b]['tot_children'] > 0) {
1611 nights_guests.push(obj_res[b]['tot_children'] + ' ' + Joomla.JText._((obj_res[b]['tot_children'] > 1 ? 'VBMAILCHILDREN' : 'VBMAILCHILD')));
1612 }
1613
1614 // build booking structure
1615 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";
1616 rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-avatar">' + "\n";
1617 if (obj_res[b]['avatar_src']) {
1618 rday_bookings_html += '<img class="vbo-dashboard-guest-activity-avatar-profile" src="' + obj_res[b]['avatar_src'] + '" alt="' + obj_res[b]['avatar_alt'] + '" />' + "\n";
1619 } else if (obj_res[b]['closure']) {
1620 rday_bookings_html += closure_i + "\n";
1621 } else {
1622 rday_bookings_html += def_bicon + "\n";
1623 }
1624 rday_bookings_html += ' </div>' + "\n";
1625 rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content">' + "\n";
1626 rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-head">' + "\n";
1627 rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-info-details">' + "\n";
1628 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";
1629 rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-info-icon">' + "\n";
1630 rday_bookings_html += ' <span class="badge badge-info">' + obj_res[b]['id'] + '</span> ' + "\n";
1631 rday_bookings_html += ' <span class="badge badge-' + (obj_res[b]['status'] == 'confirmed' ? 'success' : 'warning') + '">' + obj_res[b]['status_lbl'] + '</span>' + "\n";
1632 rday_bookings_html += ' <span class="vbo-w-guestmessages-message-staydates">' + "\n";
1633 rday_bookings_html += ' <?php VikBookingIcons::e('calendar-alt'); ?>' + "\n";
1634 rday_bookings_html += ' <span class="vbo-w-guestmessages-message-staydates-in">' + obj_res[b]['checkin_short'] + '</span>' + "\n";
1635 rday_bookings_html += ' <span class="vbo-w-guestmessages-message-staydates-sep">-</span>' + "\n";
1636 rday_bookings_html += ' <span class="vbo-w-guestmessages-message-staydates-out">' + obj_res[b]['checkout_short'] + '</span>' + "\n";
1637 rday_bookings_html += ' </span>' + "\n";
1638 rday_bookings_html += ' </div>' + "\n";
1639 rday_bookings_html += ' </div>' + "\n";
1640 rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-info-date">' + "\n";
1641 rday_bookings_html += ' <span>' + obj_res[b]['book_date'] + '</span>' + "\n";
1642 rday_bookings_html += ' <span>' + obj_res[b]['book_time'] + '</span>' + "\n";
1643 rday_bookings_html += ' </div>' + "\n";
1644 rday_bookings_html += ' </div>' + "\n";
1645 rday_bookings_html += ' <div class="vbo-dashboard-guest-activity-content-info-msg">' + "\n";
1646 rday_bookings_html += ' <div><?php VikBookingIcons::e('bed'); ?> ' + nights_guests.join(', ') + '</div>' + "\n";
1647 if (obj_res[b].hasOwnProperty('sub_units_data')) {
1648 rday_bookings_html += ' <div class="vbo-rdaybooking-subunits">' + "\n";
1649 for (let sub_rname in obj_res[b]['sub_units_data']) {
1650 if (!obj_res[b]['sub_units_data'].hasOwnProperty(sub_rname)) {
1651 continue;
1652 }
1653 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";
1654 }
1655 rday_bookings_html += ' </div>' + "\n";
1656 }
1657 rday_bookings_html += ' </div>' + "\n";
1658 rday_bookings_html += ' </div>' + "\n";
1659 rday_bookings_html += ' </div>' + "\n";
1660 }
1661 rday_bookings_html += ' </div>' + "\n";
1662 rday_bookings_html += '</div>' + "\n";
1663
1664 // append the response
1665 rday_bookings_modal_body.html(rday_bookings_html);
1666 } catch(err) {
1667 console.error('could not parse JSON response', err, res);
1668 alert('Could not parse JSON response');
1669 }
1670 },
1671 (err) => {
1672 // stop loading and display alert message
1673 VBOCore.emitMultitaskEvent('vbo-loading-modal-roverv-rdaybookings');
1674 console.error(err);
1675 alert(err.responseText);
1676 }
1677 );
1678 });
1679 });
1680
1681 /**
1682 * Room-day notes
1683 */
1684 function vboRenderRdayNotes(day, rid) {
1685 // compose room-day notes information (no sub-units)
1686 var notes_html = '';
1687 var keyid = day + '_' + rid + '_0';
1688 if (vboRdayNotes.hasOwnProperty(keyid) && vboRdayNotes[keyid]['info'] && vboRdayNotes[keyid]['info'].length) {
1689 for (var i = 0; i < vboRdayNotes[keyid]['info'].length; i++) {
1690 var note_data = vboRdayNotes[keyid]['info'][i];
1691 notes_html += '<div class="vbo-overlay-fest-details vbo-roverv-roomdaynotes-note-details">';
1692 notes_html += ' <div class="vbo-fest-info vbo-roverv-roomdaynotes-note-info">';
1693 notes_html += ' <div class="vbo-fest-name vbo-roverv-roomdaynotes-note-name">' + note_data['name'] + '</div>';
1694 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>';
1695 notes_html += ' </div>';
1696 notes_html += '</div>';
1697 }
1698 }
1699 // append room-day notes to the list of festivities
1700 if (notes_html.length) {
1701 notes_html = '<h4 class="vbo-roverw-roomdaynotes-title">' + roverw_messages.notesForRoom + '</h4>' + notes_html;
1702 jQuery('.vbo-overlay-fests-list').append(notes_html);
1703 }
1704 }
1705
1706 /**
1707 * Fests
1708 */
1709 function vboRenderFests(day, daytitle) {
1710 // compose fests information
1711 let fests_html = '';
1712 if (vboFests[day] && vboFests[day]['festinfo'] && vboFests[day]['festinfo'].length) {
1713 for (var i = 0; i < vboFests[day]['festinfo'].length; i++) {
1714 let fest = vboFests[day]['festinfo'][i];
1715 fests_html += '<div class="vbo-overlay-fest-details">';
1716 fests_html += ' <div class="vbo-fest-info">';
1717 fests_html += ' <div class="vbo-fest-name">' + fest['trans_name'] + '</div>';
1718 fests_html += ' <div class="vbo-fest-desc">' + fest['descr'].replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br />' + '$2') + '</div>';
1719 fests_html += ' </div>';
1720 fests_html += ' <div class="vbo-fest-cmds">';
1721 fests_html += ' <button type="button" class="btn btn-danger" onclick="vboRemoveFest(\'' + day + '\', \'' + i + '\', \'' + fest['type'] + '\', this);"><?php VikBookingIcons::e('trash-alt', 'icn-nomargin'); ?></button>';
1722 fests_html += ' </div>';
1723 fests_html += '</div>';
1724 }
1725 }
1726
1727 // update ymd key for the selected date, useful for adding new fests
1728 jQuery('.vbo-overlay-fests-addnew').attr('data-ymd', day);
1729
1730 // set content
1731 jQuery('.vbo-overlay-fests-list').html(fests_html);
1732
1733 if (daytitle) {
1734 // define the modal buttons
1735 let cancel_btn = jQuery('<button></button>')
1736 .attr('type', 'button')
1737 .addClass('btn')
1738 .text(Joomla.JText._('VBANNULLA'))
1739 .on('click', function() {
1740 VBOCore.emitEvent('vbo-dismiss-modal-roverv-fests');
1741 });
1742
1743 let save_btn = jQuery('<button></button>')
1744 .attr('type', 'button')
1745 .addClass('btn btn-success')
1746 .text(Joomla.JText._('VBSAVE'))
1747 .on('click', function() {
1748 vboAddFest();
1749 });
1750
1751 let modal_body = VBOCore.displayModal({
1752 suffix: 'ratesoverv-fests',
1753 extra_class: 'vbo-modal-rounded vbo-modal-tall',
1754 title: '<?php VikBookingIcons::e('star'); ?> ' + daytitle,
1755 footer_left: cancel_btn,
1756 footer_right: save_btn,
1757 dismiss_event: 'vbo-dismiss-modal-roverv-fests',
1758 onDismiss: () => {
1759 jQuery('.vbo-ratesoverview-fests-wrap').appendTo('.vbo-ratesoverview-fests-helper');
1760 },
1761 });
1762
1763 jQuery('.vbo-ratesoverview-fests-wrap').appendTo(modal_body);
1764 }
1765 }
1766 function vboRemoveFest(day, index, fest_type, that) {
1767 if (!confirm('<?php echo addslashes(JText::translate('VBDELCONFIRM')); ?>')) {
1768 return false;
1769 }
1770 var elem = jQuery(that);
1771 // make the AJAX request to the controller to remove this fest from the DB
1772 VBOCore.doAjax(
1773 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=remove_fest'); ?>",
1774 {
1775 tmpl: "component",
1776 dt: day,
1777 ind: index,
1778 type: fest_type
1779 },
1780 (res) => {
1781 if (res.indexOf('e4j.ok') >= 0) {
1782 // delete fest also from the json-decode array of objects
1783 if (vboFests[day] && vboFests[day]['festinfo']) {
1784 // use splice to remove the desired index from array, or delete would not make the length of the array change
1785 vboFests[day]['festinfo'].splice(index, 1);
1786 // re-build indexes of delete buttons, fundamental for removing the right index at next click
1787 vboRenderFests(day);
1788 if (!vboFests[day]['festinfo'].length) {
1789 // delete also this date object from fests
1790 delete vboFests[day];
1791 // no more fests, remove the class for this date from all cells
1792 jQuery('td.bluedays[data-ymd="'+day+'"]').removeClass('vbo-roverv-festcell');
1793 }
1794 }
1795 elem.closest('.vbo-overlay-fest-details').remove();
1796 } else {
1797 console.log(res);
1798 alert('Invalid response');
1799 }
1800 },
1801 (err) => {
1802 alert('Request failed');
1803 }
1804 );
1805 }
1806 function vboAddFest() {
1807 var ymd = jQuery('.vbo-overlay-fests-addnew').attr('data-ymd');
1808 var fest_name = jQuery('#vbo-newfest-name').val();
1809 var fest_descr = jQuery('#vbo-newfest-descr').val();
1810 if (!fest_name.length) {
1811 alert(Joomla.JText._('VBO_PLEASE_FILL_FIELDS'));
1812 return false;
1813 }
1814
1815 // make the AJAX request to the controller to add the festivity to the DB
1816 VBOCore.doAjax(
1817 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=add_fest'); ?>",
1818 {
1819 tmpl: "component",
1820 dt: ymd,
1821 type: "custom",
1822 name: fest_name,
1823 descr: fest_descr
1824 },
1825 (res) => {
1826 // parse the JSON response that contains the fest object for the passed date
1827 try {
1828 var stored_fest = JSON.parse(res);
1829 if (!vboFests.hasOwnProperty(stored_fest['dt'])) {
1830 // we need to add the proper class to all cells to show that there is a fest
1831 jQuery('td.bluedays[data-ymd="'+stored_fest['dt']+'"]').addClass('vbo-roverv-festcell');
1832 }
1833 vboFests[stored_fest['dt']] = stored_fest;
1834 hideVboDialogFests();
1835 // reset input fields
1836 jQuery('#vbo-newfest-name').val('');
1837 jQuery('#vbo-newfest-descr').val('');
1838 } catch (e) {
1839 console.log(res);
1840 alert('Invalid response');
1841 return false;
1842 }
1843 },
1844 (err) => {
1845 alert('Request failed');
1846 }
1847 );
1848 }
1849 /**
1850 * Fests dialog
1851 */
1852 function hideVboDialogFests() {
1853 VBOCore.emitEvent('vbo-dismiss-modal-roverv-fests');
1854 }
1855 //
1856
1857 function checkInvokeVcm() {
1858 if (!vbolistener || !vbolistener.first || !vbolistener.first.rplan) {
1859 return;
1860 }
1861 var rplanid = vbolistener.first.rplan;
1862 var idroom = vbolistener.first.idroom;
1863 var curval = document.getElementById('roverw-newrate-vcm').value;
1864 if (parseInt(curval) < 0) {
1865 return;
1866 }
1867 var buiscuits = document.cookie;
1868 if (!buiscuits.length) {
1869 return;
1870 }
1871 var vcmmatch = "vboVcmRov"+idroom+rplanid+"=";
1872 if (buiscuits.indexOf(vcmmatch) >= 0) {
1873 // last cookie does not terminate with ; so just use 0 to compare
1874 vcmmatch += "0";
1875 if (buiscuits.indexOf(vcmmatch) >= 0) {
1876 jQuery('#roverw-newrate-vcm').prop('checked', false);
1877 } else {
1878 jQuery('#roverw-newrate-vcm').prop('checked', true);
1879 }
1880 }
1881 vboCheckVcmRestrictions();
1882 }
1883
1884 /**
1885 * Restrictions can be updated only if VCM is available and toggled ON, because
1886 * the creation and transmission is made through the Connector Class of VCM.
1887 *
1888 * @since 1.11
1889 */
1890 function vboCheckVcmRestrictions() {
1891 if (!jQuery('#roverw-newrate-vcm').prop('disabled') && jQuery('#roverw-newrate-vcm').prop('checked')) {
1892 jQuery('#roverw-newrestr').val('');
1893 jQuery('.vbo-roverw-newrestr-wrap').show();
1894 } else {
1895 jQuery('.vbo-roverw-newrestr-wrap').hide();
1896 }
1897 }
1898
1899 function showVboDialog() {
1900 var format = new Date().format;
1901 format = format.replace(new RegExp("/", 'g'), new Date().datesep);
1902 jQuery("#rovervw-roomname").html('<?php VikBookingIcons::e('building'); ?> ' + vbolistener.first.roomName);
1903 jQuery("#rovervw-rplan").html(vbolistener.first.rplanName);
1904 jQuery("#rovervw-closeopen-rplan").html('"'+vbolistener.first.rplanName+'"');
1905 jQuery("#rovervw-fromdate").html(vbolistener.first.toDate(format));
1906 jQuery("#rovervw-todate").html(vbolistener.last.toDate(format));
1907 jQuery(".vbo-roverw-alldays-inner").html("");
1908 var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, true);
1909 if (all_blocks !== false) {
1910 var newdayscont = '';
1911 var highestrate = vbolistener.first.defRate;
1912 var allblocksclosed = true;
1913 jQuery.each(all_blocks, function(k, v) {
1914 let date_read = jQuery(v).attr('data-vbodateread');
1915 if (!v.hasClass('vbo-roverw-rplan-off')) {
1916 allblocksclosed = false;
1917 }
1918 var spids = jQuery(v).attr("data-vbospids").split("-");
1919 var spids_det = '';
1920 if (jQuery(v).attr("data-vbospids").length > 0 && spids.length > 0) {
1921 spids_det += "<div class=\"vbo-roverw-daymod-infospids\" data-dt=\"" + date_read + "\"><span><i class=\"<?php echo VikBookingIcons::i('info-circle'); ?>\"></i></span></div>";
1922 spids_det += "<div class=\"vbo-roverw-daymod-infospids-outcont\">";
1923 spids_det += "<div class=\"vbo-roverw-daymod-infospids-incont\"><ul>";
1924 for (var x = 0; x < spids.length; x++) {
1925 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>";
1926 }
1927 spids_det += "</ul></div></div>";
1928 }
1929 var dayrate = parseFloat(v.find('.vbo-rplan-price').text());
1930 if (!isNaN(dayrate) && dayrate > highestrate) {
1931 highestrate = dayrate;
1932 }
1933
1934 let date_parts = date_read.split(',');
1935 let wday = date_parts[0].trim();
1936 let mon = date_parts[1].replace(/[^a-z]/ig, '');
1937 let mday = date_parts[1].replace(/[^0-9]/g, '');
1938
1939 newdayscont += "<div class=\"vbo-roverw-daymod\">";
1940 newdayscont += " <div class=\"vbo-roverw-daymod-inner\">";
1941 newdayscont += " <div class=\"vbo-roverw-daymod-innercell\">";
1942 newdayscont += " <span class=\"vbo-roverw-daydate\">";
1943 newdayscont += " <span class=\"vbo-roverw-daydate-wdaymday\">";
1944 newdayscont += " <span class=\"vbo-roverw-daydate-wday\">" + wday + "</span>";
1945 newdayscont += " <span class=\"vbo-roverw-daydate-mday\">" + mday + "</span>";
1946 newdayscont += " </span>";
1947 newdayscont += " <span class=\"vbo-roverw-daydate-month\">" + mon + "</span>";
1948 newdayscont += " </span>";
1949 newdayscont += " <span class=\"vbo-roverw-dayprice\">" + v.html() + "</span>" + spids_det;
1950 newdayscont += " </div>";
1951 newdayscont += " </div>";
1952 newdayscont += "</div>";
1953 });
1954 jQuery(".vbo-roverw-alldays-inner").html(newdayscont);
1955 jQuery("#roverw-newrate").attr("placeholder", vbolistener.first.defRate).val(highestrate);
1956 // 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
1957 if (allblocksclosed) {
1958 jQuery("#rovervw-rplan").html('<span style="color: #f00"><i class="<?php echo VikBookingIcons::i('ban'); ?>"></i> '+vbolistener.first.rplanName+'</span>');
1959 }
1960 }
1961
1962 // VCM check
1963 checkInvokeVcm();
1964
1965 // define the modal buttons
1966 let cancel_btn = jQuery('<button></button>')
1967 .attr('type', 'button')
1968 .addClass('btn')
1969 .text(Joomla.JText._('VBANNULLA'))
1970 .on('click', function() {
1971 VBOCore.emitEvent('vbo-dismiss-modal-roverv-newratesrestr');
1972 });
1973
1974 let save_btn = jQuery('<button></button>')
1975 .attr('type', 'button')
1976 .addClass('btn btn-success')
1977 .html('<?php VikBookingIcons::e('check-circle'); ?>' + Joomla.JText._('VBAPPLY'))
1978 .on('click', function() {
1979 setNewRates();
1980 });
1981
1982 // display modal
1983 let modal_body = VBOCore.displayModal({
1984 suffix: 'ratesoverv-newratesrestr',
1985 extra_class: 'vbo-modal-rounded vbo-modal-tall',
1986 title: Joomla.JText._('VBO_RATES_AND_RESTR'),
1987 lock_scroll: true,
1988 draggable: true,
1989 footer_left: cancel_btn,
1990 footer_right: save_btn,
1991 dismiss_event: 'vbo-dismiss-modal-roverv-newratesrestr',
1992 loading_event: 'vbo-loading-modal-roverv-newratesrestr',
1993 loading_body: '<?php VikBookingIcons::e('refresh', 'fa-spin fa-3x fa-fw'); ?>',
1994 onDismiss: () => {
1995 // cancel dates selection
1996 vbolistener.clear();
1997 jQuery('.day-block').removeClass('block-picked-start block-picked-middle block-picked-end');
1998
1999 // reset period selection
2000 jQuery('.vbo-ratesoverview-period-from').find('span').text('');
2001 jQuery('.vbo-ratesoverview-period-from-icon').show();
2002 jQuery('.vbo-ratesoverview-period-to').find('span').text('');
2003 jQuery('.vbo-ratesoverview-period-to-icon').show();
2004
2005 // move the element back to its original position
2006 jQuery('.vbo-ratesoverview-newratesrestr-wrap').appendTo('.vbo-ratesoverview-newratesrestr-helper');
2007 },
2008 });
2009
2010 jQuery('.vbo-ratesoverview-newratesrestr-wrap').appendTo(modal_body);
2011 }
2012
2013 function showVboDialogPeriod() {
2014 var format = new Date().format;
2015 format = format.replace(new RegExp("/", 'g'), new Date().datesep);
2016 jQuery('.vbo-ratesoverview-period-box-cals').fadeOut();
2017 jQuery("#rovervw-roomname").html('<?php VikBookingIcons::e('building'); ?> ' + vbolistener.first.roomName);
2018 jQuery("#rovervw-rplan").html(vbolistener.first.rplanName);
2019 jQuery("#rovervw-closeopen-rplan").html('"'+vbolistener.first.rplanName+'"');
2020 jQuery("#rovervw-fromdate").html(vbolistener.first.toDate(format));
2021 jQuery("#rovervw-todate").html(vbolistener.last.toDate(format));
2022 jQuery(".vbo-roverw-alldays-inner").html("");
2023 // reset default new price and placeholder
2024 jQuery("#roverw-newrate").attr("placeholder", "").val("");
2025 // check if all selected blocks are closed
2026 var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, true);
2027 if (all_blocks !== false) {
2028 var allblocksclosed = true;
2029 jQuery.each(all_blocks, function(k, v) {
2030 if (!v.hasClass('vbo-roverw-rplan-off')) {
2031 allblocksclosed = false;
2032 return false;
2033 }
2034 });
2035 if (allblocksclosed) {
2036 jQuery("#rovervw-rplan").html('<span style="color: #f00"><i class="<?php echo VikBookingIcons::i('ban'); ?>"></i> '+vbolistener.first.rplanName+'</span>');
2037 }
2038 }
2039
2040 // VCM check
2041 checkInvokeVcm();
2042
2043 // define the modal buttons
2044 let cancel_btn = jQuery('<button></button>')
2045 .attr('type', 'button')
2046 .addClass('btn')
2047 .text(Joomla.JText._('VBANNULLA'))
2048 .on('click', function() {
2049 VBOCore.emitEvent('vbo-dismiss-modal-roverv-newratesrestr');
2050 });
2051
2052 let save_btn = jQuery('<button></button>')
2053 .attr('type', 'button')
2054 .addClass('btn btn-success')
2055 .html('<?php VikBookingIcons::e('check-circle'); ?>' + Joomla.JText._('VBAPPLY'))
2056 .on('click', function() {
2057 setNewRates();
2058 });
2059
2060 // display modal
2061 let modal_body = VBOCore.displayModal({
2062 suffix: 'ratesoverv-newratesrestr',
2063 extra_class: 'vbo-modal-rounded vbo-modal-tall',
2064 title: Joomla.JText._('VBO_RATES_AND_RESTR'),
2065 lock_scroll: true,
2066 draggable: true,
2067 footer_left: cancel_btn,
2068 footer_right: save_btn,
2069 dismiss_event: 'vbo-dismiss-modal-roverv-newratesrestr',
2070 loading_event: 'vbo-loading-modal-roverv-newratesrestr',
2071 loading_body: '<?php VikBookingIcons::e('refresh', 'fa-spin fa-3x fa-fw'); ?>',
2072 onDismiss: () => {
2073 // cancel dates selection
2074 vbolistener.clear();
2075 jQuery('.day-block').removeClass('block-picked-start block-picked-middle block-picked-end');
2076
2077 // reset period selection
2078 jQuery('.vbo-ratesoverview-period-from').find('span').text('');
2079 jQuery('.vbo-ratesoverview-period-from-icon').show();
2080 jQuery('.vbo-ratesoverview-period-to').find('span').text('');
2081 jQuery('.vbo-ratesoverview-period-to-icon').show();
2082
2083 // move the element back to its original position
2084 jQuery('.vbo-ratesoverview-newratesrestr-wrap').appendTo('.vbo-ratesoverview-newratesrestr-helper');
2085 },
2086 });
2087
2088 jQuery('.vbo-ratesoverview-newratesrestr-wrap').appendTo(modal_body);
2089 }
2090
2091 function vboCheckVcmRatesChanges() {
2092 if (vcm_exists < 1) {
2093 return false;
2094 }
2095
2096 VBOCore.doAjax(
2097 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=checkvcmrateschanges'); ?>",
2098 {
2099 tmpl: "component",
2100 e4j_debug: debug_mode
2101 },
2102 (res) => {
2103 if (res.indexOf('e4j.error') >= 0 ) {
2104 console.log(res);
2105 alert(res.replace("e4j.error.", ""));
2106 jQuery('.vbo-ratesoverview-right-inner').hide();
2107 } else {
2108 //display the VCM link for updating the rates on the OTAs
2109 var obj_res = JSON.parse(res);
2110 var esitcont = "";
2111 if (obj_res.changesCount > 0 && obj_res.hasOwnProperty('changesData') && obj_res.changesData.hasOwnProperty('dfrom')) {
2112 esitcont += "<span class=\"vbo-ratesoverview-vcmwarn-close\"> <i class=\"vboicn-cancel-circle\"></i></span>";
2113 esitcont += "<span class=\"vbo-ratesoverview-vcmwarn-count\"><i class=\"vboicn-notification\"></i> <span>"+roverw_messages.vcmRatesChanged.replace("%d", obj_res.changesCount)+"</span></span>";
2114 esitcont += "<span class=\"vbo-ratesoverview-vcmwarn-open\"><a href=\"index.php?option=com_vikchannelmanager&amp;task=ratespush&amp;vbosess=1\" class=\"btn btn-primary\">"+roverw_messages.vcmRatesChangedOpen+"</a></span>";
2115 jQuery('.vbo-ratesoverview-right-inner').html(esitcont).fadeIn();
2116 } else {
2117 jQuery('.vbo-ratesoverview-right-inner').hide().html('');
2118 }
2119 }
2120 },
2121 (err) => {
2122 console.error(err);
2123 jQuery('.vbo-ratesoverview-right-inner').hide();
2124 }
2125 );
2126 }
2127
2128 /* Delay and launch the check VCM rates modification function, when the page loads */
2129 setTimeout(function() {
2130 vboCheckVcmRatesChanges();
2131 }, 1000);
2132 /* - */
2133
2134 /**
2135 * Displays the results of the Channel Manager update request for rates/restrictions.
2136 * Supports multiple rate plans due to derived/linkage rules.
2137 */
2138 function renderChannelManagerResult(vcm_response) {
2139 if (!Array.isArray(vcm_response)) {
2140 // make sure the result is a list of result objects
2141 vcm_response = [vcm_response];
2142 }
2143
2144 // compose modal body
2145 var htmlres = '<div class="vbo-vcm-rates-res-container">';
2146
2147 vcm_response.forEach((obj) => {
2148 htmlres += '<div class="vbo-vcm-rates-res-rplan-wrap">';
2149
2150 if (obj.hasOwnProperty('rplan_name')) {
2151 htmlres += '<div class="vbo-vcm-rates-res-rplan-data">';
2152 htmlres += '<strong>' + obj['rplan_name'] + '</strong>';
2153 if (obj.hasOwnProperty('is_derived') && obj['is_derived']) {
2154 htmlres += ' <span class="label label-info">' + Joomla.JText._('VBO_IS_DERIVED_RATE') + '</span>';
2155 }
2156 htmlres += '</div>';
2157 }
2158
2159 if (obj.hasOwnProperty('channels_success')) {
2160 htmlres += '<div class="vbo-vcm-rates-res-success">';
2161 for (var ch_id in obj['channels_success']) {
2162 htmlres += '<div class="vbo-vcm-rates-res-channel">';
2163 htmlres += ' <div class="vbo-vcm-rates-res-channel-esit">';
2164 htmlres += ' <i class="<?php echo VikBookingIcons::i('check'); ?>"></i>';
2165 htmlres += ' </div>';
2166 htmlres += ' <div class="vbo-vcm-rates-res-channel-logo">';
2167 if (obj['channels_updated'].hasOwnProperty(ch_id) && obj['channels_updated'][ch_id]['logo'].length) {
2168 htmlres += '<img src="'+obj['channels_updated'][ch_id]['logo']+'" />';
2169 } else {
2170 htmlres += '<span>'+obj['channels_success'][ch_id]+'</span>';
2171 }
2172 htmlres += ' </div>';
2173 htmlres += '</div>';
2174 }
2175
2176 if (obj.hasOwnProperty('channels_bkdown')) {
2177 htmlres += '<div class="vbo-vcm-rates-res-bkdown">';
2178 htmlres += ' <div><pre>'+obj['channels_bkdown']+'</pre></div>';
2179 htmlres += '</div>';
2180 }
2181 htmlres += '</div>';
2182 }
2183
2184 if (obj.hasOwnProperty('channels_warnings')) {
2185 htmlres += '<div class="vbo-vcm-rates-res-warning">';
2186 for (var ch_id in obj['channels_warnings']) {
2187 htmlres += '<div class="vbo-vcm-rates-res-channel">';
2188 htmlres += ' <div class="vbo-vcm-rates-res-channel-esit">';
2189 htmlres += ' <i class="<?php echo VikBookingIcons::i('exclamation-triangle'); ?>"></i>';
2190 htmlres += ' </div>';
2191 htmlres += ' <div class="vbo-vcm-rates-res-channel-logo">';
2192 if (obj['channels_updated'].hasOwnProperty(ch_id) && obj['channels_updated'][ch_id]['logo'].length) {
2193 htmlres += '<img src="'+obj['channels_updated'][ch_id]['logo']+'" />';
2194 } else if (obj['channels_updated'].hasOwnProperty(ch_id)) {
2195 htmlres += '<span>'+obj['channels_updated'][ch_id]['name']+'</span>';
2196 }
2197 htmlres += ' </div>';
2198 htmlres += ' <div class="vbo-vcm-rates-res-channel-det">';
2199 htmlres += ' <pre>'+obj['channels_warnings'][ch_id]+'</pre>';
2200 htmlres += ' </div>';
2201 htmlres += '</div>';
2202 }
2203 htmlres += '</div>';
2204 }
2205
2206 if (obj.hasOwnProperty('channels_errors')) {
2207 htmlres += '<div class="vbo-vcm-rates-res-error">';
2208 for (var ch_id in obj['channels_errors']) {
2209 htmlres += '<div class="vbo-vcm-rates-res-channel">';
2210 htmlres += ' <div class="vbo-vcm-rates-res-channel-esit">';
2211 htmlres += ' <i class="<?php echo VikBookingIcons::i('times'); ?>"></i>';
2212 htmlres += ' </div>';
2213 htmlres += ' <div class="vbo-vcm-rates-res-channel-logo">';
2214 if (obj['channels_updated'].hasOwnProperty(ch_id) && obj['channels_updated'][ch_id]['logo'].length) {
2215 htmlres += ' <img src="'+obj['channels_updated'][ch_id]['logo']+'" />';
2216 } else if (obj['channels_updated'].hasOwnProperty(ch_id)) {
2217 htmlres += ' <span>'+obj['channels_updated'][ch_id]['name']+'</span>';
2218 }
2219 htmlres += ' </div>';
2220 htmlres += ' <div class="vbo-vcm-rates-res-channel-det">';
2221 htmlres += ' <pre>'+obj['channels_errors'][ch_id]+'</pre>';
2222 htmlres += ' </div>';
2223 htmlres += '</div>';
2224 }
2225 htmlres += '</div>';
2226 }
2227
2228 htmlres += '</div>';
2229 });
2230
2231 // close container
2232 htmlres += '</div>';
2233
2234 // display results within a modal window
2235 VBOCore.displayModal({
2236 suffix: 'vbo-vcm-rates-res',
2237 extra_class: 'vbo-modal-rounded vbo-modal-tall',
2238 title: Joomla.JText._('VBOVCMRATESRES'),
2239 body: htmlres,
2240 draggable: true,
2241 });
2242 }
2243
2244 function setNewRates() {
2245 var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, true);
2246 var toval = jQuery("#roverw-newrate").val();
2247 var tovalint = parseFloat(toval);
2248 var invoke_vcm = jQuery("#roverw-newrate-vcm").is(":checked") ? 1 : 0;
2249 var setminlos = jQuery("#roverw-newrestr").val();
2250 var closerplan = 0;
2251 if (all_blocks !== false && toval.length > 0 && !isNaN(tovalint) && tovalint > 0.00) {
2252 // set cookie to remember the action to invoke VCM for this combination of room-rateplan
2253 var nd = new Date();
2254 nd.setTime(nd.getTime() + (365*24*60*60*1000));
2255 document.cookie = "vboVcmRov"+vbolistener.first.idroom+vbolistener.first.rplan+"="+invoke_vcm+"; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
2256 // check whether all blocks have closed the rate plan
2257 var allblocksclosed = true;
2258 jQuery.each(all_blocks, function(k, v) {
2259 if (!v.hasClass('vbo-roverw-rplan-off')) {
2260 allblocksclosed = false;
2261 // break
2262 return false;
2263 }
2264 });
2265 closerplan = allblocksclosed ? 1 : closerplan;
2266
2267 // show loading
2268 VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
2269
2270 VBOCore.doAjax(
2271 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=pricing.setnewrates'); ?>",
2272 {
2273 tmpl: "component",
2274 e4j_debug: debug_mode,
2275 id_room: vbolistener.first.idroom,
2276 id_price: vbolistener.first.rplan,
2277 rate: toval,
2278 vcm: invoke_vcm,
2279 minlos: setminlos,
2280 fromdate: vbolistener.first.toDate("yy-mm-dd"),
2281 todate: vbolistener.last.toDate("yy-mm-dd"),
2282 rateclosed: closerplan
2283 },
2284 (res) => {
2285 if (typeof res === 'string' && res.indexOf('e4j.error') === 0) {
2286 alert(res.replace('e4j.error.', ''));
2287 // stop loading
2288 VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
2289 // abort
2290 return;
2291 }
2292
2293 try {
2294 // display new rates in all_blocks IDs
2295 var restr_set = false;
2296 var obj_res = typeof res === 'string' ? JSON.parse(res) : res;
2297
2298 jQuery.each(obj_res, function(k, v) {
2299 if (k == 'vcm') {
2300 return true;
2301 }
2302
2303 var elem = jQuery("#cell-"+k+"-"+vbolistener.first.idroom);
2304 if (elem.length) {
2305 elem.find(".vbo-rplan-price").html(v.cost);
2306 var spids = '';
2307 if (v.hasOwnProperty('spids')) {
2308 jQuery.each(v.spids, function(spk, spv) {
2309 spids += spv+'-';
2310 });
2311 //right trim dash
2312 spids = spids.replace(/-+$/, '');
2313 }
2314 elem.attr('data-vbospids', spids);
2315 // check if restrictions were set
2316 if (v.hasOwnProperty('newminlos')) {
2317 // always convert v.newminlos to a string to avoid errors with indexOf
2318 var newminlos = v.newminlos+'';
2319 if (newminlos.indexOf('e4j.error') >= 0) {
2320 // an error occurred
2321 alert(newminlos.replace("e4j.error.", ""));
2322 } else {
2323 // get cell identifier part
2324 restr_set = true;
2325 var cell_parts = k.split('-');
2326 var restr_elem = jQuery('#cell-'+cell_parts[0]+'-'+cell_parts[1]+'-'+cell_parts[2]+'-'+vbolistener.first.idroom+'-restr');
2327 if (restr_elem.length) {
2328 var restr_cont = restr_elem.find('.vbo-roverw-curminlos');
2329 restr_cont.html(newminlos);
2330 if (parseInt(newminlos) > 1) {
2331 restr_cont.addClass('vbo-roverw-curminlos-active');
2332 } else {
2333 restr_cont.removeClass('vbo-roverw-curminlos-active');
2334 }
2335 }
2336 // attempt to remove an eventual orphan list
2337 var orphan_elem = jQuery('.vbo-ratesoverview-orphan-dt[data-dt="'+cell_parts[0]+'-'+cell_parts[1]+'-'+cell_parts[2]+'-'+vbolistener.first.idroom+'"]');
2338 if (orphan_elem.length) {
2339 if (orphan_elem.length < 2) {
2340 jQuery('#vbo-ratesoverview-orphans-wrapper-'+vbolistener.first.idroom).fadeOut(400, function() {
2341 orphan_elem.remove();
2342 });
2343 } else {
2344 orphan_elem.remove();
2345 }
2346 }
2347 }
2348 }
2349 //
2350 }
2351 });
2352
2353 // stop loading
2354 VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
2355
2356 // dismiss modal
2357 VBOCore.emitEvent('vbo-dismiss-modal-roverv-newratesrestr');
2358
2359 if (obj_res.hasOwnProperty('vcm')) {
2360 // display CM results
2361 renderChannelManagerResult(obj_res['vcm']);
2362 } else {
2363 setTimeout(function() {
2364 vboCheckVcmRatesChanges();
2365 }, 500);
2366 }
2367
2368 if (restr_set) {
2369 // re-calculate orphans after setting the restriction
2370 setTimeout(function() {
2371 vboCheckOrphans();
2372 }, 200);
2373 }
2374 } catch(err) {
2375 throw new Error(err);
2376 }
2377 },
2378 (err) => {
2379 alert(err.responseText || 'Request Failed');
2380 // stop loading
2381 VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
2382 }
2383 );
2384 } else {
2385 alert(roverw_messages.setNewRatesMissing);
2386 return false;
2387 }
2388 }
2389
2390 function modRoomRatePlan(mode) {
2391 var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, true);
2392 if (all_blocks !== false && mode.length > 0) {
2393 // start loading
2394 VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
2395
2396 VBOCore.doAjax(
2397 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=modroomrateplans'); ?>",
2398 {
2399 tmpl: "component",
2400 e4j_debug: debug_mode,
2401 id_room: vbolistener.first.idroom,
2402 id_price: vbolistener.first.rplan,
2403 type: mode,
2404 fromdate: vbolistener.first.toDate("yy-mm-dd"),
2405 todate: vbolistener.last.toDate("yy-mm-dd")
2406 },
2407 (res) => {
2408 if (res.indexOf('e4j.error') >= 0 ) {
2409 console.log(res);
2410 alert(res.replace("e4j.error.", ""));
2411 // stop loading
2412 VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
2413 } else {
2414 // apply new classes in all_blocks IDs
2415 var obj_res = JSON.parse(res);
2416 jQuery.each(obj_res, function(k, v) {
2417 var elem = jQuery("#cell-"+k+"-"+vbolistener.first.idroom);
2418 if (elem.length) {
2419 elem.removeClass(v.oldcls).addClass(v.newcls);
2420 }
2421 });
2422
2423 // stop loading
2424 VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
2425
2426 // dismiss modal
2427 VBOCore.emitEvent('vbo-dismiss-modal-roverv-newratesrestr');
2428
2429 setTimeout(function() {
2430 vboCheckVcmRatesChanges();
2431 }, 500);
2432 }
2433 },
2434 (err) => {
2435 alert("Request Failed");
2436 // stop loading
2437 VBOCore.emitEvent('vbo-loading-modal-roverv-newratesrestr');
2438 }
2439 );
2440 } else {
2441 alert(roverw_messages.modRplansMissing);
2442 return false;
2443 }
2444 }
2445
2446 function vboUpdateRplan(that) {
2447 if (vbolistener === null || vbolistener.first === null) {
2448 return true;
2449 }
2450 vbolistener.first.rplan = jQuery(that).val();
2451 vbolistener.first.rplanName = jQuery(that).find('option:selected').text();
2452 vbolistener.first.defRate = jQuery(that).find('option:selected').attr('data-defrate');
2453 }
2454
2455 function pickBlock(id) {
2456 var struct = initBlockStructure(id);
2457
2458 if (!vbolistener.pickFirst(struct)) {
2459 // first already picked
2460 if ((vbolistener.first.isBeforeThan(struct) || vbolistener.first.isSameDay(struct)) && vbolistener.first.isSameRplan(struct) && vbolistener.first.isSameRoom(struct)) {
2461 // last > first : pick last
2462 if (vbolistener.pickLast(struct)) {
2463 var all_blocks = getAllBlocksBetween(vbolistener.first, vbolistener.last, false);
2464 if (all_blocks !== false) {
2465 jQuery.each(all_blocks, function(k, v){
2466 if ( !v.hasClass('block-picked-middle') ) {
2467 v.addClass('block-picked-middle');
2468 }
2469 });
2470 jQuery('#'+vbolistener.last.id).addClass('block-picked-end');
2471 showVboDialog();
2472 }
2473 }
2474 } else {
2475 // last < first : clear selection
2476 vbolistener.clear();
2477 jQuery('.day-block').removeClass('block-picked-start block-picked-middle block-picked-end');
2478 }
2479 } else {
2480 // first picked
2481 jQuery('#'+vbolistener.first.id).addClass('block-picked-start');
2482 }
2483 }
2484
2485 function getAllBlocksBetween(start, end, outers_included) {
2486 if (!start.isSameRplan(end) || !start.isSameRoom(end)) {
2487 return false;
2488 }
2489
2490 if (start.isAfterThan(end)) {
2491 return false;
2492 }
2493
2494 var queue = new Array();
2495
2496 if (outers_included) {
2497 queue.push(jQuery('#'+start.id));
2498 }
2499
2500 if (start.isSameDay(end)) {
2501 return queue;
2502 }
2503
2504 var node = jQuery('#'+start.id).next();
2505 var end_id = jQuery('#'+end.id).attr('id');
2506 while (node.length > 0 && node.attr('id') != end_id) {
2507 queue.push(node);
2508 node = node.next();
2509 }
2510
2511 if (outers_included) {
2512 queue.push(jQuery('#'+end.id));
2513 }
2514
2515 return queue;
2516 }
2517
2518 function getPeriodStructure(data) {
2519 return {
2520 "day": parseInt(data[0]),
2521 "month": parseInt(data[1]),
2522 "year": parseInt(data[2]),
2523 "rplan": data[3],
2524 "idroom": data[6],
2525 "roomName": data[7],
2526 "rplanName": data[4],
2527 "defRate": data[5],
2528 "id": "cell-"+parseInt(data[0])+"-"+parseInt(data[1])+"-"+parseInt(data[2])+"-"+data[3]+"-"+data[6],
2529 "isSameDay": function(block) {
2530 return (this.month == block.month && this.day == block.day && this.year == block.year);
2531 },
2532 "isBeforeThan": function(block) {
2533 return (
2534 (this.year < block.year) ||
2535 (this.year == block.year && this.month < block.month) ||
2536 (this.year == block.year && this.month == block.month && this.day < block.day)
2537 );
2538 },
2539 "isAfterThan": function(block) {
2540 return (
2541 (this.year > block.year) ||
2542 (this.year == block.year && this.month > block.month) ||
2543 (this.year == block.year && this.month == block.month && this.day > block.day)
2544 );
2545 },
2546 "isSameRplan": function(block) {
2547 return (this.rplan == block.rplan);
2548 },
2549 "isSameRoom": function(block) {
2550 return (this.idroom == block.idroom);
2551 },
2552 "toDate": function(format) {
2553 return format.replace(
2554 'dd', (this.day < 10 ? '0' : '' ) + this.day
2555 ).replace(
2556 'mm', (this.month < 10 ? '0' : '') + this.month
2557 ).replace(
2558 'yy', this.year
2559 );
2560 }
2561 };
2562 }
2563
2564 function initBlockStructure(id) {
2565 var s = id.split("-");
2566 if (s.length != 6) {
2567 return {};
2568 }
2569 var elem = jQuery("#"+id);
2570 return {
2571 "day": parseInt(s[1]),
2572 "month": parseInt(s[2]),
2573 "year": parseInt(s[3]),
2574 "rplan": s[4],
2575 "idroom": s[5],
2576 "roomName": elem.parent("tr").find("td").first().attr("data-roomname"),
2577 "rplanName": elem.parent("tr").find("td").first().find(".vbo-rplan-name").text(),
2578 "defRate": elem.parent("tr").find("td").first().attr("data-defrate"),
2579 "id": id,
2580 "isSameDay": function(block) {
2581 return (this.month == block.month && this.day == block.day && this.year == block.year);
2582 },
2583 "isBeforeThan": function(block) {
2584 return (
2585 (this.year < block.year) ||
2586 (this.year == block.year && this.month < block.month) ||
2587 (this.year == block.year && this.month == block.month && this.day < block.day)
2588 );
2589 },
2590 "isAfterThan": function(block) {
2591 return (
2592 (this.year > block.year) ||
2593 (this.year == block.year && this.month > block.month) ||
2594 (this.year == block.year && this.month == block.month && this.day > block.day)
2595 );
2596 },
2597 "isSameRplan": function(block) {
2598 return (this.rplan == block.rplan);
2599 },
2600 "isSameRoom": function(block) {
2601 return (this.idroom == block.idroom);
2602 },
2603 "toDate": function(format) {
2604 return format.replace(
2605 'dd', (this.day < 10 ? '0' : '') + this.day
2606 ).replace(
2607 'mm', (this.month < 10 ? '0' : '') + this.month
2608 ).replace(
2609 'yy', this.year
2610 );
2611 }
2612 };
2613 }
2614
2615 function CalendarListener() {
2616 this.first = null;
2617 this.last = null;
2618 }
2619
2620 CalendarListener.prototype.pickFirst = function(struct) {
2621 if (!this.isFirstPicked()) {
2622 this.first = struct;
2623 return true;
2624 }
2625 return false;
2626 }
2627
2628 CalendarListener.prototype.pickLast = function(struct) {
2629 if (!this.isLastPicked() && this.isFirstPicked()) {
2630 this.last = struct;
2631 return true;
2632 }
2633 return false;
2634 }
2635
2636 CalendarListener.prototype.clear = function() {
2637 this.first = null;
2638 this.last = null;
2639 }
2640
2641 CalendarListener.prototype.isFirstPicked = function() {
2642 return this.first != null;
2643 }
2644
2645 CalendarListener.prototype.isLastPicked = function() {
2646 return this.last != null;
2647 }
2648
2649 /* Dates selection - End */
2650
2651 function vboToggleOBPRows() {
2652 jQuery('tr.vbo-roverviewtablerow-occupancy').toggle();
2653 var newcookieval = 0;
2654 if (jQuery('tr.vbo-roverviewtablerow-occupancy').length && jQuery('tr.vbo-roverviewtablerow-occupancy').is(':visible')) {
2655 newcookieval = 1;
2656 }
2657 var nd = new Date();
2658 nd.setTime(nd.getTime() + (365*24*60*60*1000));
2659 document.cookie = "vboRovwObp=" + newcookieval + "; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
2660 }
2661
2662 function vboToggleCollapse() {
2663 var expand = jQuery('input[name="vbo_collapse"]').is(':checked');
2664 var collapse = expand ? 0 : 1;
2665 if (expand) {
2666 jQuery('.vbo-ratesoverview-roomsel-entry-calc-inner, .vbo-roverv-forecast-inner').show();
2667 jQuery('.vbo-ratesoverview-top-container').removeClass('collapsed');
2668 } else {
2669 jQuery('.vbo-ratesoverview-roomsel-entry-calc-inner, .vbo-roverv-forecast-inner').hide();
2670 jQuery('.vbo-ratesoverview-top-container').addClass('collapsed');
2671 }
2672 var nd = new Date();
2673 nd.setTime(nd.getTime() + (365*24*60*60*1000));
2674 document.cookie = "vboRovwColl=" + collapse + "; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
2675 }
2676
2677 function vboCheckCollapse() {
2678 if (jQuery('.vbo-ratesoverview-roomsel-entry-calc-inner').is(':visible') && jQuery('.vbo-roverv-forecast-inner').is(':visible')) {
2679 // all elements are visible, expanded
2680 return;
2681 }
2682 jQuery('input[name="vbo_collapse"]').trigger('click');
2683 }
2684
2685 function vboSelectAllRooms(btn) {
2686 var sel_elem = jQuery('#roomsel');
2687 sel_elem.find('option').prop('selected', true);
2688 sel_elem.trigger('change');
2689 // hide button
2690 jQuery(btn).parent().remove();
2691 // auto-submit form
2692 document.vboratesovwform.submit();
2693 }
2694
2695 var timeline_height_set = false;
2696
2697 jQuery(function() {
2698 // register to the event emitted when a new booking is created through an admin widget
2699 document.addEventListener('vbo_new_booking_created', (e) => {
2700 if (!e || !e.detail || !e.detail.hasOwnProperty('bid') || !e.detail['bid']) {
2701 // do nothing
2702 return;
2703 }
2704 // reload the page to display the new booking just created
2705 location.reload();
2706 });
2707
2708 // toggle OBP rows
2709 if (jQuery('.vbo-ratesoverview-obp-toggle').length && jQuery('tr.vbo-roverviewtablerow-occupancy').length) {
2710 jQuery('.vbo-ratesoverview-obp-toggle').show();
2711 var initial = jQuery('.vbo-ratesoverview-obp-toggle').attr('data-obpstartstatus');
2712 if (initial == '0') {
2713 jQuery('tr.vbo-roverviewtablerow-occupancy').hide();
2714 }
2715 }
2716 //
2717 jQuery(".vbo-ratesoverview-tab-los").click(function() {
2718 var nd = new Date();
2719 nd.setTime(nd.getTime() + (365*24*60*60*1000));
2720 document.cookie = "vboRovwRab=los; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
2721 jQuery(this).removeClass("vbo-ratesoverview-tab-unactive").addClass("vbo-ratesoverview-tab-active");
2722 jQuery(".vbo-ratesoverview-tab-cal").removeClass("vbo-ratesoverview-tab-active").addClass("vbo-ratesoverview-tab-unactive");
2723 jQuery(".vbo-ratesoverview-roomsel-entry-los").show();
2724 jQuery(".vbo-ratesoverview-roomsel-entry-forecast").hide();
2725 jQuery(".vbo-ratesoverview-caltab-cont").hide();
2726 jQuery(".vbo-ratesoverview-lostab-cont").fadeIn();
2727 if (!timeline_height_set) {
2728 jQuery('.vbo-timeline-container').css('min-height', (jQuery('.vbo-timeline-container').outerHeight() + 20));
2729 timeline_height_set = true;
2730 }
2731 });
2732 jQuery(".vbo-ratesoverview-tab-cal").click(function() {
2733 var nd = new Date();
2734 nd.setTime(nd.getTime() + (365*24*60*60*1000));
2735 document.cookie = "vboRovwRab=cal; expires=" + nd.toUTCString() + "; path=/; SameSite=Lax";
2736 jQuery(this).removeClass("vbo-ratesoverview-tab-unactive").addClass("vbo-ratesoverview-tab-active");
2737 jQuery(".vbo-ratesoverview-tab-los").removeClass("vbo-ratesoverview-tab-active").addClass("vbo-ratesoverview-tab-unactive");
2738 jQuery(".vbo-ratesoverview-roomsel-entry-los").hide();
2739 jQuery(".vbo-ratesoverview-roomsel-entry-forecast").show();
2740 jQuery(".vbo-ratesoverview-lostab-cont").hide();
2741 jQuery(".vbo-ratesoverview-caltab-cont").fadeIn();
2742 });
2743 if (window.location.hash == '#tabcal') {
2744 jQuery(".vbo-ratesoverview-tab-cal").trigger("click");
2745 }
2746 jQuery("body").on("click", ".vbo-ratesoverview-numnight", function() {
2747 var inpnight = jQuery(this).attr('id');
2748 if (jQuery('.vbo-ratesoverview-numnight').length > 1) {
2749 jQuery('#inp'+inpnight).remove();
2750 jQuery(this).remove();
2751 }
2752 });
2753 jQuery("body").on("dblclick", ".vbo-calcrates-rateblock", function() {
2754 if (jQuery(this).parent('.vbo-ratesoverview-calculation-response-room').find('.vbo-calcrates-rateblock').length < 2) {
2755 // remove the whole container as there is just one rate plan
2756 jQuery(this).parent('.vbo-ratesoverview-calculation-response-room').remove();
2757 } else {
2758 // remove only this rate plan
2759 jQuery(this).remove();
2760 }
2761 });
2762 jQuery('#vbo-addnumnight-act').click(function() {
2763 var setnights = jQuery('#vbo-addnumnight').val();
2764 if (parseInt(setnights) > 0) {
2765 var los_exists = false;
2766 jQuery('.vbo-ratesoverview-numnight').each(function() {
2767 if (parseInt(jQuery(this).text()) == parseInt(setnights)) {
2768 los_exists = true;
2769 }
2770 });
2771 if (!los_exists) {
2772 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+"\" />");
2773 } else {
2774 jQuery('#vbo-addnumnight').val((parseInt(setnights) + 1));
2775 }
2776 }
2777 });
2778 jQuery('#vbo-ratesoverview-calculate').click(function() {
2779 jQuery(this).text(Joomla.JText._('VBRATESOVWRATESCALCULATORCALCING')).prop('disabled', true);
2780 var checkindate = jQuery("#checkindate").val();
2781 if (!(checkindate.length > 0)) {
2782 checkindate = '<?php echo date('Y-m-d') ?>';
2783 jQuery("#checkindate").val(checkindate);
2784 }
2785 var nights = jQuery("#vbo-numnights").val();
2786 var adults = jQuery("#vbo-numadults").val();
2787 var children = jQuery("#vbo-numchildren").val();
2788 var idroom = jQuery("#roomselcalc").val();
2789 // always remove warning messages
2790 jQuery(".vbo-ratesoverview-calculation-response").find('.vbo-warning').remove();
2791 if (jQuery("#vbo-ratesoverview-calculation-response-room"+idroom).length) {
2792 // remove previous containers for this room
2793 jQuery("#vbo-ratesoverview-calculation-response-room"+idroom).remove();
2794 }
2795 if (!jQuery(".vbo-ratesoverview-calculation-response-room").length) {
2796 // if no rooms responses, empty the whole container
2797 jQuery('.vbo-ratesoverview-calculation-response').html('');
2798 }
2799
2800 VBOCore.doAjax(
2801 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=calc_rates'); ?>",
2802 {
2803 tmpl: "component",
2804 id_room: idroom,
2805 checkin: checkindate,
2806 num_nights: nights,
2807 num_adults: adults,
2808 num_children: children
2809 },
2810 (res) => {
2811 res = JSON.parse(res);
2812 res = res[0];
2813 if (res.indexOf('e4j.error') >= 0 ) {
2814 jQuery(".vbo-ratesoverview-calculation-response").html("<p class='vbo-warning'>" + res.replace("e4j.error.", "") + "</p>").fadeIn();
2815 } else {
2816 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')); ?>';
2817 var newcont = '<div class="vbo-ratesoverview-calculation-response-room" id="vbo-ratesoverview-calculation-response-room'+idroom+'"><h4>'+titlecont+'</h4>'+res+'</div>';
2818 // check whether the content should be appended
2819 if (jQuery(".vbo-ratesoverview-calculation-response").find('.vbo-ratesoverview-calculation-response-room').length) {
2820 newcont = jQuery(".vbo-ratesoverview-calculation-response").html() + newcont;
2821 }
2822 //
2823 jQuery(".vbo-ratesoverview-calculation-response").html(newcont).fadeIn();
2824 // loop over every room response and pricing to append the book-now button for the page calendar
2825 var base_booknow_link_orig = jQuery('#vbo-base-booknow-link').attr('href');
2826 jQuery('.vbo-calcrates-rateblock').each(function(k, v) {
2827 var elem = jQuery(v);
2828 var base_booknow_link = base_booknow_link_orig;
2829 // remove existing button
2830 elem.find('.vbo-room-booknow-rct').remove();
2831 //
2832 var b_idprice = elem.attr('data-idprice');
2833 base_booknow_link = base_booknow_link.replace('idprice=', 'idprice=' + b_idprice);
2834 var b_idroom = elem.attr('data-idroom');
2835 base_booknow_link = base_booknow_link.replace('cid[]=', 'cid[]=' + b_idroom);
2836 var b_checkin = elem.attr('data-checkin');
2837 base_booknow_link = base_booknow_link.replace('checkin=', 'checkin=' + b_checkin);
2838 var b_checkout = elem.attr('data-checkout');
2839 base_booknow_link = base_booknow_link.replace('checkout=', 'checkout=' + b_checkout);
2840 var b_adults = elem.attr('data-adults');
2841 base_booknow_link = base_booknow_link.replace('adults=', 'adults=' + b_adults);
2842 var b_children = elem.attr('data-children');
2843 base_booknow_link = base_booknow_link.replace('children=', 'children=' + b_children);
2844 var booknow = '<a href="' + base_booknow_link + '" class="btn btn-primary vbo-room-booknow-rct" target="_blank">' + Joomla.JText._('VBO_BOOKNOW') + '</a>';
2845 elem.append(booknow);
2846 });
2847 //
2848 }
2849 jQuery('#vbo-ratesoverview-calculate').text(Joomla.JText._('VBRATESOVWRATESCALCULATORCALC')).prop('disabled', false);
2850 },
2851 (err) => {
2852 console.error(err);
2853 jQuery(".vbo-ratesoverview-calculation-response").fadeOut();
2854 jQuery('#vbo-ratesoverview-calculate').text(Joomla.JText._('VBRATESOVWRATESCALCULATORCALC')).prop('disabled', false);
2855 alert("Error Performing Ajax Request");
2856 }
2857 );
2858 });
2859
2860 /* Orphans Calculation */
2861 vboCheckOrphans();
2862 //
2863 });
2864
2865 function vboCheckOrphans() {
2866 /* Orphans Calculation - Start */
2867 var calc_method = '<?php echo VikBooking::orphansCalculation(); ?>';
2868 jQuery('table.vbratesoverviewtable').each(function() {
2869 var current_room = jQuery(this).attr('data-idroom');
2870 var orphans_pool = new Array;
2871 var avcells = jQuery(this).find('tr.vbo-roverviewtableavrow').find('td');
2872 var restrcells = jQuery(this).find('tr.vbo-roverviewtablerow-restrs').find('td');
2873 avcells.each(function(k, v) {
2874 if (!jQuery(v).find('.vbo-roverw-curunits').length) {
2875 // continue
2876 return true;
2877 }
2878 var todayav = parseInt(jQuery(v).find('.vbo-roverw-curunits').text());
2879 if (!restrcells.hasOwnProperty(k) || isNaN(todayav) || todayav < 1) {
2880 // continue, no restriction cell found or no availability for this day
2881 return true;
2882 }
2883 var todayminlos = parseInt(jQuery(restrcells[k]).find('.vbo-roverw-curminlos').text());
2884 if (isNaN(todayminlos) || todayminlos < 2) {
2885 // continue, no min los > 1 set for this day
2886 return true;
2887 }
2888 // check if any night after today, until min los, is fully booked
2889 var cell_queue = new Array;
2890 var hasorphans = false;
2891 var forward_count = 0;
2892 cell_queue.push(v);
2893 for (var i = 1; i < todayminlos; i++) {
2894 if (!avcells.hasOwnProperty((k + i))) {
2895 // break loop, no info for this day after
2896 break;
2897 }
2898 var tomorrowav = parseInt(jQuery(avcells[(k + i)]).find('.vbo-roverw-curunits').text());
2899 if (isNaN(tomorrowav) || tomorrowav != 0) {
2900 // continue, availability found for tomorrow, we need a non available next-day
2901 continue;
2902 }
2903 // orphan found for this day
2904 hasorphans = true;
2905 forward_count = i;
2906 break;
2907 }
2908 // backward calculation method only if "prevnext".
2909 var backward_count = 0;
2910 for (var i = 1; i <= todayminlos; i++) {
2911 if (!avcells.hasOwnProperty((k - i))) {
2912 // break loop, no info for this prev day
2913 break;
2914 }
2915 var yesterdayav = parseInt(jQuery(avcells[(k - i)]).find('.vbo-roverw-curunits').text());
2916 if (isNaN(yesterdayav) || yesterdayav != 0) {
2917 // increase free nights going backward
2918 backward_count++;
2919 }
2920 }
2921 if (calc_method == 'prevnext' && hasorphans && backward_count > 0 && (backward_count >= todayminlos || (backward_count + forward_count) >= todayminlos)) {
2922 // this should not be an orphan date because of enough free days back, or enough free days in between
2923 hasorphans = false;
2924 }
2925
2926 if (hasorphans && cell_queue.length) {
2927 for (var i in cell_queue) {
2928 if (cell_queue.hasOwnProperty(i)) {
2929 // push the cell
2930 orphans_pool.push(cell_queue[i]);
2931 }
2932 }
2933 }
2934 });
2935 if (orphans_pool.length) {
2936 var orphans_list = '';
2937 for (var i in orphans_pool) {
2938 if (!orphans_pool.hasOwnProperty(i)) {
2939 continue;
2940 }
2941 var idparts = jQuery(orphans_pool[i]).attr('id').split('-');
2942 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>';
2943 }
2944 jQuery('#vbo-ratesoverview-orphans-list-'+current_room).html(orphans_list);
2945 jQuery('#vbo-ratesoverview-orphans-wrapper-'+current_room).fadeIn();
2946 }
2947 });
2948 /* Orphans Calculation - End */
2949 }
2950 </script>
2951
2952 <div class="vbo-ratesoverview-fests-helper" style="display: none;">
2953 <div class="vbo-ratesoverview-fests-wrap">
2954 <div class="vbo-overlay-fests-list"></div>
2955 <div class="vbo-overlay-fests-addnew" data-ymd="">
2956 <h4><?php echo JText::translate('VBOADDCUSTOMFESTTODAY'); ?></h4>
2957 <div class="vbo-overlay-fests-addnew-elem">
2958 <label for="vbo-newfest-name"><?php echo JText::translate('VBPVIEWPLACESONE'); ?></label>
2959 <input type="text" id="vbo-newfest-name" value="" />
2960 </div>
2961 <div class="vbo-overlay-fests-addnew-elem">
2962 <label for="vbo-newfest-descr"><?php echo JText::translate('VBPLACEDESCR'); ?></label>
2963 <textarea id="vbo-newfest-descr"></textarea>
2964 </div>
2965 </div>
2966 </div>
2967 </div>
2968