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
← All changes | site/views/booking/view.html.php +459 -0 1.6.0 → 1.8.16 View file →
@@ -1,0 +1,459 @@
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 VikbookingViewBooking extends JViewVikBooking
16 +{
17 + public function display($tpl = null)
18 + {
19 + $dbo = JFactory::getDbo();
20 + $app = JFactory::getApplication();
21 + $document = JFactory::getDocument();
22 + $vbo_tn = VikBooking::getTranslator();
23 +
24 + // validation of data and availability before the rendering
25 + $sid = VikRequest::getString('sid', '', 'request');
26 + $ts = VikRequest::getString('ts', '', 'request');
27 + if (empty($sid) || empty($ts)) {
28 + showSelectVb(JText::translate('VBINSUFDATA'));
29 + return;
30 + }
31 +
32 + $q = "SELECT `o`.*,(SELECT SUM(`or`.`adults`) FROM `#__vikbooking_ordersrooms` AS `or` WHERE `or`.`idorder`=`o`.`id`) AS `tot_adults` FROM `#__vikbooking_orders` AS `o` WHERE (`o`.`sid`=" . $dbo->quote($sid) . " OR `o`.`idorderota`=" . $dbo->quote($sid) . ") AND `o`.`ts`=" . $dbo->quote($ts);
33 + $dbo->setQuery($q, 0, 1);
34 + $order = $dbo->loadAssoc();
35 + if (!$order) {
36 + showSelectVb(JText::translate('VBORDERNOTFOUND'));
37 + return;
38 + }
39 +
40 + // availability helper
41 + $av_helper = VikBooking::getAvailabilityInstance();
42 +
43 + // room stay dates in case of split stay
44 + $room_stay_dates = [];
45 + if ($order['split_stay']) {
46 + if ($order['status'] == 'confirmed') {
47 + $room_stay_dates = $av_helper->loadSplitStayBusyRecords($order['id']);
48 + } else {
49 + $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $order['id'], []);
50 + }
51 + }
52 +
53 + if ($order['status'] == 'confirmed') {
54 + // prepare impression data for channels
55 + $impressiondata = $order;
56 + $q = "SELECT `or`.`idtar`,`d`.`idprice`,`p`.`idiva`,`t`.`aliq`,`t`.`taxcap` FROM `#__vikbooking_ordersrooms` AS `or` " .
57 + "LEFT JOIN `#__vikbooking_dispcost` `d` ON `d`.`id`=`or`.`idtar` " .
58 + "LEFT JOIN `#__vikbooking_prices` `p` ON `p`.`id`=`d`.`idprice` " .
59 + "LEFT JOIN `#__vikbooking_iva` `t` ON `t`.`id`=`p`.`idiva` " .
60 + "WHERE `or`.`idorder`='".$order['id']."' ORDER BY `t`.`aliq` ASC";
61 + $dbo->setQuery($q, 0, 1);
62 + $taxdata = $dbo->loadAssoc();
63 + if ($taxdata) {
64 + $taxes = 0;
65 + if (!empty($taxdata['aliq'])) {
66 + $realtotal = round(($order['total'] / ((100 + $taxdata['aliq']) / 100)), 2);
67 + $taxes = round(($order['total'] - $realtotal), 2);
68 + /**
69 + * Tax Cap implementation.
70 + *
71 + * @since 1.12
72 + */
73 + if ($taxdata['taxcap'] > 0 && $taxes > $taxdata['taxcap']) {
74 + $realtotal = $order['total'] - $taxdata['taxcap'];
75 + $taxes = $taxdata['taxcap'];
76 + }
77 + $impressiondata['total'] = $realtotal;
78 + }
79 + $impressiondata['taxes'] = $taxes;
80 + $impressiondata['fees'] = 0;
81 + }
82 + VikBooking::invokeChannelManager(true, $impressiondata);
83 + // end prepare impression data for channels
84 + } elseif ($order['status'] == 'standby') {
85 + $roomavail = false;
86 +
87 + $q = $dbo->getQuery(true)
88 + ->select($dbo->qn('or') . '.*')
89 + ->select($dbo->qn('r.units'))
90 + ->from($dbo->qn('#__vikbooking_ordersrooms', 'or'))
91 + ->leftJoin($dbo->qn('#__vikbooking_rooms', 'r') . ' ON ' . $dbo->qn('or.idroom') . ' = ' . $dbo->qn('r.id'))
92 + ->where($dbo->qn('or.idorder') . ' = ' . (int)$order['id'])
93 + ->order($dbo->qn('or.id') . ' ASC');
94 +
95 + $dbo->setQuery($q);
96 + $orderrooms = $dbo->loadAssocList();
97 +
98 + /**
99 + * Even if redundant, we read the eventually occupied records by this booking ID to ensure
100 + * server-side cache will not produce a booking cancellation after receiving a valid payment.
101 + * An eventual list of busy record IDs is passed to the method for checking if the room is
102 + * available, because the status of the reservation may actually be confirmed already.
103 + *
104 + * @since 1.16.9 (J) - 1.6.9 (WP)
105 + */
106 + $dbo->setQuery(
107 + $dbo->getQuery(true)
108 + ->select($dbo->qn('idbusy'))
109 + ->from($dbo->qn('#__vikbooking_ordersbusy'))
110 + ->where($dbo->qn('idorder') . ' = ' . (int)$order['id'])
111 + );
112 + $skip_busy_ids = array_column($dbo->loadAssocList(), 'idbusy');
113 +
114 + foreach ($orderrooms as $kor => $or) {
115 + // determine proper values for this room
116 + $room_stay_checkin = $order['checkin'];
117 + $room_stay_checkout = $order['checkout'];
118 + if ($order['split_stay'] && $room_stay_dates && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
119 + $room_stay_checkin = !empty($room_stay_dates[$kor]['checkin_ts']) ? $room_stay_dates[$kor]['checkin_ts'] : $room_stay_dates[$kor]['checkin'];
120 + $room_stay_checkout = !empty($room_stay_dates[$kor]['checkout_ts']) ? $room_stay_dates[$kor]['checkout_ts'] : $room_stay_dates[$kor]['checkout'];
121 + }
122 +
123 + // make sure room is still available
124 + $roomavail = VikBooking::roomBookable($or['idroom'], $or['units'], $room_stay_checkin, $room_stay_checkout, $skip_busy_ids);
125 + if (!$roomavail) {
126 + break;
127 + }
128 + }
129 +
130 + // tell if the booking has been automatically cancelled
131 + $autoremove = false;
132 +
133 + // make sure we are not beyond the check-in date and time
134 + $today_midnight = mktime(0, 0, 0, date('n'), date('j'), date('Y'));
135 + if ($today_midnight > $order['checkin']) {
136 + $roomavail = false;
137 + }
138 +
139 + /**
140 + * Check if we are dealing with a pending booking solution of a quote.
141 + *
142 + * @since 1.18.8 (J) - 1.8.8 (WP)
143 + */
144 + $quoteValidUntilDt = null;
145 + if (!empty($order['idquote'])) {
146 + // load quote record
147 + $quoteRecord = VBOMvcModel::getInstance('quote')->getItem((int) $order['idquote']);
148 + if (!empty($quoteRecord->valid_until)) {
149 + $quoteValidUntilDt = JFactory::getDate($quoteRecord->valid_until);
150 + }
151 + }
152 +
153 + if ($quoteValidUntilDt) {
154 + // make sure the quote is still valid
155 + if (JFactory::getDate('now') > $quoteValidUntilDt) {
156 + $roomavail = false;
157 + $autoremove = true;
158 + }
159 + } else {
160 + // check global settings for booking auto-cancellation
161 + $minautoremove = VikBooking::getMinutesAutoRemove();
162 + $mins_elapsed = floor((time() - $order['ts']) / 60);
163 + if ($minautoremove > 0 && $mins_elapsed > $minautoremove) {
164 + $roomavail = false;
165 + $autoremove = true;
166 + }
167 + }
168 +
169 + /**
170 + * Make sure not to cancel an OTA pending reservation.
171 + *
172 + * @since 1.15.4 (J) - 1.5.10 (WP)
173 + */
174 + $is_ota_pending = (!empty($order['type']) && !empty($order['channel']));
175 +
176 + if ($roomavail || $is_ota_pending) {
177 + // invoke channel impression
178 + VikBooking::invokeChannelManager(false);
179 + //
180 + } else {
181 + // set the booking to cancelled
182 + $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$order['id'].";";
183 + $dbo->setQuery($q);
184 + $dbo->execute();
185 + // update status in the array
186 + $order['status'] = 'cancelled';
187 + //
188 + $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . (int)$order['id'] . ";";
189 + $dbo->setQuery($q);
190 + $dbo->execute();
191 + $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$order['id'].";";
192 + $dbo->setQuery($q);
193 + $ordbusy = $dbo->loadAssocList();
194 + if ($ordbusy) {
195 + foreach ($ordbusy as $ob) {
196 + $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`=".(int)$ob['idbusy'].";";
197 + $dbo->setQuery($q);
198 + $dbo->execute();
199 + }
200 + }
201 + $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$order['id'].";";
202 + $dbo->setQuery($q);
203 + $dbo->execute();
204 +
205 + /**
206 + * We now save onto a var the full error message to understand what made the booking become cancelled.
207 + * This way, by checking the booking history it will be easy to understand the cause of the issue.
208 + *
209 + * @since October 15th 2020
210 + */
211 + $history_err_descr = '';
212 + if ($today_midnight > $order['checkin']) {
213 + $history_err_descr = JText::translate('VBOBOOKNOLONGERPAYABLE');
214 + } elseif ($autoremove === true) {
215 + $history_err_descr = JText::translate('VBOERRAUTOREMOVED');
216 + } else {
217 + $history_err_descr = JText::translate('VBERRREPSEARCH');
218 + }
219 + if (!empty($history_err_descr)) {
220 + VikError::raiseWarning('', $history_err_descr);
221 + }
222 +
223 + //Booking History
224 + VikBooking::getBookingHistoryInstance()->setBid($order['id'])->store('CA', $history_err_descr);
225 + //
226 + }
227 + }
228 +
229 + // render the booking details
230 +
231 + // set noindex instruction for robots
232 + $document->setMetaData('robots', 'noindex, nofollow');
233 +
234 + // load jQuery
235 + if (VikBooking::loadJquery()) {
236 + JHtml::fetch('jquery.framework', true, true);
237 + }
238 +
239 + $tars = [];
240 + $cookie = $app->input->cookie;
241 + $pcheckin = $order['checkin'];
242 + $pcheckout = $order['checkout'];
243 + $secdiff = $pcheckout - $pcheckin;
244 + $daysdiff = $secdiff / 86400;
245 + if (is_int($daysdiff)) {
246 + if ($daysdiff < 1) {
247 + $daysdiff = 1;
248 + }
249 + } else {
250 + if ($daysdiff < 1) {
251 + $daysdiff = 1;
252 + } else {
253 + $sum = floor($daysdiff) * 86400;
254 + $newdiff = $secdiff - $sum;
255 + $maxhmore = VikBooking::getHoursMoreRb() * 3600;
256 + if ($maxhmore >= $newdiff) {
257 + $daysdiff = floor($daysdiff);
258 + } else {
259 + $daysdiff = ceil($daysdiff);
260 + }
261 + }
262 + }
263 + $is_package = !empty($order['pkg']) ? true : false;
264 +
265 + // get the rooms booked list
266 + $dbo->setQuery(
267 + $dbo->getQuery(true)
268 + ->select($dbo->qn('or') . '.*')
269 + ->select($dbo->qn('r.id', 'r_reference_id'))
270 + ->select([
271 + $dbo->qn('r.name'),
272 + $dbo->qn('r.img'),
273 + $dbo->qn('r.idcarat'),
274 + $dbo->qn('r.fromadult'),
275 + $dbo->qn('r.toadult'),
276 + ])
277 + ->from($dbo->qn('#__vikbooking_ordersrooms', 'or'))
278 + ->leftJoin($dbo->qn('#__vikbooking_rooms', 'r') . ' ON ' . $dbo->qn('or.idroom') . ' = ' . $dbo->qn('r.id'))
279 + ->where($dbo->qn('or.idorder') . ' = ' . (int)$order['id'])
280 + ->order($dbo->qn('or.id') . ' ASC')
281 + );
282 + $orderrooms = $dbo->loadAssocList();
283 +
284 + if ($orderrooms) {
285 + $vbo_tn->translateContents($orderrooms, '#__vikbooking_rooms', array('id' => 'r_reference_id'));
286 + foreach ($orderrooms as $kor => $or) {
287 + $num = $kor + 1;
288 + if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
289 + //package or custom cost set from the back-end
290 + continue;
291 + }
292 + $q = "SELECT `t`.*,`p`.`name`,`p`.`free_cancellation`,`p`.`canc_deadline`,`p`.`canc_policy` FROM `#__vikbooking_dispcost` AS `t` LEFT JOIN `#__vikbooking_prices` AS `p` ON `t`.`idprice`=`p`.`id` WHERE `t`.`id`=" . (int)$or['idtar'] . ";";
293 + $dbo->setQuery($q);
294 + $tar = $dbo->loadAssocList();
295 + if (!$tar) {
296 + continue;
297 + }
298 + $vbo_tn->translateContents($tar, '#__vikbooking_prices', array('id' => 'idprice'));
299 +
300 + // determine proper values for this room
301 + $room_stay_checkin = $order['checkin'];
302 + $room_stay_checkout = $order['checkout'];
303 + $room_stay_nights = $order['days'];
304 + if ($order['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
305 + $room_stay_checkin = !empty($room_stay_dates[$kor]['checkin_ts']) ? $room_stay_dates[$kor]['checkin_ts'] : $room_stay_dates[$kor]['checkin'];
306 + $room_stay_checkout = !empty($room_stay_dates[$kor]['checkout_ts']) ? $room_stay_dates[$kor]['checkout_ts'] : $room_stay_dates[$kor]['checkout'];
307 + $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
308 + }
309 +
310 + // apply seasonal rates
311 + $tar = VikBooking::applySeasonsRoom($tar, $room_stay_checkin, $room_stay_checkout);
312 +
313 + // apply OBP rules
314 + $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
315 +
316 + // push tariffs
317 + $tars[$num] = $tar[0];
318 + }
319 + }
320 +
321 + $days_to_arrival = 0;
322 + $now_info = getdate();
323 + $checkin_info = getdate($order['checkin']);
324 + if ($now_info[0] < $checkin_info[0]) {
325 + while ($now_info[0] < $checkin_info[0]) {
326 + if (!($now_info['mday'] != $checkin_info['mday'] || $now_info['mon'] != $checkin_info['mon'] || $now_info['year'] != $checkin_info['year'])) {
327 + break;
328 + }
329 + $days_to_arrival++;
330 + $now_info = getdate(mktime(0, 0, 0, $now_info['mon'], ($now_info['mday'] + 1), $now_info['year']));
331 + }
332 + }
333 +
334 + $is_refundable = 0;
335 + $daysadv_refund_arr = [];
336 + $daysadv_refund = 0;
337 + $canc_policy = '';
338 + foreach ($tars as $num => $tar) {
339 + if ($tar['free_cancellation'] < 1) {
340 + // if at least one rate plan is non-refundable, the whole reservation cannot be cancelled
341 + $is_refundable = 0;
342 + $daysadv_refund_arr = [];
343 + break;
344 + }
345 + $is_refundable = 1;
346 + $daysadv_refund_arr[] = $tar['canc_deadline'];
347 + }
348 +
349 + // get the rate plan with the lowest cancellation deadline
350 + $daysadv_refund = count($daysadv_refund_arr) > 0 ? min($daysadv_refund_arr) : $daysadv_refund;
351 + if ($daysadv_refund > 0) {
352 + foreach ($tars as $num => $tar) {
353 + if ($tar['free_cancellation'] > 0 && $tar['canc_deadline'] == $daysadv_refund) {
354 + //get the cancellation policy from the first rate plan with free cancellation and same cancellation deadline
355 + $canc_policy = $tar['canc_policy'];
356 + break;
357 + }
358 + }
359 + }
360 +
361 + $payment = "";
362 + if (!empty($order['idpayment'])) {
363 + $exppay = explode('=', $order['idpayment']);
364 + $payment = VikBooking::getPayment($exppay[0], $vbo_tn);
365 + }
366 + $pnodep = VikRequest::getString('nodep', '', 'request');
367 + $cnodep = $cookie->get('vboFA', '', 'string');
368 + $nodep = intval($pnodep) > 0 || intval($cnodep) > 0 ? 1 : 0;
369 +
370 + /**
371 + * Scan the booking and related rooms for damage deposit payment data.
372 + * Obtain also the information about possible previous payments.
373 + *
374 + * @since 1.17.6 (J) - 1.7.6 (WP)
375 + */
376 + $damage_deposit_payment = VBORoomHelper::getInstance()->getDamageDepositSplitPayment($order, $orderrooms);
377 + $prev_dd_payments = [];
378 + if ($damage_deposit_payment['damagedep_gross'] ?? 0) {
379 + $prev_dd_payments = VikBooking::getBookingHistoryInstance($order['id'])
380 + ->getEventsWithData('PN', function($data) {
381 + return (is_object($data) && !empty($data->damage_deposit));
382 + });
383 + if (!$prev_dd_payments) {
384 + // check also the first payment event in case of OTA bookings
385 + $prev_dd_payments = VikBooking::getBookingHistoryInstance($order['id'])
386 + ->getEventsWithData('P0', function($data) {
387 + return (is_object($data) && !empty($data->damage_deposit));
388 + });
389 + }
390 + }
391 +
392 + /**
393 + * Upselling extra services only for non-cancelled bookings
394 + * with a check-out date in the future.
395 + *
396 + * @since 1.13.0 (J) - 1.3.0 (WP)
397 + */
398 + $upselling = [];
399 + if ($order['status'] != 'cancelled' && VikBooking::upsellingEnabled() && $order['checkout'] > time()) {
400 + $upsell_data = [];
401 + foreach ($orderrooms as $kor => $or) {
402 + $room_data = new stdClass;
403 + $room_data->id = $or['idroom'];
404 + $room_data->name = $or['name'];
405 + $room_data->img = $or['img'];
406 + $room_data->adults = $or['adults'];
407 + $room_data->children = $or['children'];
408 + $room_data->nights = $order['days'];
409 + $room_data->options = [];
410 + if (!empty($or['optionals'])) {
411 + $optids = explode(';', $or['optionals']);
412 + foreach ($optids as $optid) {
413 + if (!empty($optid)) {
414 + // the : may express the quantity
415 + $optidparts = explode(':', $optid);
416 + array_push($room_data->options, (int)$optidparts[0]);
417 + }
418 + }
419 + }
420 + array_push($upsell_data, $room_data);
421 + }
422 + $upselling = VikBooking::loadUpsellingData($upsell_data, $order, $vbo_tn);
423 + }
424 +
425 + /**
426 + * Trigger first tracking conversion on booking.
427 + *
428 + * @since 1.16.3 (J) - 1.6.3 (WP)
429 + */
430 + VikBooking::getTracker()->triggerBookingConversion($order);
431 +
432 + $this->ord = $order;
433 + $this->orderrooms = $orderrooms;
434 + $this->tars = $tars;
435 + $this->days_to_arrival = $days_to_arrival;
436 + $this->is_refundable = $is_refundable;
437 + $this->daysadv_refund = $daysadv_refund;
438 + $this->canc_policy = $canc_policy;
439 + $this->payment = $payment;
440 + $this->nodep = $nodep;
441 + $this->upselling = $upselling;
442 + $this->damage_deposit_payment = $damage_deposit_payment;
443 + $this->prev_dd_payments = $prev_dd_payments;
444 + $this->quoteValidUntilDt = $quoteValidUntilDt ?? null;
445 + $this->vbo_tn = $vbo_tn;
446 +
447 + // theme
448 + $theme = VikBooking::getTheme();
449 + if ($theme != 'default') {
450 + $thdir = VBO_SITE_PATH . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $theme . DIRECTORY_SEPARATOR . 'booking';
451 + if (is_dir($thdir)) {
452 + $this->_setPath('template', $thdir . DIRECTORY_SEPARATOR);
453 + }
454 + }
455 + //
456 +
457 + parent::display($tpl);
458 + }
459 +}