PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.15
VikBooking Hotel Booking Engine & PMS v1.8.15
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 1.7.3 All 36 releases
vikbooking / site / views / search / view.html.php

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

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