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

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