PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.4
VikBooking Hotel Booking Engine & PMS v1.6.4
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 / site / views / search / view.html.php

view.html.php in VikBooking Hotel Booking Engine & PMS 1.6.4, at site/views/search/view.html.php

1,391 lines 65.7 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 jimport('joomla.application.component.view');
14
15 class VikbookingViewSearch extends JViewVikBooking
16 {
17 public function display($tpl = null)
18 {
19 $dbo = JFactory::getDbo();
20 if (VikBooking::allowBooking()) {
21 $session = JFactory::getSession();
22 $mainframe = JFactory::getApplication();
23 $vbo_tn = VikBooking::getTranslator();
24 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
25 $pcheckinm = VikRequest::getString('checkinm', '', 'request');
26 $pcheckinh = VikRequest::getString('checkinh', '', 'request');
27 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
28 $pcheckoutm = VikRequest::getString('checkoutm', '', 'request');
29 $pcheckouth = VikRequest::getString('checkouth', '', 'request');
30 $pcategories = VikRequest::getString('categories', '', 'request');
31 $proomsnum = VikRequest::getInt('roomsnum', '', 'request');
32 $proomsnum = $proomsnum < 1 ? 1 : $proomsnum;
33 $showchildren = VikBooking::showChildrenFront();
34 $padults = VikRequest::getVar('adults', array());
35 $pchildren = VikRequest::getVar('children', array());
36 $ppkg_id = VikRequest::getInt('pkg_id', '', 'request');
37 $pcategory_ids = VikRequest::getVar('category_ids', array());
38 $nowdf = VikBooking::getDateFormat();
39 if ($nowdf == "%d/%m/%Y") {
40 $df = 'd/m/Y';
41 } elseif ($nowdf == "%m/%d/%Y") {
42 $df = 'm/d/Y';
43 } else {
44 $df = 'Y/m/d';
45 }
46 $timeopst = VikBooking::getTimeOpenStore();
47 if (!(strlen($pcheckinh) > 0) && !(strlen($pcheckouth) > 0) && is_array($timeopst)) {
48 $opent = VikBooking::getHoursMinutes($timeopst[0]);
49 $closet = VikBooking::getHoursMinutes($timeopst[1]);
50 $pcheckinh = $opent[0];
51 $pcheckinm = $opent[1];
52 $pcheckouth = $closet[0];
53 $pcheckoutm = $closet[1];
54 }
55 //vikbooking 1.5 channel manager
56 $ch_start_date = VikRequest::getString('start_date', '', 'request');
57 $ch_end_date = VikRequest::getString('end_date', '', 'request');
58 $ch_num_adults = VikRequest::getInt('num_adults', '', 'request');
59 $ch_num_children = VikRequest::getInt('num_children', '', 'request');
60 if (!empty($ch_start_date) && !empty($ch_end_date)) {
61 if (!empty($ch_num_adults) && $ch_num_adults > 0) {
62 $padults = array(0 => $ch_num_adults);
63 }
64 if (!empty($ch_num_children) && $ch_num_children > 0) {
65 $pchildren = array(0 => $ch_num_children);
66 }
67 if ($ch_start_date_ts = strtotime($ch_start_date)) {
68 if ($ch_end_date_ts = strtotime($ch_end_date)) {
69 $pcheckindate = date($df, $ch_start_date_ts);
70 $pcheckoutdate = date($df, $ch_end_date_ts);
71 if (is_array($timeopst)) {
72 $opent = VikBooking::getHoursMinutes($timeopst[0]);
73 $closet = VikBooking::getHoursMinutes($timeopst[1]);
74 $pcheckinh = $opent[0];
75 $pcheckinm = $opent[1];
76 $pcheckouth = $closet[0];
77 $pcheckoutm = $closet[1];
78 } else {
79 $pcheckinh = 0;
80 $pcheckinm = 0;
81 $pcheckouth = 0;
82 $pcheckoutm = 0;
83 }
84 }
85 }
86 }
87 //
88
89 /**
90 * To facilitate the search suggestions to drive more bookings in case of low
91 * availability on the requested dates, we grab all rooms by ignoring their
92 * minimum needed occupancy, and by considering only their maximum capacity.
93 * This can make sense because "solo-rates" (for single-occupancy) are, most
94 * of the times, forced by most OTAs. If the "search suggestions" are enabled
95 * then the minimum occupancy of the rooms will be ignored to guarantee the
96 * completion of a reservation by the guest, which would be booking a greater
97 * room. In terms of pricing and availability nothing changes of course.
98 *
99 * @since 1.14.3 (J) - 1.4.3 (WP)
100 */
101 $booking_suggestion = VikRequest::getInt('suggestion', 0, 'request');
102 //
103
104 $arradultsrooms = array();
105 $arradultsclause = array();
106 $arrpeople = array();
107 if (count($padults) > 0) {
108 foreach ($padults as $kad => $adu) {
109 $roomnumb = $kad + 1;
110 if (strlen($adu)) {
111 $numadults = intval($adu);
112 if ($numadults >= 0) {
113 $arradultsrooms[$roomnumb] = $numadults;
114 $arrpeople[$roomnumb]['adults'] = $numadults;
115 // build capacity requirement clauses
116 $room_requirements = array();
117 if (!$booking_suggestion) {
118 array_push($room_requirements, "`r`.`fromadult`<=" . $numadults);
119 }
120 array_push($room_requirements, "`r`.`toadult`>=" . $numadults);
121 if ($showchildren && !empty($pchildren[$kad]) && intval($pchildren[$kad]) > 0) {
122 $numchildren = intval($pchildren[$kad]);
123 $arrpeople[$roomnumb]['children'] = $numchildren;
124 if (!$booking_suggestion) {
125 array_push($room_requirements, "`r`.`fromchild`<=" . $numchildren);
126 }
127 array_push($room_requirements, "`r`.`tochild`>=" . $numchildren);
128 } else {
129 $arrpeople[$roomnumb]['children'] = 0;
130 //VikBooking 1.4 May Patch: if no children then the room must accept no children
131 if ($showchildren && intval($pchildren[$kad]) == 0) {
132 array_push($room_requirements, "`r`.`fromchild` = 0");
133 }
134 //
135 }
136 array_push($room_requirements, "`r`.`totpeople` >= " . ($arrpeople[$roomnumb]['adults'] + $arrpeople[$roomnumb]['children']));
137 if (!$booking_suggestion) {
138 array_push($room_requirements, "`r`.`mintotpeople` <= " . ($arrpeople[$roomnumb]['adults'] + $arrpeople[$roomnumb]['children']));
139 }
140 $strclause = '(' . implode(' AND ', $room_requirements) . ')';
141 $arradultsclause[] = $strclause;
142 }
143 }
144 }
145 }
146
147 //VBO 1.10 - Modify booking
148 $mod_booking = array();
149 $skip_busy_ids = array();
150 $cur_mod = $session->get('vboModBooking', '');
151 if (is_array($cur_mod) && count($cur_mod)) {
152 $mod_booking = $cur_mod;
153 $skip_busy_ids = VikBooking::loadBookingBusyIds($mod_booking['id']);
154 }
155 //
156 $session->set('vbroomsnum', $proomsnum);
157 $session->set('vbarrpeople', $arrpeople);
158 if (!empty($pcheckindate) && !empty($pcheckoutdate) && $proomsnum > 0 && count($arradultsrooms) == $proomsnum) {
159 if (VikBooking::dateIsValid($pcheckindate) && VikBooking::dateIsValid($pcheckoutdate)) {
160 $first = VikBooking::getDateTimestamp($pcheckindate, $pcheckinh, $pcheckinm);
161 $second = VikBooking::getDateTimestamp($pcheckoutdate, $pcheckouth, $pcheckoutm);
162 $actnow = time();
163 $today_bookings = VikBooking::todayBookings();
164 if ($today_bookings) {
165 $actnow = mktime(0, 0, 0, date('n'), date('j'), date('Y'));
166 }
167 if ($second > $first && $first >= $actnow) {
168 $session->set('vbcheckin', $first);
169 $session->set('vbcheckout', $second);
170 $secdiff = $second - $first;
171 $daysdiff = $secdiff / 86400;
172 if (is_int($daysdiff)) {
173 if ($daysdiff < 1) {
174 $daysdiff = 1;
175 }
176 } else {
177 if ($daysdiff < 1) {
178 $daysdiff = 1;
179 } else {
180 $sum = floor($daysdiff) * 86400;
181 $newdiff = $secdiff - $sum;
182 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
183 if ($maxhmore >= $newdiff) {
184 $daysdiff = floor($daysdiff);
185 } else {
186 $daysdiff = ceil($daysdiff);
187 }
188 }
189 }
190 // VBO 1.11 - push data to tracker
191 VikBooking::getTracker()->pushDates($first, $second, $daysdiff)->pushParty($arrpeople);
192 //
193 //Restrictions
194 $allrestrictions = VikBooking::loadRestrictions(false);
195 $restrictions = VikBooking::globalRestrictions($allrestrictions);
196 $restrcheckin = getdate($first);
197 $restrcheckout = getdate($second);
198 $restrictionsvalid = true;
199 $restrictions_affcount = 0;
200 $restrictionerrmsg = '';
201 if (count($restrictions) > 0) {
202 if (array_key_exists($restrcheckin['mon'], $restrictions)) {
203 //restriction found for this month, checking:
204 $restrictions_affcount++;
205 if (strlen((string)$restrictions[$restrcheckin['mon']]['wday'])) {
206 $rvalidwdays = array($restrictions[$restrcheckin['mon']]['wday']);
207 if (strlen((string)$restrictions[$restrcheckin['mon']]['wdaytwo'])) {
208 $rvalidwdays[] = $restrictions[$restrcheckin['mon']]['wdaytwo'];
209 }
210 if (!in_array($restrcheckin['wday'], $rvalidwdays)) {
211 $restrictionsvalid = false;
212 $restrictionerrmsg = JText::sprintf('VBRESTRERRWDAYARRIVAL', VikBooking::sayMonth($restrcheckin['mon']), VikBooking::sayWeekDay($restrictions[$restrcheckin['mon']]['wday']).(strlen($restrictions[$restrcheckin['mon']]['wdaytwo']) > 0 ? '/'.VikBooking::sayWeekDay($restrictions[$restrcheckin['mon']]['wdaytwo']) : ''));
213 } elseif ($restrictions[$restrcheckin['mon']]['multiplyminlos'] == 1) {
214 if (($daysdiff % $restrictions[$restrcheckin['mon']]['minlos']) != 0) {
215 $restrictionsvalid = false;
216 $restrictionerrmsg = JText::sprintf('VBRESTRERRMULTIPLYMINLOS', VikBooking::sayMonth($restrcheckin['mon']), $restrictions[$restrcheckin['mon']]['minlos']);
217 }
218 }
219 $comborestr = VikBooking::parseJsDrangeWdayCombo($restrictions[$restrcheckin['mon']]);
220 if (count($comborestr) > 0) {
221 if (array_key_exists($restrcheckin['wday'], $comborestr)) {
222 if (!in_array($restrcheckout['wday'], $comborestr[$restrcheckin['wday']])) {
223 $restrictionsvalid = false;
224 $restrictionerrmsg = JText::sprintf('VBRESTRERRWDAYCOMBO', VikBooking::sayMonth($restrcheckin['mon']), VikBooking::sayWeekDay($comborestr[$restrcheckin['wday']][0]).(count($comborestr[$restrcheckin['wday']]) == 2 ? '/'.VikBooking::sayWeekDay($comborestr[$restrcheckin['wday']][1]) : ''), VikBooking::sayWeekDay($restrcheckin['wday']));
225 }
226 }
227 }
228 } elseif (!empty($restrictions[$restrcheckin['mon']]['ctad']) || !empty($restrictions[$restrcheckin['mon']]['ctdd'])) {
229 if (!empty($restrictions[$restrcheckin['mon']]['ctad'])) {
230 $ctarestrictions = explode(',', $restrictions[$restrcheckin['mon']]['ctad']);
231 if (in_array('-'.$restrcheckin['wday'].'-', $ctarestrictions)) {
232 $restrictionsvalid = false;
233 $restrictionerrmsg = JText::sprintf('VBRESTRERRWDAYCTAMONTH', VikBooking::sayWeekDay($restrcheckin['wday']), VikBooking::sayMonth($restrcheckin['mon']));
234 }
235 }
236 if (!empty($restrictions[$restrcheckin['mon']]['ctdd'])) {
237 $ctdrestrictions = explode(',', $restrictions[$restrcheckin['mon']]['ctdd']);
238 if (in_array('-'.$restrcheckout['wday'].'-', $ctdrestrictions)) {
239 $restrictionsvalid = false;
240 $restrictionerrmsg = JText::sprintf('VBRESTRERRWDAYCTDMONTH', VikBooking::sayWeekDay($restrcheckout['wday']), VikBooking::sayMonth($restrcheckin['mon']));
241 }
242 }
243 }
244 if (!empty($restrictions[$restrcheckin['mon']]['maxlos']) && $restrictions[$restrcheckin['mon']]['maxlos'] > 0 && $restrictions[$restrcheckin['mon']]['maxlos'] > $restrictions[$restrcheckin['mon']]['minlos']) {
245 if ($daysdiff > $restrictions[$restrcheckin['mon']]['maxlos']) {
246 $restrictionsvalid = false;
247 $restrictionerrmsg = JText::sprintf('VBRESTRERRMAXLOSEXCEEDED', VikBooking::sayMonth($restrcheckin['mon']), $restrictions[$restrcheckin['mon']]['maxlos']);
248 }
249 }
250 if ($daysdiff < $restrictions[$restrcheckin['mon']]['minlos']) {
251 $restrictionsvalid = false;
252 $restrictionerrmsg = JText::sprintf('VBRESTRERRMINLOSEXCEEDED', VikBooking::sayMonth($restrcheckin['mon']), $restrictions[$restrcheckin['mon']]['minlos']);
253 }
254 } elseif (array_key_exists('range', $restrictions)) {
255 /**
256 * We use this map to know which restriction IDs are okay or not okay with the Min LOS.
257 * The most recent restrictions will have a higher priority over the oldest ones.
258 *
259 * @since 1.13.5 (J) - 1.3.6 (WP)
260 */
261 $minlos_priority = array(
262 'ok' => array(),
263 'nok' => array()
264 );
265 //
266 foreach ($restrictions['range'] as $restr) {
267 /**
268 * We should not always add 82799 seconds to the end date of the restriction
269 * because if they only last for one day (like a Saturday), then $restr['dto']
270 * will be already set to the time 23:59:59.
271 *
272 * @since 1.13 (J) - 1.3.0 (WP)
273 */
274 $end_operator = date('Y-m-d', $restr['dfrom']) != date('Y-m-d', $restr['dto']) ? 82799 : 0;
275 //
276 if ($restr['dfrom'] <= $restrcheckin[0] && ($restr['dto'] + $end_operator) >= $restrcheckin[0]) {
277 // restriction found for this date range based on arrival date, check if compliant
278 $restrictions_affcount++;
279 if (strlen((string)$restr['wday'])) {
280 $rvalidwdays = array($restr['wday']);
281 if (strlen((string)$restr['wdaytwo'])) {
282 $rvalidwdays[] = $restr['wdaytwo'];
283 }
284 if (!in_array($restrcheckin['wday'], $rvalidwdays)) {
285 $restrictionsvalid = false;
286 $restrictionerrmsg = JText::sprintf('VBRESTRERRWDAYARRIVALRANGE', VikBooking::sayWeekDay($restr['wday']).(strlen((string)$restr['wdaytwo']) ? '/'.VikBooking::sayWeekDay($restr['wdaytwo']) : ''));
287 } elseif ($restr['multiplyminlos'] == 1) {
288 if (($daysdiff % $restr['minlos']) != 0) {
289 $restrictionsvalid = false;
290 $restrictionerrmsg = JText::sprintf('VBRESTRERRMULTIPLYMINLOSRANGE', $restr['minlos']);
291 }
292 }
293 $comborestr = VikBooking::parseJsDrangeWdayCombo($restr);
294 if ($comborestr) {
295 if (array_key_exists($restrcheckin['wday'], $comborestr)) {
296 if (!in_array($restrcheckout['wday'], $comborestr[$restrcheckin['wday']])) {
297 $restrictionsvalid = false;
298 $restrictionerrmsg = JText::sprintf('VBRESTRERRWDAYCOMBORANGE', VikBooking::sayWeekDay($comborestr[$restrcheckin['wday']][0]).(count($comborestr[$restrcheckin['wday']]) == 2 ? '/'.VikBooking::sayWeekDay($comborestr[$restrcheckin['wday']][1]) : ''), VikBooking::sayWeekDay($restrcheckin['wday']));
299 }
300 }
301 }
302 } elseif (!empty($restr['ctad']) || !empty($restr['ctdd'])) {
303 if (!empty($restr['ctad'])) {
304 $ctarestrictions = explode(',', $restr['ctad']);
305 if (in_array('-'.$restrcheckin['wday'].'-', $ctarestrictions)) {
306 $restrictionsvalid = false;
307 $restrictionerrmsg = JText::sprintf('VBRESTRERRWDAYCTARANGE', VikBooking::sayWeekDay($restrcheckin['wday']));
308 }
309 }
310 if (!empty($restr['ctdd'])) {
311 $ctdrestrictions = explode(',', $restr['ctdd']);
312 if (in_array('-'.$restrcheckout['wday'].'-', $ctdrestrictions) && $restrcheckout[0] <= ($restr['dto'] + $end_operator)) {
313 $restrictionsvalid = false;
314 $restrictionerrmsg = JText::sprintf('VBRESTRERRWDAYCTDRANGE', VikBooking::sayWeekDay($restrcheckout['wday']));
315 }
316 }
317 }
318 if (!empty($restr['maxlos']) && $restr['maxlos'] > 0 && $restr['maxlos'] > $restr['minlos']) {
319 if ($daysdiff > $restr['maxlos']) {
320 $restrictionsvalid = false;
321 $restrictionerrmsg = JText::sprintf('VBRESTRERRMAXLOSEXCEEDEDRANGE', $restr['maxlos']);
322 }
323 }
324 if ($daysdiff < $restr['minlos']) {
325 $restrictionsvalid = false;
326 $restrictionerrmsg = JText::sprintf('VBRESTRERRMINLOSEXCEEDEDRANGE', $restr['minlos']);
327 array_push($minlos_priority['nok'], (int)$restr['id']);
328 } else {
329 array_push($minlos_priority['ok'], (int)$restr['id']);
330 }
331 } elseif ($restr['dfrom'] <= $restrcheckout[0] && ($restr['dto'] + $end_operator) >= $restrcheckout[0] && !empty($restr['ctdd'])) {
332 /**
333 * We validate the CTD restrictions depending on the check-out date.
334 *
335 * @since 1.16.3 (J) - 1.6.3 (WP)
336 */
337 $ctdrestrictions = explode(',', $restr['ctdd']);
338 if (in_array('-'.$restrcheckout['wday'].'-', $ctdrestrictions)) {
339 $restrictions_affcount++;
340 $restrictionsvalid = false;
341 $restrictionerrmsg = JText::sprintf('VBRESTRERRWDAYCTDRANGE', VikBooking::sayWeekDay($restrcheckout['wday']));
342 }
343 }
344 }
345 /**
346 * We give priority to more recent restrictions to override MinLOS.
347 *
348 * @since 1.13.5 (J) - 1.3.6 (WP)
349 */
350 if (!$restrictionsvalid && count($minlos_priority['ok']) && count($minlos_priority['nok']) && max($minlos_priority['ok']) > max($minlos_priority['nok'])) {
351 // we unset the error message and we reset the validity because a more recent restriction is allowing this MinLOS
352 $restrictionsvalid = true;
353 $restrictionerrmsg = '';
354 }
355 //
356 }
357 }
358 /**
359 * We are no longer counting the "global restriction records" applied to all rooms, but
360 * we are rather counting all restriction records, global and for individual rooms. This
361 * way we apply the default Min LOS only when there are no restrictions at all. We are
362 * also ignoring if some restrictions were applied. This is the previous IF statement:
363 *
364 * if (!count($restrictions) || $restrictions_affcount <= 0) {
365 *
366 * @since 1.15.0 (J) - 1.5.0 (WP)
367 */
368 if (!count($allrestrictions)) {
369 // check global MinLOS (only in case there are no restrictions affecting these dates or no restrictions at all)
370 $globminlos = VikBooking::getDefaultNightsCalendar();
371 if ($globminlos > 1 && $daysdiff < $globminlos) {
372 $restrictionsvalid = false;
373 $restrictionerrmsg = JText::sprintf('VBRESTRERRMINLOSEXCEEDEDRANGE', $globminlos);
374 }
375 }
376 //VBO 1.9 - check if we are coming from a package to not consider the global restrictions for the standard booking procedure
377 if (!empty($ppkg_id)) {
378 $pkg = VikBooking::getPackage($ppkg_id);
379 if (count($pkg)) {
380 //the package exists so we let the next view perform the validation of the package criteria (MinLOS, MaxLOS etc..).
381 $restrictionsvalid = true;
382 $restrictionerrmsg = '';
383 }
384 }
385 //
386 //Closing Dates
387 $err_closingdates = VikBooking::validateClosingDates($first, $second, $df);
388 if (!empty($err_closingdates)) {
389 $restrictionsvalid = false;
390 $restrictionerrmsg = JText::sprintf('VBERRDATESCLOSED', $err_closingdates);
391 }
392 //
393 //Maximum date in the future for bookings
394 $err_maxdatefuture = VikBooking::validateMaxDateBookings($first);
395 if (!empty($err_maxdatefuture)) {
396 $restrictionsvalid = false;
397 $restrictionerrmsg = JText::sprintf('VBOERRMAXDATEBOOKINGS', $err_maxdatefuture);
398 }
399 //
400 //Minimum days in advance for bookings
401 $err_mindaysadv = VikBooking::validateMinDaysAdvance($first);
402 if (!empty($err_mindaysadv)) {
403 $restrictionsvalid = false;
404 $restrictionerrmsg = JText::sprintf('VBOERRMINDAYSADV', $err_mindaysadv);
405 }
406 //
407 if ($restrictionsvalid === true) {
408 $hoursdiff = VikBooking::countHoursToArrival($first);
409 $q = "SELECT `p`.*,`r`.`id` AS `r_reference_id`,`r`.`name`,`r`.`img`,`r`.`idcat`,`r`.`idcarat`,`r`.`units`,`r`.`moreimgs`,`r`.`fromadult`,`r`.`toadult`,`r`.`fromchild`,`r`.`tochild`,`r`.`smalldesc`,`r`.`totpeople`,`r`.`params`,`r`.`imgcaptions`,`rp`.`name` AS `rpname`,`rp`.`minlos`,`rp`.`minhadv` FROM `#__vikbooking_dispcost` AS `p`, `#__vikbooking_rooms` AS `r`, `#__vikbooking_prices` AS `rp` WHERE `p`.`days`=".(int)$daysdiff." AND `p`.`idroom`=`r`.`id` AND `p`.`idprice`=`rp`.`id` AND `r`.`avail`='1' AND (".implode(" OR ", $arradultsclause).") ORDER BY `p`.`cost` ASC, `p`.`idprice` DESC, `p`.`idroom` ASC;";
410 $dbo->setQuery($q);
411 $tars = $dbo->loadAssocList();
412 if ($tars) {
413 $vbo_tn->translateContents($tars, '#__vikbooking_rooms', array('id' => 'r_reference_id'));
414 $arrtar = array();
415 foreach ($tars as $tar) {
416 $arrtar[$tar['idroom']][] = $tar;
417 }
418 //Closed rate plans on these dates
419 $roomrpclosed = VikBooking::getRoomRplansClosedInDates(array_keys($arrtar), $first, $daysdiff);
420 if (count($roomrpclosed) > 0) {
421 foreach ($arrtar as $kk => $tt) {
422 if (array_key_exists($kk, $roomrpclosed)) {
423 foreach ($tt as $tk => $tv) {
424 if (array_key_exists($tv['idprice'], $roomrpclosed[$kk])) {
425 unset($arrtar[$kk][$tk]);
426 }
427 }
428 if (!(count($arrtar[$kk]) > 0)) {
429 unset($arrtar[$kk]);
430 } else {
431 $arrtar[$kk] = array_values($arrtar[$kk]);
432 }
433 }
434 }
435 }
436 //
437 //VBO 1.10 - rate plans with a minlos, or with a min hours in advance
438 foreach ($arrtar as $kk => $tt) {
439 foreach ($tt as $tk => $tv) {
440 if (!empty($tv['minlos']) && $tv['minlos'] > $daysdiff) {
441 unset($arrtar[$kk][$tk]);
442 } elseif ($hoursdiff < $tv['minhadv']) {
443 unset($arrtar[$kk][$tk]);
444 }
445 }
446 if (!(count($arrtar[$kk]) > 0)) {
447 unset($arrtar[$kk]);
448 } else {
449 $arrtar[$kk] = array_values($arrtar[$kk]);
450 }
451 }
452 //
453 $filtercat = (!empty($pcategories) && $pcategories != "all");
454 $filtermulticat = (is_array($pcategory_ids) && count($pcategory_ids));
455 //vikbooking 1.1
456 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
457 $morehst = VikBooking::getHoursRoomAvail() * 3600;
458 //
459 $allbusy = VikBooking::loadBusyRecords(array_keys($arrtar), $first, $second);
460 $all_locked = VikBooking::loadLockedRecords(array_keys($arrtar), $actnow);
461 foreach ($arrtar as $kk => $tt) {
462 $cats = explode(";", $tt[0]['idcat']);
463 if ($filtercat) {
464 if (!in_array($pcategories, $cats)) {
465 unset($arrtar[$kk]);
466 continue;
467 }
468 }
469 if ($filtermulticat) {
470 /**
471 * Added support for multiple category IDs as filter
472 *
473 * @since 1.13
474 */
475 $multicat_found = false;
476 foreach ($pcategory_ids as $fcatid) {
477 if (!empty($fcatid) && in_array($fcatid, $cats)) {
478 $multicat_found = true;
479 break;
480 }
481 }
482 if (!$multicat_found) {
483 unset($arrtar[$kk]);
484 continue;
485 }
486 }
487 $arrtar[$kk][0]['unitsavail'] = $tt[0]['units'];
488 if (count($allbusy) > 0 && array_key_exists($kk, $allbusy) && count($allbusy[$kk]) > 0) {
489 $units_booked = array();
490 $check_locked = (bool)(count($all_locked) > 0 && array_key_exists($kk, $all_locked) && count($all_locked[$kk]) > 0);
491 foreach ($groupdays as $gday) {
492 $bfound = 0;
493 foreach ($allbusy[$kk] as $bu) {
494 if (in_array($bu['id'], $skip_busy_ids)) {
495 //VBO 1.10 - Booking modification
496 continue;
497 }
498 if ($gday >= $bu['checkin'] && $gday <= ($morehst + $bu['checkout'])) {
499 $bfound++;
500 }
501 }
502 if ($bfound >= $tt[0]['units']) {
503 unset($arrtar[$kk]);
504 break;
505 } else {
506 $units_booked[] = $bfound;
507 if ($check_locked === true) {
508 foreach ($all_locked[$kk] as $bu) {
509 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
510 $bfound++;
511 }
512 }
513 if ($bfound >= $tt[0]['units']) {
514 unset($arrtar[$kk]);
515 break;
516 }
517 }
518 }
519 }
520 if (isset($arrtar[$kk]) && count($units_booked) > 0) {
521 $tot_u_booked = max($units_booked);
522 $tot_u_left = ($tt[0]['units'] - $tot_u_booked);
523 $arrtar[$kk][0]['unitsavail'] = $tot_u_left >= 0 ? $tot_u_left : 0;
524 }
525 } elseif (!VikBooking::roomNotLocked($kk, $tt[0]['units'], $first, $second)) {
526 unset($arrtar[$kk]);
527 }
528 //single room restrictions
529 if (count($allrestrictions) > 0 && array_key_exists($kk, $arrtar)) {
530 $roomrestr = VikBooking::roomRestrictions($kk, $allrestrictions);
531 if (count($roomrestr) > 0) {
532 $restrictionerrmsg = VikBooking::validateRoomRestriction($roomrestr, $restrcheckin, $restrcheckout, $daysdiff);
533 if (strlen($restrictionerrmsg) > 0) {
534 //VBO 1.9 - check if we are coming from a package to not consider the restrictions for the standard booking procedure
535 $canunset = true;
536 if (!empty($ppkg_id)) {
537 $pkg = VikBooking::getPackage($ppkg_id);
538 if (count($pkg)) {
539 //the package exists so we let the next view perform the validation of the package criterai (MinLOS, MaxLOS etc..).
540 $canunset = false;
541 }
542 }
543 if ($canunset === true) {
544 unset($arrtar[$kk]);
545 } else {
546 $restrictionerrmsg = '';
547 }
548 //
549 }
550 }
551 }
552 //end single room restrictions
553
554 /**
555 * Room-level maximum advance booking notice validation.
556 *
557 * @since 1.16.3 (J) - 1.6.3 (WP)
558 */
559 $err_maxdatefuture_room = VikBooking::validateMaxDateBookings($first, $kk);
560 if (!empty($err_maxdatefuture_room)) {
561 // unset non-compliant room and register last error
562 unset($arrtar[$kk]);
563 $restrictionerrmsg = JText::sprintf('VBOERRMAXDATEBOOKINGS', $err_maxdatefuture_room);
564 }
565 }
566 if (is_array($arrtar) && $arrtar) {
567 /**
568 * Despite of the higher resources needed, we parse all rate plans for all rooms.
569 *
570 * @since 1.13 (J) - 1.3.0 (WP)
571 */
572 $arrtar = VikBooking::applySeasonalPrices($arrtar, $first, $second);
573 $multi_rates = 1;
574 foreach ($arrtar as $idr => $tars) {
575 $multi_rates = count($tars) > $multi_rates ? count($tars) : $multi_rates;
576 }
577 if ($multi_rates > 1) {
578 for ($r = 1; $r < $multi_rates; $r++) {
579 $deeper_rates = array();
580 foreach ($arrtar as $idr => $tars) {
581 foreach ($tars as $tk => $tar) {
582 if ($tk == $r) {
583 $deeper_rates[$idr][0] = $tar;
584 break;
585 }
586 }
587 }
588 if (!$deeper_rates) {
589 continue;
590 }
591 $deeper_rates = VikBooking::applySeasonalPrices($deeper_rates, $first, $second);
592 foreach ($deeper_rates as $idr => $dtars) {
593 foreach ($dtars as $dtk => $dtar) {
594 $arrtar[$idr][$r] = $dtar;
595 }
596 }
597 }
598 }
599 $arrtar = VikBooking::sortResults($arrtar);
600 //
601
602 // separate results per number of rooms with $results
603 $tmparrtar = $arrtar;
604 $results = array();
605 $multiroomcount = array();
606 foreach ($arrpeople as $numroom => $aduchild) {
607 $arrtar = $tmparrtar;
608 $diffusage = array();
609 $aduchild['children'] = !array_key_exists('children', $aduchild) ? 0 : $aduchild['children'];
610 $nowtotpeople = $aduchild['adults'] + $aduchild['children'];
611 foreach ($arrtar as $kk => $tt) {
612 $validchildren = true;
613 if ($showchildren) {
614 if (!($tt[0]['fromchild'] <= $aduchild['children'] && $tt[0]['tochild'] >= $aduchild['children']) && $aduchild['children'] > 0) {
615 $validchildren = false;
616 }
617 }
618 $validtotpeople = true;
619 if ($nowtotpeople > $tt[0]['totpeople']) {
620 $errmess = JText::sprintf('VBERRPEOPLEPERROOM', $nowtotpeople, $aduchild['adults'], $aduchild['children']);
621 $validtotpeople = false;
622 }
623 if ($validchildren && $validtotpeople) {
624 if ($tt[0]['toadult'] == $aduchild['adults']) {
625 //clean the diffusage from best usage in case it exists from before
626 foreach ($arrtar[$kk] as $kpr => $vpr) {
627 if (array_key_exists('diffusage', $arrtar[$kk][$kpr])) {
628 unset($arrtar[$kk][$kpr]['diffusage']);
629 }
630 if (array_key_exists('diffusagecost', $arrtar[$kk][$kpr])) {
631 //restore original price
632 $operator = substr($arrtar[$kk][$kpr]['diffusagecost'], 0, 1);
633 $valpcent = substr($arrtar[$kk][$kpr]['diffusagecost'], -1);
634 if ($operator == "+") {
635 if ($valpcent == "%") {
636 $diffvalue = substr($arrtar[$kk][$kpr]['diffusagecost'], 1, (strlen($arrtar[$kk][$kpr]['diffusagecost']) - 1));
637 if (array_key_exists('diffusagecostpernight', $arrtar[$kk][$kpr]) && $arrtar[$kk][$kpr]['diffusagecostpernight'] > 0) {
638 $arrtar[$kk][$kpr]['cost'] = $arrtar[$kk][$kpr]['diffusagecostpernight'];
639 } else {
640 $arrtar[$kk][$kpr]['cost'] = round(($vpr['cost'] * (100 - $diffvalue) / 100), 2);
641 }
642 } else {
643 $diffvalue = substr($arrtar[$kk][$kpr]['diffusagecost'], 1);
644 $arrtar[$kk][$kpr]['cost'] = $vpr['cost'] - $diffvalue;
645 }
646 } elseif ($operator == "-") {
647 if ($valpcent == "%") {
648 $diffvalue = substr($arrtar[$kk][$kpr]['diffusagecost'], 1, (strlen($arrtar[$kk][$kpr]['diffusagecost']) - 1));
649 if (array_key_exists('diffusagecostpernight', $arrtar[$kk][$kpr]) && $arrtar[$kk][$kpr]['diffusagecostpernight'] > 0) {
650 $arrtar[$kk][$kpr]['cost'] = $arrtar[$kk][$kpr]['diffusagecostpernight'];
651 } else {
652 $arrtar[$kk][$kpr]['cost'] = round(($vpr['cost'] * (100 + $diffvalue) / 100), 2);
653 }
654 } else {
655 $diffvalue = substr($arrtar[$kk][$kpr]['diffusagecost'], 1);
656 $arrtar[$kk][$kpr]['cost'] = $vpr['cost'] + $diffvalue;
657 }
658 }
659 //
660 unset($arrtar[$kk][$kpr]['diffusagecost']);
661 unset($arrtar[$kk][$kpr]['diffusagecostpernight']);
662 }
663 }
664 //
665 //VikBooking 1.3 - Maximum Occupancy Charges/Discounts
666 $diffusageprice = VikBooking::loadAdultsDiff($kk, $aduchild['adults']);
667 //Occupancy Override
668 if (array_key_exists('occupancy_ovr', $tt[0]) && array_key_exists($aduchild['adults'], $tt[0]['occupancy_ovr']) && strlen($tt[0]['occupancy_ovr'][$aduchild['adults']]['value'])) {
669 $diffusageprice = $tt[0]['occupancy_ovr'][$aduchild['adults']];
670 }
671 //
672 if (is_array($diffusageprice)) {
673 //set a charge or discount to the price(s) for the different usage of the room
674 foreach ($arrtar[$kk] as $kpr => $vpr) {
675 $arrtar[$kk][$kpr]['diffusage'] = $aduchild['adults'];
676 if ($diffusageprice['chdisc'] == 1) {
677 //charge
678 if ($diffusageprice['valpcent'] == 1) {
679 //fixed value
680 $arrtar[$kk][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? 1 : 0;
681 $aduseval = $diffusageprice['pernight'] == 1 ? $diffusageprice['value'] * $arrtar[$kk][$kpr]['days'] : $diffusageprice['value'];
682 $arrtar[$kk][$kpr]['diffusagecost'] = "+".$aduseval;
683 $arrtar[$kk][$kpr]['cost'] = $vpr['cost'] + $aduseval;
684 } else {
685 //percentage value
686 $arrtar[$kk][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? $vpr['cost'] : 0;
687 $aduseval = $diffusageprice['pernight'] == 1 ? round(($vpr['cost'] * $diffusageprice['value'] / 100) * $arrtar[$kk][$kpr]['days'] + $vpr['cost'], 2) : round(($vpr['cost'] * (100 + $diffusageprice['value']) / 100), 2);
688 $arrtar[$kk][$kpr]['diffusagecost'] = "+".$diffusageprice['value']."%";
689 $arrtar[$kk][$kpr]['cost'] = $aduseval;
690 }
691 } else {
692 //discount
693 if ($diffusageprice['valpcent'] == 1) {
694 //fixed value
695 $arrtar[$kk][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? 1 : 0;
696 $aduseval = $diffusageprice['pernight'] == 1 ? $diffusageprice['value'] * $arrtar[$kk][$kpr]['days'] : $diffusageprice['value'];
697 $arrtar[$kk][$kpr]['diffusagecost'] = "-".$aduseval;
698 $arrtar[$kk][$kpr]['cost'] = $vpr['cost'] - $aduseval;
699 } else {
700 //percentage value
701 $arrtar[$kk][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? $vpr['cost'] : 0;
702 $aduseval = $diffusageprice['pernight'] == 1 ? round($vpr['cost'] - ((($vpr['cost'] / $arrtar[$kk][$kpr]['days']) * $diffusageprice['value'] / 100) * $arrtar[$kk][$kpr]['days']), 2) : round(($vpr['cost'] * (100 - $diffusageprice['value']) / 100), 2);
703 $arrtar[$kk][$kpr]['diffusagecost'] = "-".$diffusageprice['value']."%";
704 $arrtar[$kk][$kpr]['cost'] = $aduseval;
705 }
706 }
707 }
708 }
709 //VikBooking 1.3 - Maximum Occupancy Charges/Discounts
710 //best usage
711 $results[$numroom][] = $arrtar[$kk];
712 if (!isset($multiroomcount[$arrtar[$kk][0]['idroom']])) {
713 $multiroomcount[$arrtar[$kk][0]['idroom']] = array('count' => 0);
714 }
715 $multiroomcount[$arrtar[$kk][0]['idroom']]['count'] += 1;
716 $multiroomcount[$arrtar[$kk][0]['idroom']]['unitsavail'] = (int)$arrtar[$kk][0]['unitsavail'];
717 $multiroomcount[$arrtar[$kk][0]['idroom']]['diffusage_r'.$numroom] = 0;
718 } elseif (($tt[0]['fromadult'] <= $aduchild['adults'] || $booking_suggestion) && $tt[0]['toadult'] > $aduchild['adults']) {
719 //different usage
720 $diffusageprice = VikBooking::loadAdultsDiff($kk, $aduchild['adults']);
721 //Occupancy Override
722 if (array_key_exists('occupancy_ovr', $tt[0]) && array_key_exists($aduchild['adults'], $tt[0]['occupancy_ovr']) && strlen($tt[0]['occupancy_ovr'][$aduchild['adults']]['value'])) {
723 $diffusageprice = $tt[0]['occupancy_ovr'][$aduchild['adults']];
724 }
725 //
726 if (is_array($diffusageprice)) {
727 //set a charge or discount to the price(s) for the different usage of the room
728 foreach ($arrtar[$kk] as $kpr => $vpr) {
729 $arrtar[$kk][$kpr]['diffusage'] = $aduchild['adults'];
730 if ($diffusageprice['chdisc'] == 1) {
731 //charge
732 if ($diffusageprice['valpcent'] == 1) {
733 //fixed value
734 $arrtar[$kk][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? 1 : 0;
735 $aduseval = $diffusageprice['pernight'] == 1 ? $diffusageprice['value'] * $arrtar[$kk][$kpr]['days'] : $diffusageprice['value'];
736 $arrtar[$kk][$kpr]['diffusagecost'] = "+".$aduseval;
737 $arrtar[$kk][$kpr]['cost'] = $vpr['cost'] + $aduseval;
738 } else {
739 //percentage value
740 $arrtar[$kk][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? $vpr['cost'] : 0;
741 $aduseval = $diffusageprice['pernight'] == 1 ? round(($vpr['cost'] * $diffusageprice['value'] / 100) * $arrtar[$kk][$kpr]['days'] + $vpr['cost'], 2) : round(($vpr['cost'] * (100 + $diffusageprice['value']) / 100), 2);
742 $arrtar[$kk][$kpr]['diffusagecost'] = "+".$diffusageprice['value']."%";
743 $arrtar[$kk][$kpr]['cost'] = $aduseval;
744 }
745 } else {
746 //discount
747 if ($diffusageprice['valpcent'] == 1) {
748 //fixed value
749 $arrtar[$kk][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? 1 : 0;
750 $aduseval = $diffusageprice['pernight'] == 1 ? $diffusageprice['value'] * $arrtar[$kk][$kpr]['days'] : $diffusageprice['value'];
751 $arrtar[$kk][$kpr]['diffusagecost'] = "-".$aduseval;
752 $arrtar[$kk][$kpr]['cost'] = $vpr['cost'] - $aduseval;
753 } else {
754 //percentage value
755 $arrtar[$kk][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? $vpr['cost'] : 0;
756 $aduseval = $diffusageprice['pernight'] == 1 ? round($vpr['cost'] - ((($vpr['cost'] / $arrtar[$kk][$kpr]['days']) * $diffusageprice['value'] / 100) * $arrtar[$kk][$kpr]['days']), 2) : round(($vpr['cost'] * (100 - $diffusageprice['value']) / 100), 2);
757 $arrtar[$kk][$kpr]['diffusagecost'] = "-".$diffusageprice['value']."%";
758 $arrtar[$kk][$kpr]['cost'] = $aduseval;
759 }
760 }
761 }
762 } else {
763 $arrtar[$kk][0]['diffusage'] = $aduchild['adults'];
764 }
765 $diffusage[$numroom][] = $arrtar[$kk];
766 if (!isset($multiroomcount[$arrtar[$kk][0]['idroom']])) {
767 $multiroomcount[$arrtar[$kk][0]['idroom']] = array('count' => 0);
768 }
769 $multiroomcount[$arrtar[$kk][0]['idroom']]['count'] += 1;
770 $multiroomcount[$arrtar[$kk][0]['idroom']]['unitsavail'] = (int)$arrtar[$kk][0]['unitsavail'];
771 $multiroomcount[$arrtar[$kk][0]['idroom']]['diffusage_r'.$numroom] = 1;
772 }
773 }
774 }
775 //merge $diffusage rooms with and after best usage rooms in $results
776 if (count($diffusage) > 0) {
777 foreach ($diffusage as $nr => $du) {
778 foreach ($du as $duroom) {
779 $results[$nr][]=$duroom;
780 }
781 }
782 }
783 //
784 }
785 //
786 //check if rooms repeated passed the availability
787 $limitpassed = false;
788 $search_type = VikBooking::getSmartSearchType();
789 $js_search = $search_type == 'dynamic' ? true : false;
790 //dynamic smart search via PHP
791 $js_overcounter = array();
792 if ($js_search && $proomsnum > 1 && count($multiroomcount) > 0) {
793 $tot_avail = 0;
794 foreach ($multiroomcount as $idroom => $info) {
795 $tot_avail += $info['unitsavail'];
796 }
797 if ($tot_avail >= $proomsnum) {
798 $gen_avail = $results;
799 foreach ($multiroomcount as $idroom => $info) {
800 $multiroomcount[$idroom]['used'] = 0;
801 if ($info['count'] > $info['unitsavail']) {
802 $excessnum = $info['count'] - $info['unitsavail'];
803 if ($excessnum > 0) {
804 for ($z = $proomsnum; $z >= 1; $z--) {
805 if ($excessnum > 0) {
806 /**
807 * VBO 1.10 Patch May 2018
808 * @see comments below
809 */
810 $excessproc = false;
811 //
812 foreach ($results[$z] as $kres => $res) {
813 if ($res[0]['idroom'] == $idroom) {
814 /**
815 * We do not need to unset the rooms as we risk to produce no results.
816 * We skip this control if the "search type" setting is set to "dynamic".
817 *
818 * @since 1.12 Patch October 2nd 2019
819 */
820 if (!$js_search) {
821 unset($gen_avail[$z][$kres]);
822 }
823 $excessproc = true;
824 }
825 }
826 if ($excessproc) {
827 /**
828 * VBO 1.10 Patch May 2018
829 * @see comments below
830 */
831 $excessnum--;
832 }
833 }
834 }
835 }
836 }
837 }
838 /**
839 * We do not need to unset the rooms as we risk to produce no results.
840 * We skip this control if the "search type" setting is set to "dynamic".
841 *
842 * @since 1.12 Patch October 2nd 2019
843 */
844 if (!$js_search) {
845 for ($z = $proomsnum; $z >= 1; $z--) {
846 if (!isset($gen_avail[$z]) || !count($gen_avail[$z])) {
847 foreach ($gen_avail as $oknroom => $res) {
848 if (count($gen_avail[$oknroom]) > 1) {
849 $searchfrom = min(array_keys($res));
850 foreach ($res as $kr => $rr) {
851 if (intval($kr) > intval($searchfrom)) {
852 //check if the second, third.. cheapest room(s) is compatible
853 if ($rr[0]['fromadult'] <= $arrpeople[$z]['adults'] && $rr[0]['toadult'] >= $arrpeople[$z]['adults'] && $rr[0]['fromchild'] <= $arrpeople[$z]['children'] && $rr[0]['tochild'] >= $arrpeople[$z]['children']) {
854 $gen_avail[$z][] = $gen_avail[$oknroom][$kr];
855 unset($gen_avail[$oknroom][$kr]);
856 break 2;
857 }
858 }
859 }
860 }
861 }
862 }
863 }
864 }
865 /**
866 * VBO 1.10 Patch May 2018
867 *
868 * Scenario: One room with 3 units in total, 2 units booked and 1 free on certain dates, for 6 adults.
869 * Another room with 5 units available on these dates, for 2 adults. Dynamic search enabled.
870 *
871 * Reservation: 3 room types, 6 adults 1st room, 6 adults 2nd room, 2 adults 3rd room.
872 *
873 * Results: the 6-adult room is displayed for the 1st and 2nd rooms requested, the 2-adult room for the 3rd.
874 * With the Dynamic search enabled, by selecting the 6-adult room once, it gets removed from the other combo.
875 * This leaves one room-party empty, with no results, but no errors are displayed for the search suggestions,
876 * the search results page just gets stuck in there because for a party there are no rooms that can be chosen.
877 *
878 * Solution: if one room-party has no more rooms, unset it so that $js_overcounter won't be set, and the
879 * "automatic smart search via PHP" statement will be processed below. This will raise the error "not enough rooms",
880 * and the Search Suggestions will correctly calculate the availability.
881 *
882 */
883 foreach ($gen_avail as $oknroom => $res) {
884 if (!count($gen_avail[$oknroom])) {
885 unset($gen_avail[$oknroom]);
886 }
887 }
888 //
889 if (count($gen_avail) == $proomsnum) {
890 $js_overcounter = $multiroomcount;
891 unset($gen_avail);
892 }
893 }
894 }
895 //
896 //automatic smart search via PHP
897 if ($proomsnum > 1 && count($multiroomcount) > 0) {
898 foreach ($multiroomcount as $idroom => $info) {
899 if ($info['count'] > $info['unitsavail']) {
900 $excessnum = $info['count'] - $info['unitsavail'];
901 for ($z = $proomsnum; $z >= 1; $z--) {
902 /**
903 * VBO 1.10 Patch June 2018
904 * the different usage clause below should be ignored, or we risk to keep a room in excess
905 * for some room parties when there should be actually no availability for booking multiple times.
906 * This room in excess may be removed only for the parties with different usage, and this is incorrect.
907 */
908 if (true || (array_key_exists('diffusage_r'.$z, $info) && $info['diffusage_r'.$z] == 1)) {
909 //remove repeated room where diffusage and excessnum still exceeds
910 if ($excessnum > 0 && count($js_overcounter) == 0) {
911 foreach ($results[$z] as $kres => $res) {
912 if ($res[0]['idroom'] == $idroom) {
913 unset($results[$z][$kres]);
914 $limitpassed = true;
915 }
916 }
917 if ($limitpassed) {
918 $excessnum--;
919 }
920 }
921 //
922 }
923 }
924 //if excessnum still exceeds, means that the room is not available for the repeated best usages
925 if ($excessnum > 0) {
926 for ($z = $proomsnum; $z >= 1; $z--) {
927 if ($excessnum > 0 && count($js_overcounter) == 0) {
928 foreach ($results[$z] as $kres => $res) {
929 if ($res[0]['idroom'] == $idroom) {
930 unset($results[$z][$kres]);
931 $limitpassed = true;
932 }
933 }
934 if ($limitpassed) {
935 $excessnum--;
936 }
937 }
938 }
939 }
940 //
941 }
942 }
943 }
944 //
945 //if some room was repeated and removed from the multi rooms searched, check if enough results for each room
946 if ($limitpassed == true) {
947 $critic = array();
948 for ($z = $proomsnum; $z >= 1; $z--) {
949 if (!isset($results[$z]) || !count($results[$z])) {
950 $critic[] = $z;
951 unset($results[$z]);
952 }
953 }
954 if (count($critic) > 0) {
955 //some rooms have 0 results, check if something good for this num of adults can be placed here
956 $moved = array();
957 foreach ($critic as $kcr => $nroom) {
958 foreach ($results as $oknroom => $res) {
959 if (count($results[$oknroom]) > 1) {
960 $searchfrom = min(array_keys($res));
961 foreach ($res as $kr => $rr) {
962 if (intval($kr) > intval($searchfrom)) {
963 //check if the second, third.. cheapest room(s) is compatible
964 if ($rr[0]['fromadult'] <= $arrpeople[$nroom]['adults'] && $rr[0]['toadult'] >= $arrpeople[$nroom]['adults'] && $rr[0]['fromchild'] <= $arrpeople[$nroom]['children'] && $rr[0]['tochild'] >= $arrpeople[$nroom]['children']) {
965 $results[$nroom][] = $results[$oknroom][$kr];
966 $moved[] = $oknroom.'_'.$nroom;
967 unset($results[$oknroom][$kr]);
968 unset($critic[$kcr]);
969 break 2;
970 }
971 }
972 }
973 }
974 }
975 }
976 ksort($results);
977 if (count($moved) > 0) {
978 //check if moved rooms had charges/discounts for adults occupancy to update it
979 foreach ($moved as $move) {
980 $movedata = explode('_', $move);
981 if ($arrpeople[$movedata[0]]['adults'] != $arrpeople[$movedata[1]]['adults'] && array_key_exists('diffusagecost', $results[$movedata[1]][0][0])) {
982 //reset prices of the room
983 foreach ($results[$movedata[1]][0] as $kpr => $vpr) {
984 if (array_key_exists('diffusage', $results[$movedata[1]][0][$kpr])) {
985 unset($results[$movedata[1]][0][$kpr]['diffusage']);
986 }
987 if (array_key_exists('diffusagecost', $results[$movedata[1]][0][$kpr])) {
988 //restore original price
989 $operator = substr($results[$movedata[1]][0][$kpr]['diffusagecost'], 0, 1);
990 $valpcent = substr($results[$movedata[1]][0][$kpr]['diffusagecost'], -1);
991 if ($operator == "+") {
992 if ($valpcent == "%") {
993 $diffvalue = substr($results[$movedata[1]][0][$kpr]['diffusagecost'], 1, (strlen($results[$movedata[1]][0][$kpr]['diffusagecost']) - 1));
994 if (array_key_exists('diffusagecostpernight', $results[$movedata[1]][0][$kpr]) && $results[$movedata[1]][0][$kpr]['diffusagecostpernight'] > 0) {
995 $results[$movedata[1]][0][$kpr]['cost'] = $results[$movedata[1]][0][$kpr]['diffusagecostpernight'];
996 } else {
997 $results[$movedata[1]][0][$kpr]['cost'] = round(($vpr['cost'] * (100 - $diffvalue) / 100), 2);
998 }
999 } else {
1000 $diffvalue = substr($results[$movedata[1]][0][$kpr]['diffusagecost'], 1);
1001 $results[$movedata[1]][0][$kpr]['cost'] = $vpr['cost'] - $diffvalue;
1002 }
1003 } elseif ($operator == "-") {
1004 if ($valpcent == "%") {
1005 $diffvalue = substr($results[$movedata[1]][0][$kpr]['diffusagecost'], 1, (strlen($results[$movedata[1]][0][$kpr]['diffusagecost']) - 1));
1006 if (array_key_exists('diffusagecostpernight', $results[$movedata[1]][0][$kpr]) && $results[$movedata[1]][0][$kpr]['diffusagecostpernight'] > 0) {
1007 $results[$movedata[1]][0][$kpr]['cost'] = $results[$movedata[1]][0][$kpr]['diffusagecostpernight'];
1008 } else {
1009 $results[$movedata[1]][0][$kpr]['cost'] = round(($vpr['cost'] * (100 + $diffvalue) / 100), 2);
1010 }
1011 } else {
1012 $diffvalue = substr($results[$movedata[1]][0][$kpr]['diffusagecost'], 1);
1013 $results[$movedata[1]][0][$kpr]['cost'] = $vpr['cost'] + $diffvalue;
1014 }
1015 }
1016 //
1017 unset($results[$movedata[1]][0][$kpr]['diffusagecost']);
1018 unset($results[$movedata[1]][0][$kpr]['diffusagecostpernight']);
1019 }
1020 }
1021 //end reset prices of the room
1022 $diffusageprice = VikBooking::loadAdultsDiff($results[$movedata[1]][0][0]['idroom'], $arrpeople[$movedata[1]]['adults']);
1023 //Occupancy Override - Special Price may be setting a charge/discount for this occupancy while default price had no occupancy pricing
1024 if (!is_array($diffusageprice)) {
1025 foreach ($results[$movedata[1]][0] as $kpr => $vpr) {
1026 if (array_key_exists('occupancy_ovr', $vpr) && array_key_exists($arrpeople[$movedata[1]]['adults'], $vpr['occupancy_ovr']) && strlen($vpr['occupancy_ovr'][$arrpeople[$movedata[1]]['adults']]['value'])) {
1027 $diffusageprice = $vpr['occupancy_ovr'][$arrpeople[$movedata[1]]['adults']];
1028 break;
1029 }
1030 }
1031 reset($results[$movedata[1]][0]);
1032 }
1033 //
1034 if (is_array($diffusageprice)) {
1035 //set a charge or discount to the price(s) for the different usage of the room
1036 foreach ($results[$movedata[1]][0] as $kpr => $vpr) {
1037 //Occupancy Override
1038 if (array_key_exists('occupancy_ovr', $results[$movedata[1]][0][$kpr]) && array_key_exists($arrpeople[$movedata[1]]['adults'], $results[$movedata[1]][0][$kpr]['occupancy_ovr']) && strlen($results[$movedata[1]][0][$kpr]['occupancy_ovr'][$arrpeople[$movedata[1]]['adults']]['value'])) {
1039 $diffusageprice = $results[$movedata[1]][0][$kpr]['occupancy_ovr'][$arrpeople[$movedata[1]]['adults']];
1040 }
1041 //
1042 $results[$movedata[1]][0][$kpr]['diffusage'] = $arrpeople[$movedata[1]]['adults'];
1043 if ($diffusageprice['chdisc'] == 1) {
1044 //charge
1045 if ($diffusageprice['valpcent'] == 1) {
1046 //fixed value
1047 $results[$movedata[1]][0][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? 1 : 0;
1048 $aduseval = $diffusageprice['pernight'] == 1 ? $diffusageprice['value'] * $results[$movedata[1]][0][$kpr]['days'] : $diffusageprice['value'];
1049 $results[$movedata[1]][0][$kpr]['diffusagecost'] = "+".$aduseval;
1050 $results[$movedata[1]][0][$kpr]['cost'] = $vpr['cost'] + $aduseval;
1051 } else {
1052 //percentage value
1053 $results[$movedata[1]][0][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? $vpr['cost'] : 0;
1054 $aduseval = $diffusageprice['pernight'] == 1 ? round(($vpr['cost'] * $diffusageprice['value'] / 100) * $results[$movedata[1]][0][$kpr]['days'] + $vpr['cost'], 2) : round(($vpr['cost'] * (100 + $diffusageprice['value']) / 100), 2);
1055 $results[$movedata[1]][0][$kpr]['diffusagecost'] = "+".$diffusageprice['value']."%";
1056 $results[$movedata[1]][0][$kpr]['cost'] = $aduseval;
1057 }
1058 } else {
1059 //discount
1060 if ($diffusageprice['valpcent'] == 1) {
1061 //fixed value
1062 $results[$movedata[1]][0][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? 1 : 0;
1063 $aduseval = $diffusageprice['pernight'] == 1 ? $diffusageprice['value'] * $results[$movedata[1]][0][$kpr]['days'] : $diffusageprice['value'];
1064 $results[$movedata[1]][0][$kpr]['diffusagecost'] = "-".$aduseval;
1065 $results[$movedata[1]][0][$kpr]['cost'] = $vpr['cost'] - $aduseval;
1066 } else {
1067 //percentage value
1068 $results[$movedata[1]][0][$kpr]['diffusagecostpernight'] = $diffusageprice['pernight'] == 1 ? $vpr['cost'] : 0;
1069 $aduseval = $diffusageprice['pernight'] == 1 ? round($vpr['cost'] - ((($vpr['cost'] / $results[$movedata[1]][0][$kpr]['days']) * $diffusageprice['value'] / 100) * $results[$movedata[1]][0][$kpr]['days']), 2) : round(($vpr['cost'] * (100 - $diffusageprice['value']) / 100), 2);
1070 $results[$movedata[1]][0][$kpr]['diffusagecost'] = "-".$diffusageprice['value']."%";
1071 $results[$movedata[1]][0][$kpr]['cost'] = $aduseval;
1072 }
1073 }
1074 }
1075 }
1076 }
1077 }
1078 //end check if moved rooms had charges/discounts for adults occupancy to update it
1079 }
1080 //
1081 }
1082 }
1083 //
1084 $results = VikBooking::sortMultipleResults($results);
1085 //save prices in session for the modules
1086 $sessvals = array();
1087 $modprices = array();
1088 $sessvals['roomsnum'] = $proomsnum;
1089 $sessvals['checkin'] = $first;
1090 $sessvals['checkout'] = $second;
1091 for ($i = 1; $i <= $proomsnum; $i++) {
1092 if (!isset($results[$i])) {
1093 continue;
1094 }
1095 foreach ($results[$i] as $indres => $res) {
1096 $modprices[$i][] = $res[0]['cost'];
1097 }
1098 }
1099 for ($i = 1; $i <= $proomsnum; $i++) {
1100 if (!isset($modprices[$i])) {
1101 continue;
1102 }
1103 $mincost = min($modprices[$i]);
1104 $maxcost = max($modprices[$i]);
1105 $sessvals[$i]['min'] = $mincost;
1106 $sessvals[$i]['max'] = $maxcost;
1107 $sessvals[$i]['adults'] = $arrpeople[$i]['adults'];
1108 $sessvals[$i]['children'] = $arrpeople[$i]['children'];
1109 }
1110 $session->set('vbsearchdata', $sessvals);
1111 //end save prices in session for the modules
1112 //apply price filters
1113 $ppricefrom = VikRequest::getInt('r1pricefrom', '', 'request');
1114 $ppriceto = VikRequest::getInt('r1priceto', '', 'request');
1115 if (!empty($ppricefrom) && !empty($ppriceto)) {
1116 foreach ($results as $oknroom => $res) {
1117 $totroomres = count($res);
1118 foreach ($res as $kr => $rr) {
1119 if ($oknroom > 1) {
1120 $ppricefrom = VikRequest::getInt('r'.$oknroom.'pricefrom', '', 'request');
1121 $ppriceto = VikRequest::getInt('r'.$oknroom.'priceto', '', 'request');
1122 }
1123 if (!empty($ppricefrom) && !empty($ppriceto)) {
1124 if ($rr[0]['cost'] < $ppricefrom || $rr[0]['cost'] > $ppriceto) {
1125 if ($totroomres > 1) {
1126 unset($results[$oknroom][$kr]);
1127 $totroomres--;
1128 }
1129 }
1130 }
1131 }
1132 }
1133 }
1134 //end apply price filters
1135 if (count($results) == $proomsnum) {
1136 // check whether the user is coming from roomdetails
1137 $proomdetail = VikRequest::getInt('roomdetail', 0, 'request');
1138 $rate_plan_id = VikRequest::getInt('rate_plan_id', 0, 'request');
1139 $user_currency = VikRequest::getString('user_currency', '', 'request');
1140 $children_age = VikRequest::getVar('children_age', array());
1141 $pitemid = VikRequest::getInt('Itemid', 0, 'request');
1142 if (!empty($proomdetail) && array_key_exists($proomdetail, $arrtar) && $proomsnum == 1) {
1143 // VBO 1.11 - push data to tracker and close
1144 VikBooking::getTracker()->pushRooms($proomdetail)->closeTrack();
1145 // store in the session that we are coming from the room details page
1146 $session->set('vboSearchRoomId', $proomdetail);
1147
1148 /**
1149 * Build redirect URI to the "showprc" View to continue the booking process, and
1150 * keep some special vars that may serve to reflect the original booking link.
1151 *
1152 * @since 1.15.0 (J) - 1.5.0 (WP)
1153 */
1154 $url_query_args = [
1155 'option' => 'com_vikbooking',
1156 'task' => 'showprc',
1157 'roomsnum' => '1',
1158 'roomopt' => [
1159 $proomdetail,
1160 ],
1161 'adults' => [
1162 $arrpeople[1]['adults'],
1163 ],
1164 'children' => [
1165 $arrpeople[1]['children'],
1166 ],
1167 'days' => $daysdiff,
1168 'checkin' => $first,
1169 'checkout' => $second,
1170 ];
1171 if (!empty($ppkg_id)) {
1172 $url_query_args['pkg_id'] = $ppkg_id;
1173 }
1174 if (!empty($rate_plan_id)) {
1175 $url_query_args['rate_plan_id'] = $rate_plan_id;
1176 }
1177 if (is_array($children_age) && count($children_age)) {
1178 $url_query_args['children_age'] = $children_age;
1179 }
1180 if (!empty($user_currency)) {
1181 $url_query_args['user_currency'] = $user_currency;
1182 }
1183 if (!empty($pcategory_ids)) {
1184 $url_query_args['category_ids'] = $pcategory_ids;
1185 }
1186 if (!empty($pitemid)) {
1187 $url_query_args['Itemid'] = $pitemid;
1188 }
1189
1190 $mainframe->redirect(JRoute::rewrite('index.php?' . http_build_query($url_query_args), false));
1191 exit;
1192 } else {
1193 if (!empty($proomdetail) && $proomsnum == 1) {
1194 $q = "SELECT `id`,`name` FROM `#__vikbooking_rooms` WHERE `id`=".intval($proomdetail).";";
1195 $dbo->setQuery($q);
1196 $cdet = $dbo->loadAssocList();
1197 if ($cdet) {
1198 $vbo_tn->translateContents($cdet, '#__vikbooking_rooms');
1199 $msg = JText::sprintf('VBDETAILCNOTAVAIL', $cdet[0]['name'], $daysdiff);
1200 VikError::raiseWarning('', $msg);
1201 // VBO 1.11 - push data to tracker and close
1202 VikBooking::getTracker()->pushRooms($proomdetail)->pushMessage($msg, 'warning')->closeTrack();
1203 //
1204 }
1205 } elseif (!empty($proomdetail) && $proomsnum > 1) {
1206 //check whether the user is coming from roomdetails and if the room is available for any room party
1207 $room_missing = false;
1208 foreach ($results as $indroom => $rooms) {
1209 $room_found = false;
1210 foreach ($rooms as $room) {
1211 if ($room[0]['idroom'] == $proomdetail && (!array_key_exists('unitsavail', $room[0]) || $room[0]['unitsavail'] >= $proomsnum)) {
1212 $room_found = true;
1213 break;
1214 }
1215 }
1216 if (!$room_found) {
1217 $room_missing = true;
1218 break;
1219 }
1220 }
1221 if ($room_missing === false) {
1222 $aduchild_str = '';
1223 foreach ($arrpeople as $people) {
1224 $aduchild_str .= '&adults[]='.$people['adults'].'&children[]='.$people['children'];
1225 }
1226 $roomopt_str = '';
1227 for ($ri = 0; $ri < $proomsnum; $ri++) {
1228 $roomopt_str .= '&roomopt[]='.$proomdetail;
1229 }
1230 // store in the session that we are coming from the room details page
1231 $session->set('vboSearchRoomId', $proomdetail);
1232 //
1233 $mainframe->redirect(JRoute::rewrite("index.php?option=com_vikbooking&task=showprc&roomsnum=".$proomsnum.$roomopt_str.$aduchild_str."&days=".$daysdiff."&checkin=".$first."&checkout=".$second.(!empty($ppkg_id) ? "&pkg_id=" . $ppkg_id : "").(!empty($pitemid) ? "&Itemid=" . $pitemid : ""), false));
1234 // VBO 1.11 - push data to tracker and close
1235 VikBooking::getTracker()->pushRooms(array_fill(0, $proomsnum, $proomdetail))->closeTrack();
1236 //
1237 exit;
1238 } else {
1239 $q = "SELECT `id`,`name` FROM `#__vikbooking_rooms` WHERE `id`=".intval($proomdetail).";";
1240 $dbo->setQuery($q);
1241 $cdet = $dbo->loadAssocList();
1242 if ($cdet) {
1243 $vbo_tn->translateContents($cdet, '#__vikbooking_rooms');
1244 $msg = JText::sprintf('VBDETAILMULTIRNOTAVAIL', $proomsnum, $cdet[0]['name'], $daysdiff);
1245 VikError::raiseWarning('', $msg);
1246 // VBO 1.11 - push data to tracker and close
1247 VikBooking::getTracker()->pushMessage($msg, 'warning')->closeTrack();
1248 //
1249 }
1250 }
1251 }
1252 $this->res = $results;
1253 $this->days = $daysdiff;
1254 $this->checkin = $first;
1255 $this->checkout = $second;
1256 $this->roomsnum = $proomsnum;
1257 $this->arrpeople = $arrpeople;
1258 $showchildren = $showchildren ? 1 : 0;
1259 $this->showchildren = $showchildren;
1260 $this->js_overcounter = $js_overcounter;
1261 $this->mod_booking = $mod_booking;
1262 $this->vbo_tn = $vbo_tn;
1263 //theme
1264 $theme = VikBooking::getTheme();
1265 if ($theme != 'default') {
1266 $thdir = VBO_SITE_PATH.DS.'themes'.DS.$theme.DS.'search';
1267 if (is_dir($thdir)) {
1268 $this->_setPath('template', $thdir.DS);
1269 }
1270 }
1271 //
1272
1273 // unset the session if we were coming from the room details page
1274 $session->set('vboSearchRoomId', '');
1275 //
1276
1277 // VBO 1.11 - close tracker
1278 VikBooking::getTracker()->closeTrack();
1279 //
1280
1281 parent::display($tpl);
1282 }
1283 //
1284 } else {
1285 //zero results for some room
1286 $errmess = array();
1287 if (isset($critic) && count($critic) > 0) {
1288 foreach ($critic as $nroom) {
1289 $errmess[] = $arrpeople[$nroom]['adults']." ".($arrpeople[$nroom]['adults'] == 1 ? JText::translate('VBSEARCHRESADULT') : JText::translate('VBSEARCHRESADULTS')).($arrpeople[$nroom]['children'] > 0 ? ", ".$arrpeople[$nroom]['children']." ".($arrpeople[$nroom]['children'] == 1 ? JText::translate('VBSEARCHRESCHILD') : JText::translate('VBSEARCHRESCHILDREN')) : "");
1290 }
1291 $errmess = array_unique($errmess);
1292 } else {
1293 $errmess[] = JText::translate('VBOSEARCHERRCODETHREEBASE');
1294 }
1295 $err_code_info = array(
1296 'code' => 3,
1297 'fromts' => $first,
1298 'tots' => $second,
1299 'party' => $arrpeople
1300 );
1301 $msg = JText::sprintf('VBSEARCHERRNOTENOUGHROOMS', implode(" - ", $errmess));
1302 // VBO 1.11 - push data to tracker and close
1303 VikBooking::getTracker()->pushMessage($msg, 'error')->closeTrack();
1304 //
1305 $this->setVboError($msg, $err_code_info);
1306 }
1307 } else {
1308 $err_code_info = array();
1309 if (strlen($restrictionerrmsg) > 0) {
1310 VikError::raiseWarning('', $restrictionerrmsg);
1311 } else {
1312 $err_code_info = array(
1313 'code' => 1,
1314 'fromts' => $first,
1315 'tots' => $second,
1316 'party' => $arrpeople
1317 );
1318 }
1319 $msg = JText::translate('VBNOROOMSINDATE');
1320 // VBO 1.11 - push data to tracker and close
1321 VikBooking::getTracker()->pushMessage($msg, 'error')->closeTrack();
1322 //
1323 $this->setVboError($msg, $err_code_info);
1324 }
1325 } else {
1326 $sayerr = JText::translate('VBNOROOMAVFOR') . " " . $daysdiff . " " . ($daysdiff > 1 ? JText::translate('VBDAYS') : JText::translate('VBDAY'));
1327 if (count($padults) == 1) {
1328 $sayerr .= ", ".$arrpeople[1]['adults']." ".($arrpeople[1]['adults'] > 1 ? JText::translate('VBSEARCHRESADULTS') : JText::translate('VBSEARCHRESADULT'));
1329 if ($arrpeople[1]['children'] > 0) {
1330 $sayerr .= ", ".$arrpeople[1]['children']." ".($arrpeople[1]['children'] > 1 ? JText::translate('VBSEARCHRESCHILDREN') : JText::translate('VBSEARCHRESCHILD'));
1331 }
1332 }
1333 $err_code_info = array(
1334 'code' => 2,
1335 'fromts' => $first,
1336 'tots' => $second,
1337 'party' => $arrpeople
1338 );
1339 // VBO 1.11 - push data to tracker and close
1340 VikBooking::getTracker()->pushMessage($sayerr, 'error')->closeTrack();
1341 //
1342 $this->setVboError($sayerr, $err_code_info);
1343 }
1344 } else {
1345 $this->setVboError($restrictionerrmsg);
1346 }
1347 } else {
1348 $session->set('vbcheckin', '');
1349 $session->set('vbcheckout', '');
1350 if ($first <= $actnow) {
1351 if (date('d/m/Y', $first) == date('d/m/Y', $actnow)) {
1352 $emess = JText::translate('VBSRCHERRCHKINPASSED');
1353 } else {
1354 $emess = JText::translate('VBSRCHERRCHKINPAST');
1355 }
1356 } else {
1357 $emess = JText::translate('VBPICKBRET');
1358 }
1359 $this->setVboError($emess);
1360 }
1361 } else {
1362 $this->setVboError(JText::translate('VBWRONGDF') . ": " . VikBooking::sayDateFormat());
1363 }
1364 } else {
1365 $this->setVboError(JText::translate('VBSELPRDATE'));
1366 }
1367 } else {
1368 echo VikBooking::getDisabledBookingMsg();
1369 }
1370 }
1371
1372 protected function setVboError($err, $err_code_info = [])
1373 {
1374 $app = JFactory::getApplication();
1375
1376 $ppkg_id = VikRequest::getInt('pkg_id', '', 'request');
1377 $pitemid = VikRequest::getInt('Itemid', '', 'request');
1378
1379 if (!empty($ppkg_id)) {
1380 if (!empty($err)) {
1381 VikError::raiseWarning('', $err);
1382 }
1383
1384 $app->redirect(JRoute::rewrite("index.php?option=com_vikbooking&view=packagedetails&pkgid=".$ppkg_id.(!empty($pitemid) ? "&Itemid=".$pitemid : ""), false));
1385 $app->close();
1386 } else {
1387 showSelectVb($err, $err_code_info);
1388 }
1389 }
1390 }
1391