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 / booking / view.html.php

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

460 lines 16.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 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 }
460