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 / tmpl / default.php

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

2,201 lines 92.1 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 $ord = $this->ord;
14 $orderrooms = $this->orderrooms;
15 $tars = $this->tars;
16 $payment = $this->payment;
17 $vbo_tn = $this->vbo_tn;
18
19 /**
20 * Include the VBOCore JS class.
21 */
22 VikBooking::getVboApplication()->loadCoreJS();
23
24 // availability helper
25 $av_helper = VikBooking::getAvailabilityInstance();
26
27 // room stay dates in case of split stay
28 $room_stay_dates = [];
29 if ($ord['split_stay']) {
30 if ($ord['status'] == 'confirmed') {
31 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
32 } else {
33 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
34 }
35 }
36
37 // construct booking registry
38 try {
39 $registry = VBOBookingRegistry::getInstance($this->ord, $this->orderrooms);
40 } catch (Exception $e) {
41 // do nothing
42 $registry = null;
43 }
44
45 $currencysymb = VikBooking::getCurrencySymb();
46 $nowdf = VikBooking::getDateFormat();
47 if ($nowdf == "%d/%m/%Y") {
48 $df = 'd/m/Y';
49 } elseif ($nowdf == "%m/%d/%Y") {
50 $df = 'm/d/Y';
51 } else {
52 $df = 'Y/m/d';
53 }
54 $datesep = VikBooking::getDateSeparator();
55 $ptmpl = VikRequest::getString('tmpl', '', 'request');
56 $pitemid = VikRequest::getInt('Itemid', 0, 'request');
57 $bestitemid = VikBooking::findProperItemIdType(['booking']);
58 $now_info = getdate();
59
60 $wdays_map = [
61 JText::translate('VBWEEKDAYZERO'),
62 JText::translate('VBWEEKDAYONE'),
63 JText::translate('VBWEEKDAYTWO'),
64 JText::translate('VBWEEKDAYTHREE'),
65 JText::translate('VBWEEKDAYFOUR'),
66 JText::translate('VBWEEKDAYFIVE'),
67 JText::translate('VBWEEKDAYSIX')
68 ];
69
70 // count payment processor instances
71 $payProcessorInstances = 0;
72
73 $isdue = 0;
74 $isdue_orig = 0;
75 $imp = 0;
76 $pricenames = array();
77 $optbought = array();
78 $extraservices = array();
79 $roomsnames = array();
80 $is_package = !empty($ord['pkg']) ? true : false;
81 foreach ($orderrooms as $kor => $or) {
82 $num = $kor + 1;
83 $roomsnames[] = $or['name'];
84
85 // determine proper values for this room
86 $room_stay_checkin = $ord['checkin'];
87 $room_stay_checkout = $ord['checkout'];
88 $room_stay_nights = $ord['days'];
89 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
90 $room_stay_checkin = !empty($room_stay_dates[$kor]['checkin_ts']) ? $room_stay_dates[$kor]['checkin_ts'] : $room_stay_dates[$kor]['checkin'];
91 $room_stay_checkout = !empty($room_stay_dates[$kor]['checkout_ts']) ? $room_stay_dates[$kor]['checkout_ts'] : $room_stay_dates[$kor]['checkout'];
92 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
93 // inject nights calculated for this room
94 $room_stay_dates[$kor]['nights'] = $room_stay_nights;
95 }
96
97 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
98 // package cost or cust_cost may not be inclusive of taxes if prices tax included is off
99 $calctar = VikBooking::sayPackagePlusIva($or['cust_cost'], $or['cust_idiva']);
100 $isdue += $calctar;
101 $isdue_orig += $calctar;
102 $imp += VikBooking::sayPackageMinusIva($or['cust_cost'], $or['cust_idiva']);
103 $pricenames[$num] = (!empty($or['pkg_name']) ? $or['pkg_name'] : (!empty($or['otarplan']) ? $or['otarplan'] : JText::translate('VBOROOMCUSTRATEPLAN')));
104 } elseif (array_key_exists($num, $tars) && is_array($tars[$num])) {
105 $display_rate = $ord['status'] != 'confirmed' && !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
106 $calctar = VikBooking::sayCostPlusIva($display_rate, $tars[$num]['idprice']);
107 $tars[$num]['calctar'] = $calctar;
108 $isdue += $calctar;
109 $isdue_orig += $or['room_cost'];
110 $imp += VikBooking::sayCostMinusIva($display_rate, $tars[$num]['idprice']);
111 $pricenames[$num] = VikBooking::getPriceName($tars[$num]['idprice'], $vbo_tn);
112 }
113 if (!empty($or['optionals'])) {
114 $stepo = explode(";", $or['optionals']);
115 foreach ($stepo as $roptkey => $one) {
116 if (empty($one)) {
117 continue;
118 }
119 $stept = explode(":", $one);
120 $actopt = VikBooking::getSingleOption($stept[0], $vbo_tn);
121 if (!$actopt) {
122 continue;
123 }
124 $chvar = '';
125 if (!empty($actopt['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
126 $optagenames = VikBooking::getOptionIntervalsAges($actopt['ageintervals']);
127 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt['ageintervals']);
128 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt, $or['adults'], $or['children']);
129 $child_num = VikBooking::getRoomOptionChildNumber($or['optionals'], $actopt['id'], $roptkey, $or['children']);
130 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt['ageintervals']);
131 $agestept = explode('-', $stept[1]);
132 $stept[1] = $agestept[0];
133 $chvar = $agestept[1];
134 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
135 //percentage value of the adults tariff
136 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
137 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
138 } else {
139 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
140 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
141 }
142 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
143 //VBO 1.10 - percentage value of room base cost
144 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
145 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
146 } else {
147 $display_rate = isset($tars[$num]['room_base_cost']) ? $tars[$num]['room_base_cost'] : (!empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost']);
148 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
149 }
150 }
151 $actopt['chageintv'] = $chvar;
152 $actopt['name'] .= ' (' . ($optagenames[($chvar - 1)] ?? '') . ')';
153 $realcost = (intval($actopt['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)] ?? 0) * $room_stay_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)] ?? 0) * $stept[1]));
154 } else {
155 // VBO 1.11 - options percentage cost of the room total fee
156 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
157 $deftar_basecosts = $or['cust_cost'];
158 } else {
159 $deftar_basecosts = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
160 }
161 $actopt['cost'] = (int)$actopt['pcentroom'] ? ($deftar_basecosts * $actopt['cost'] / 100) : $actopt['cost'];
162 //
163 $realcost = (intval($actopt['perday']) == 1 ? ($actopt['cost'] * $room_stay_nights * $stept[1]) : ($actopt['cost'] * $stept[1]));
164 }
165 if (!empty($actopt['maxprice']) && $actopt['maxprice'] > 0 && $realcost > $actopt['maxprice']) {
166 $realcost = $actopt['maxprice'];
167 if (intval($actopt['hmany']) == 1 && intval($stept[1]) > 1) {
168 $realcost = $actopt['maxprice'] * $stept[1];
169 }
170 }
171 if ($actopt['perperson'] == 1) {
172 $realcost = $realcost * $or['adults'];
173 }
174
175 /**
176 * Trigger event to allow third party plugins to apply a custom calculation for the option/extra fee or tax.
177 *
178 * @since 1.17.7 (J) - 1.7.7 (WP)
179 */
180 $custom_calculation = VBOFactory::getPlatform()->getDispatcher()->filter('onCalculateBookingOptionFeeCost', [$realcost, &$actopt, $ord, $or]);
181 if ($custom_calculation) {
182 $realcost = (float) $custom_calculation[0];
183 }
184
185 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt['idiva']);
186 $isdue += $tmpopr;
187 $isdue_orig += $tmpopr;
188 $imp += VikBooking::sayOptionalsMinusIva($realcost, $actopt['idiva']);
189 if (!isset($optbought[$num])) {
190 $optbought[$num] = '';
191 }
192 $optbought[$num] .= "<div class=\"vbo-booking-item-row\"><span class=\"vbo-booking-pricename\">".($stept[1] > 1 ? $stept[1] . " " : "") . $actopt['name'] . "</span> <span class=\"vbo-booking-pricedet\">" . VikBooking::formatCurrencyNumber(VikBooking::numberFormat($tmpopr), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']) . "</span></div>";
193 }
194 }
195
196 // custom extra costs
197 if (!empty($or['extracosts'])) {
198 $extraservices[$num] = '';
199 $cur_extra_costs = json_decode($or['extracosts'], true);
200 foreach ($cur_extra_costs as $eck => $ecv) {
201 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
202 $isdue += $ecplustax;
203 $isdue_orig += $ecplustax;
204 $imp += !empty($ecv['idtax']) ? VikBooking::sayOptionalsMinusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
205 $extraservices[$num] .= "<div class=\"vbo-booking-item-row\"><span class=\"vbo-booking-pricename\">".$ecv['name']."</span> <span class=\"vbo-booking-pricedet\">" . VikBooking::formatCurrencyNumber(VikBooking::numberFormat($ecplustax), $currencysymb, ['<span class="vbo_currency">%s</span>' , '<span class="vbo_price">%s</span>']) . "</span></div>";
206 }
207 }
208 }
209
210 $tax = $isdue - $imp;
211
212 $usedcoupon = false;
213 $origisdue = $isdue;
214 if (strlen((string)$ord['coupon']) > 0) {
215 $usedcoupon = true;
216 $expcoupon = explode(";", $ord['coupon']);
217 $isdue = $isdue - $expcoupon[1];
218 $isdue_orig = $isdue_orig - $expcoupon[1];
219 }
220
221 if ($ord['refund'] > 0) {
222 $isdue -= $ord['refund'];
223 $isdue_orig -= $ord['refund'];
224 }
225
226 //Check whether the booking total amount has changed due to rates modifications for these dates, made after this booking
227 $rooms_total_changed = ($ord['status'] == 'confirmed' && number_format($isdue, 2) != number_format($ord['total'], 2) && number_format($origisdue, 2) != number_format($ord['total'], 2));
228 $only_roomsrates_changed = ($rooms_total_changed === true && number_format($isdue_orig, 2) == number_format($ord['total'], 2));
229
230 //booking modification, cancellation and request
231 $resmodcanc = VikBooking::getReservationModCanc();
232 $resmodcanc = $this->days_to_arrival < 1 ? 0 : $resmodcanc;
233 $resmodcancmin = VikBooking::getReservationModCancMin();
234 $mod_allowed = ($resmodcanc > 1 && $resmodcanc != 3 && $this->days_to_arrival >= $resmodcancmin);
235 $canc_allowed = ($resmodcanc > 1 && $resmodcanc != 2 && $this->is_refundable > 0 && $this->daysadv_refund <= $this->days_to_arrival && $this->days_to_arrival >= $resmodcancmin);
236
237 $ts_info = getdate($ord['ts']);
238 $checkin_info = getdate($ord['checkin']);
239 $checkout_info = getdate($ord['checkout']);
240
241 /**
242 * Custom listing check-in and check-out times.
243 *
244 * @since 1.18.3 (J) - 1.8.3 (WP)
245 */
246 $listing_params = '';
247 $listing_custom_checkin = '';
248 $listing_custom_checkout = '';
249 if (($ord['roomsnum'] ?? 0) == 1) {
250 $listing_params = VikBooking::getRoomInfo(($orderrooms[(key($orderrooms))]['idroom'] ?? 0), ['params'], true, true)['params'] ?? '';
251 $listing_custom_checkin = VikBooking::getRoomParam('checkin', $listing_params);
252 $listing_custom_checkout = VikBooking::getRoomParam('checkout', $listing_params);
253 }
254
255 // the current booking URI
256 $current_booking_uri = JRoute::rewrite('index.php?option=com_vikbooking&view=booking&sid='.(!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']).'&ts='.$ord['ts'].(!empty($bestitemid) ? '&Itemid='.$bestitemid : (!empty($pitemid) ? '&Itemid='.$pitemid : '')));
257 ?>
258 <a class="vbo-current-booking-uri" href="<?php echo $current_booking_uri; ?>" style="display: none;"></a>
259 <?php
260
261 //print button
262 if ($ord['status'] == 'confirmed' && $ptmpl != 'component') {
263 ?>
264 <div class="vbo-booking-print">
265 <a class="vbo-booking-print-link" href="<?php echo JRoute::rewrite('index.php?option=com_vikbooking&view=booking&sid='.(!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']).'&ts='.$ord['ts'].'&tmpl=component'.(!empty($bestitemid) ? '&Itemid='.$bestitemid : (!empty($pitemid) ? '&Itemid='.$pitemid : ''))); ?>" target="_blank" title="<?php echo JText::translate('VBOPRINT'); ?>"><?php VikBookingIcons::e('print'); ?></a>
266 </div>
267 <?php
268 }
269
270 if ($ord['status'] == 'confirmed') {
271 $head_css = 'vbo-booking-details-head-confirmed';
272 ?>
273 <h3 class="vbo-booking-details-intro"><?php echo JText::sprintf('VBOYOURBOOKCONFAT', VikBooking::getFrontTitle()); ?></h3>
274 <?php
275 } elseif ($ord['status'] == 'cancelled') {
276 $head_css = 'vbo-booking-details-head-cancelled';
277 } else {
278 $head_css = 'vbo-booking-details-head-pending';
279 }
280 ?>
281
282 <div class="vbo-booking-details-topcontainer">
283
284 <div class="vbo-booking-details-head <?php echo $head_css; ?>">
285 <?php
286 if ($ord['status'] == 'confirmed') {
287 ?>
288 <h4><?php echo JText::translate('VBOYOURBOOKISCONF'); ?></h4>
289 <?php
290 } elseif ($ord['status'] != 'cancelled') {
291 ?>
292 <h4><?php echo JText::translate('VBOYOURBOOKISPEND'); ?></h4>
293 <?php
294 } else {
295 ?>
296 <h4><?php echo JText::translate('VBOYOURBOOKISCANC'); ?></h4>
297 <?php
298 }
299 ?>
300 </div>
301
302 <div class="vbo-paycontainer-pos vbo-paycontainer-pos-top" style="display: none;"></div>
303
304 <div class="vbo-booking-details-midcontainer">
305
306 <div class="vbo-booking-details-bookinfos">
307 <span class="vbvordudatatitle"><?php echo JText::translate('VBORDERDETAILS'); ?></span>
308 <div class="vbo-booking-details-bookinfo">
309 <span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBORDEREDON'); ?></span>
310 <span class="vbo-booking-details-bookinfo-val"><?php echo $wdays_map[$ts_info['wday']].', '.date(str_replace("/", $datesep, $df).' H:i', $ord['ts']); ?></span>
311 </div>
312 <?php
313 if (!empty($ord['idorderota']) && !empty($ord['channel'])) {
314 ?>
315 <div class="vbo-booking-details-bookinfo">
316 <span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBORDERNUMBER'); ?></span>
317 <span class="vbo-booking-details-bookinfo-val"><?php echo $ord['idorderota']; ?></span>
318 </div>
319 <?php
320 }
321 if ($ord['status'] == 'confirmed') {
322 ?>
323 <div class="vbo-booking-details-bookinfo">
324 <span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBCONFIRMNUMB'); ?></span>
325 <span class="vbo-booking-details-bookinfo-val"><?php echo $ord['confirmnumber']; ?></span>
326 </div>
327 <?php
328 }
329 ?>
330 <div class="vbo-booking-details-bookinfo">
331 <span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBDAL'); ?></span>
332 <span class="vbo-booking-details-bookinfo-val"><?php
333 if ($listing_custom_checkin) {
334 echo $wdays_map[$checkin_info['wday']] . ', ' . date(str_replace("/", $datesep, $df), $ord['checkin']) . ' ' . $listing_custom_checkin;
335 } else {
336 echo $wdays_map[$checkin_info['wday']] . ', ' . date(str_replace("/", $datesep, $df) . ' H:i', $ord['checkin']);
337 }
338 ?></span>
339 </div>
340 <div class="vbo-booking-details-bookinfo">
341 <span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBAL'); ?></span>
342 <span class="vbo-booking-details-bookinfo-val"><?php
343 if ($listing_custom_checkout) {
344 echo $wdays_map[$checkout_info['wday']] . ', ' . date(str_replace("/", $datesep, $df), $ord['checkout']) . ' ' . $listing_custom_checkout;
345 } else {
346 echo $wdays_map[$checkout_info['wday']] . ', ' . date(str_replace("/", $datesep, $df) . ' H:i', $ord['checkout']);
347 }
348 ?></span>
349 </div>
350 <div class="vbo-booking-details-bookinfo">
351 <span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBDAYS'); ?></span>
352 <span class="vbo-booking-details-bookinfo-val"><?php echo $ord['days']; ?></span>
353 </div>
354 <?php
355 if ($ord['split_stay']) {
356 ?>
357 <div class="vbo-booking-details-bookinfo vbo-booking-details-bookinfo-splitstay">
358 <span class="vbo-booking-details-bookinfo-lbl"><?php VikBookingIcons::e('random'); ?> <?php echo JText::translate('VBO_SPLIT_STAY_RES'); ?></span>
359 </div>
360 <?php
361 }
362 ?>
363 </div>
364
365 <div class="vbo-booking-details-udets">
366 <span class="vbvordudatatitle"><?php echo JText::translate('VBPERSDETS'); ?></span>
367 <div class="vbo-bookingdet-custdata">
368 <?php
369 $custdata_parts = explode("\n", $ord['custdata']);
370 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
371 //attempt to format labels and values
372 foreach ($custdata_parts as $custdet) {
373 if (strlen((string)$custdet) < 1) {
374 continue;
375 }
376 $custdet_parts = explode(':', $custdet);
377 $custd_lbl = '';
378 $custd_val = '';
379 if (count($custdet_parts) < 2) {
380 $custd_val = $custdet;
381 } else {
382 $custd_lbl = $custdet_parts[0];
383 unset($custdet_parts[0]);
384 $custd_val = trim(implode(':', $custdet_parts));
385 }
386 ?>
387 <div class="vbo-bookingdet-userdetail">
388 <?php
389 if (strlen((string)$custd_lbl)) {
390 ?>
391 <span class="vbo-bookingdet-userdetail-lbl"><?php echo VikBooking::tnCustomerRawDataLabel($custd_lbl); ?></span>
392 <?php
393 }
394 if (strlen((string)$custd_val)) {
395 ?>
396 <span class="vbo-bookingdet-userdetail-val"><?php echo $custd_val; ?></span>
397 <?php
398 }
399 ?>
400 </div>
401 <?php
402 }
403 } else {
404 echo nl2br($ord['custdata']);
405 }
406 ?>
407 </div>
408 </div>
409 <?php
410 // booking modification, cancellation, pre check-in or modification request (confirmed status only)
411 $precheckin = VikBooking::precheckinEnabled();
412 if ($precheckin) {
413 // make sure the limit of days in advance is reflected
414 $precheckin_mind = VikBooking::precheckinMinOffset();
415 if ($precheckin_mind < 0) {
416 // validation made prior to check-out date and time
417 $precheckin = time() <= strtotime("{$precheckin_mind} days 23:59:59", $ord['checkout']);
418 } else {
419 // classic validation prior to check-in date and time
420 $precheckin_lim_ts = strtotime("+{$precheckin_mind} days 00:00:00");
421 $precheckin = ($precheckin_lim_ts <= $ord['checkin'] || ($precheckin_mind === 1 && time() <= $ord['checkin']));
422 }
423 }
424
425 /**
426 * If this is an OTA booking, try to print the OTA logo.
427 *
428 * @since 1.13
429 */
430 $isotabooking = (!empty($ord['idorderota']) && !empty($ord['channel']));
431 $otalogo = false;
432 if ($isotabooking) {
433 $otalogo = VikBooking::getVcmChannelsLogo($ord['channel']);
434 }
435 //
436
437 /**
438 * Booking guest review
439 *
440 * @since 1.13
441 */
442 $canbereviewed = VikBooking::canBookingBeReviewed($ord);
443 //
444
445 if ($ord['status'] == 'confirmed' && ($precheckin || $canbereviewed || $mod_allowed || $canc_allowed || ($resmodcanc === 1 && $this->days_to_arrival >= $resmodcancmin) || $otalogo || count($this->upselling))) {
446 ?>
447 <div class="vbo-booking-details-actions">
448 <div class="vbo-booking-details-actions-inner">
449 <?php
450 if ($otalogo) {
451 ?>
452 <div class="vbo-booking-mod-container vbo-booking-otabooking-wrap">
453 <div class="vbo-booking-mod-inner">
454 <div class="vbo-booking-mod-cmd">
455 <img class="vbo-otabooking-logo" src="<?php echo $otalogo; ?>" alt="<?php echo htmlspecialchars($ord['idorderota']); ?>" title="<?php echo htmlspecialchars($ord['idorderota']); ?>" />
456 </div>
457 </div>
458 </div>
459 <?php
460 }
461 if ($precheckin) {
462 $start_itemid = VikBooking::findProperItemIdType(['booking', 'vikbooking']);
463 ?>
464 <div class="vbo-booking-mod-container">
465 <div class="vbo-booking-mod-inner">
466 <div class="vbo-booking-mod-cmd vbo-booking-precheckin-cmd">
467 <a href="<?php echo JRoute::rewrite('index.php?option=com_vikbooking&view=precheckin&sid='.(!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']).'&ts='.$ord['ts'].(!empty($pitemid) ? '&Itemid='.$pitemid : (!empty($start_itemid) ? '&Itemid='.$start_itemid : ''))); ?>"><?php VikBookingIcons::e('users'); ?> <?php echo JText::translate('VBOPRECHECKIN'); ?></a>
468 </div>
469 </div>
470 </div>
471 <?php
472 }
473 if ($canbereviewed) {
474 $start_itemid = VikBooking::findProperItemIdType(['booking', 'vikbooking']);
475 ?>
476 <div class="vbo-booking-mod-container">
477 <div class="vbo-booking-mod-inner">
478 <div class="vbo-booking-mod-cmd vbo-booking-review-cmd">
479 <a href="<?php echo JRoute::rewrite('index.php?option=com_vikbooking&view=revstay&sid='.(!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']).'&ts='.$ord['ts'].(!empty($pitemid) ? '&Itemid='.$pitemid : (!empty($start_itemid) ? '&Itemid='.$start_itemid : ''))); ?>"><?php VikBookingIcons::e('star'); ?> <?php echo JText::translate('VBOLEAVEAREVIEW'); ?></a>
480 </div>
481 </div>
482 </div>
483 <?php
484 }
485 if ($mod_allowed && !$isotabooking && !$ord['split_stay']) {
486 $start_itemid = VikBooking::findProperItemIdType(['vikbooking', 'roomslist']);
487 ?>
488 <div class="vbo-booking-mod-container">
489 <div class="vbo-booking-mod-inner">
490 <div class="vbo-booking-mod-cmd">
491 <a onclick="return confirm('<?php echo addslashes(JText::translate('VBOMODYOURBOOKINGCONF')); ?>');" href="<?php echo JRoute::rewrite('index.php?option=com_vikbooking&view=vikbooking&modify_sid='.$ord['sid'].'&modify_id='.$ord['id'].(!empty($pitemid) ? '&Itemid='.$pitemid : (!empty($start_itemid) ? '&Itemid='.$start_itemid : ''))); ?>"><?php VikBookingIcons::e('edit'); ?> <?php echo JText::translate('VBOMODYOURBOOKING'); ?></a>
492 </div>
493 </div>
494 </div>
495 <?php
496 /**
497 * Suggest room upgrade options, if any.
498 *
499 * @since 1.16.0 (J) - 1.6.0 (WP)
500 */
501 echo $this->loadTemplate('upgrade');
502 }
503 if ($canc_allowed && !$isotabooking) {
504 ?>
505 <div class="vbo-booking-canc-container">
506 <div class="vbo-booking-canc-inner">
507 <div class="vbo-booking-canc-cmd">
508 <span onclick="document.getElementById('vbo-booking-cancform-container').style.display='block';location.hash='bcancf';"><?php VikBookingIcons::e('times-circle'); ?> <?php echo JText::translate('VBOCANCYOURBOOKING'); ?></span>
509 </div>
510 </div>
511 </div>
512 <?php
513 }
514 if ($resmodcanc === 1 && $this->days_to_arrival >= $resmodcancmin && !$isotabooking) {
515 ?>
516 <div class="vbo-booking-mod-container">
517 <div class="vbo-booking-mod-inner">
518 <div class="vbo-booking-mod-cmd">
519 <a onclick="vbOpenCancOrdForm();" href="javascript: void(0);"><?php VikBookingIcons::e('envelope'); ?> <?php echo JText::translate('VBREQUESTCANCMOD'); ?></a>
520 </div>
521 </div>
522 </div>
523 <?php
524 }
525 if (count($this->upselling)) {
526 ?>
527 <div class="vbo-hidein-print vbo-booking-mod-container vbo-booking-upselling-wrap">
528 <div class="vbo-booking-mod-inner">
529 <div class="vbo-booking-mod-cmd">
530 <a onclick="vbGotoUpsell();" href="javascript: void(0);"><?php VikBookingIcons::e('cart-plus'); ?> <?php echo JText::translate('VBOADDEXTRASTOBOOK'); ?></a>
531 </div>
532 </div>
533 </div>
534 <?php
535 }
536 ?>
537 </div>
538 </div>
539 <?php
540 }
541 ?>
542
543 </div>
544
545 <div class="vbo-paycontainer-pos vbo-paycontainer-pos-middle" style="display: none;"></div>
546
547 </div>
548
549 <div class="vbo-booking-rooms-wrapper">
550 <?php
551 foreach ($orderrooms as $kor => $or) {
552 // 1-based index
553 $num = $kor + 1;
554
555 // access current listing parameters
556 if (($ord['roomsnum'] ?? 0) > 1 || !$listing_params) {
557 // load parameters
558 $listing_params = VikBooking::getRoomInfo($or['idroom'], ['params'], true, true)['params'] ?? '';
559 }
560 ?>
561 <div class="vbvordroominfo<?php echo count($orderrooms) > 1 ? ' vbvordroominfo-multi' : ''; ?>">
562 <?php
563 if (strlen((string)$or['img']) > 0) {
564 ?>
565 <div class="vbo-booking-roomphoto">
566 <img src="<?php echo VBO_SITE_URI; ?>resources/uploads/<?php echo $or['img']; ?>"/>
567 </div>
568 <?php
569 }
570 ?>
571 <div class="vbordroomdet">
572 <span class="vbvordroominfotitle"><?php echo $or['name']; ?></span>
573 <div class="vbordroomdetpeople">
574 <span class="vbo-booking-numadults"><?php echo $or['adults']; ?> <?php echo ($or['adults'] == 1 ? JText::translate('VBSEARCHRESADULT') : JText::translate('VBSEARCHRESADULTS')); ?></span>
575 <?php
576 if ($or['children'] > 0) {
577 ?>
578 <span class="vbo-booking-numchildren"><?php echo $or['children']." ".($or['children'] == 1 ? JText::translate('VBSEARCHRESCHILD') : JText::translate('VBSEARCHRESCHILDREN')); ?></span>
579 <?php
580 }
581 ?>
582 </div>
583 <?php
584 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
585 $room_stay_checkin = !empty($room_stay_dates[$kor]['checkin_ts']) ? $room_stay_dates[$kor]['checkin_ts'] : $room_stay_dates[$kor]['checkin'];
586 $room_stay_checkout = !empty($room_stay_dates[$kor]['checkout_ts']) ? $room_stay_dates[$kor]['checkout_ts'] : $room_stay_dates[$kor]['checkout'];
587 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
588 // inject nights calculated for this room
589 $room_stay_dates[$kor]['nights'] = $room_stay_nights;
590 ?>
591 <div class="vbo-booking-splitstay-info">
592 <div class="vbo-booking-splitstay-info-room">
593 <span class="vbo-booking-splitstay-nights"><?php VikBookingIcons::e('moon'); ?> <?php echo $room_stay_nights . ' ' . ($room_stay_nights > 1 ? JText::translate('VBDAYS') : JText::translate('VBDAY')); ?></span>
594 <span class="vbo-booking-splitstay-checkin"><?php VikBookingIcons::e('sign-in'); ?> <?php echo date(str_replace("/", $datesep, $df), $room_stay_checkin); ?></span>
595 <span class="vbo-booking-splitstay-checkout"><?php VikBookingIcons::e('sign-out'); ?> <?php echo date(str_replace("/", $datesep, $df), $room_stay_checkout); ?></span>
596 </div>
597 </div>
598 <?php
599 }
600 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
601 ?>
602 <div class="vbo-booking-roomrate">
603 <span class="vbvordcoststitlemain">
604 <span class="vbo-booking-pricename"><?php echo $pricenames[$num]; ?></span>
605 <span class="room_cost">
606 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($or['cust_cost']), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']); ?>
607 </span>
608 </span>
609 </div>
610 <?php
611 /**
612 * In case of custom rate, check if a cancellation policy should be described.
613 *
614 * @since 1.18.2 (J) - 1.8.2 (WP)
615 */
616 $rate_plan_data = VBOTaxonomyFinance::getInstance()->getRatePlanData(($or['cust_cpolicy_id'] ?? 0) ?: 0);
617
618 if ($rate_plan_data) {
619 // describe cancellation policy for custom rate
620 $canc_policy_type = '';
621 $canc_policy_descr = '';
622
623 if ($rate_plan_data['free_cancellation'] == 1) {
624 if ($rate_plan_data['canc_deadline'] > 0) {
625 $canc_policy_type = JText::sprintf('VBFREECANCELLATIONWITHIN', $rate_plan_data['canc_deadline']);
626 } else {
627 $canc_policy_type = JText::translate('VBFREECANCELLATION');
628 }
629 if (!empty($rate_plan_data['canc_policy'])) {
630 $canc_policy_descr = strpos($rate_plan_data['canc_policy'], '<') !== false ? $rate_plan_data['canc_policy'] : nl2br($rate_plan_data['canc_policy']);
631 }
632 } else {
633 $canc_policy_type = JText::translate('VBONONREFUNDRATE');
634 }
635 ?>
636 <div class="vbo-booking-canc-policy-wrap">
637 <div class="vbo-booking-canc-policy-type"><span><?php echo $canc_policy_type; ?></span></div>
638 <?php
639 if (!empty($canc_policy_descr)) {
640 ?>
641 <div class="vbo-booking-canc-policy-descr"><?php echo $canc_policy_descr; ?></div>
642 <?php
643 }
644 ?>
645 </div>
646 <?php
647 }
648 } elseif (array_key_exists($num, $tars) && is_array($tars[$num])) {
649 ?>
650 <div class="vbo-booking-roomrate">
651 <span class="vbvordcoststitlemain">
652 <span class="vbo-booking-pricename"><?php echo $pricenames[$num]; ?></span>
653 <span class="room_cost">
654 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($tars[$num]['calctar']), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price"' . ($ord['status'] == 'confirmed' && $or['room_cost'] > 0 ? ' data-vborigprice="'.VikBooking::numberFormat($or['room_cost']).'"' : '') . '>%s</span>']); ?>
655 </span>
656 </span>
657 </div>
658 <?php
659 }
660 ?>
661 </div>
662
663 <?php
664 if ((array_key_exists($num, $optbought) && strlen((string)$optbought[$num]) > 0) || (array_key_exists($num, $extraservices) && strlen((string)$extraservices[$num]) > 0)) {
665 ?>
666 <div class="vbo-booking-room-extras">
667 <?php
668 if (array_key_exists($num, $optbought) && strlen((string)$optbought[$num]) > 0) {
669 ?>
670 <div class="vbo-booking-room-extras-options">
671 <span class="vbvordcoststitle"><?php echo JText::translate('VBOPTS'); ?></span>
672 <div class="vbo-booking-room-extras-options-list"><?php echo $optbought[$num]; ?></div>
673 </div>
674 <?php
675 }
676 if (array_key_exists($num, $extraservices) && strlen((string)$extraservices[$num]) > 0) {
677 ?>
678 <div class="vbo-booking-room-extras-services">
679 <span class="vbvordcoststitle"><?php echo JText::translate('VBOEXTRASERVICES'); ?></span>
680 <div class="vbo-booking-room-extras-services-list"><?php echo $extraservices[$num]; ?></div>
681 </div>
682 <?php
683 }
684 ?>
685 </div>
686 <?php
687 }
688
689 /**
690 * Access room-level check-in instructions, required to eventually
691 * display any previously created passcode through Door Access Control.
692 *
693 * @since 1.18.12 (J) - 1.8.12 (WP)
694 */
695 $listing_checkin_instructions = VikBooking::getRoomParam('instructions', $listing_params);
696 if ($listing_checkin_instructions && $registry && $ord['status'] == 'confirmed' && $ord['checkout'] > time()) {
697 // attempt to obtain the door access control passcode details
698 try {
699 // obtain the passcode details for this booking
700 $passcodeDetails = VBOFactory::getDoorAccessControl()->getBookingDevicePasscodes($registry);
701 } catch (Exception $e) {
702 // do nothing on error
703 $passcodeDetails = null;
704 }
705 ?>
706 <div class="vbo-booking-room-checkin-instr">
707 <div class="vbo-booking-room-instructions">
708 <h4><?php echo JText::translate('VBO_CHECKIN_INSTRUCTIONS'); ?></h4>
709 <div><?php echo strpos($listing_checkin_instructions, '<') === false ? nl2br($listing_checkin_instructions) : $listing_checkin_instructions; ?></div>
710 </div>
711 <?php
712 if ($passcodeDetails) {
713 // count passcodes
714 $totPasscodes = count($passcodeDetails);
715 ?>
716 <div class="vbo-booking-room-dac">
717 <h4><?php echo JText::translate('VBO_ACCESS_CODE'); ?></h4>
718 <div class="vbo-booking-room-dac-list">
719 <?php
720 if ($totPasscodes === 1) {
721 // just one passcode
722 ?>
723 <div class="vbo-booking-room-dac-code-wrap">
724 <div class="vbo-booking-room-dac-code-val"><?php echo $passcodeDetails[0]['passcode'] ?? ''; ?></div>
725 </div>
726 <?php
727 } else {
728 // display all passcodes
729 foreach ($passcodeDetails as $passcodeDetail) {
730 ?>
731 <div class="vbo-booking-room-dac-code-wrap">
732 <div class="vbo-booking-room-dac-code-lock"><?php echo $passcodeDetail['deviceName'] ?? ''; ?></div>
733 <div class="vbo-booking-room-dac-code-val"><?php echo $passcodeDetail['passcode'] ?? ''; ?></div>
734 </div>
735 <?php
736 }
737 }
738 ?>
739 </div>
740 </div>
741 <?php
742 }
743 ?>
744 </div>
745 <?php
746 }
747 ?>
748
749 </div>
750 <?php
751 }
752 ?>
753 </div>
754
755 <?php
756 if ($rooms_total_changed === true) {
757 ?>
758 <script type="text/javascript">
759 jQuery(function() {
760 jQuery(".vbo_price").not(".vbo_keepcost").each(function(k, v) {
761 var origp = jQuery(this).attr('data-vborigprice');
762 if (origp !== undefined) {
763 jQuery(this).addClass("vbo_keepcost").text(origp).parent().find(".vbo_currency").addClass("vbo_keepcost");
764 } else {
765 <?php
766 //if only the room rates changed but not the options, keep printing the prices
767 echo !$only_roomsrates_changed ? 'jQuery(this).text("").parent().find(".vbo_currency").text("");' : 'jQuery(this).addClass("vbo_keepcost").parent().find(".vbo_currency").addClass("vbo_keepcost");';
768 ?>
769 }
770 });
771 jQuery(".vbo_currency").not(".vbo_keepcost").each(function(){
772 var cur_txt = jQuery(this).parent("span").html();
773 if (cur_txt) {
774 jQuery(this).parent("span").html(cur_txt.replace(":", ""));
775 } else {
776 var cur_txt = jQuery(this).parent("div").html();
777 if (cur_txt) {
778 jQuery(this).parent("div").html(cur_txt.replace(":", ""));
779 }
780 }
781 });
782 });
783 </script>
784 <?php
785 }
786
787 if ($ord['status'] == 'confirmed' && is_array($payment) && intval($payment['shownotealw']) == 1 && !empty($payment['note'])) {
788 ?>
789 <div class="vbvordpaynote">
790 <?php
791 /**
792 * @wponly we need to let WordPress parse the paragraphs in the message.
793 */
794 if (VBOPlatformDetection::isWordPress()) {
795 echo wpautop($payment['note']);
796 } else {
797 echo $payment['note'];
798 }
799 ?>
800 </div>
801 <?php
802 }
803 ?>
804
805 <div class="vbo-booking-costs-list">
806 <?php
807 $extra_css = $ord['status'] == 'confirmed' ? ' vbo_keepcost' : '';
808 if ($usedcoupon === true) {
809 ?>
810 <div class="vbo-booking-cost-detail vbo-booking-cost-detail-discount">
811 <div class="vbo-booking-cost-lbl">
812 <span><?php echo JText::translate('VBCOUPON') . ' ' . $expcoupon[2]; ?></span>
813 </div>
814 <div class="vbo-booking-cost-val">
815 <span class="vbo-booking-cost-val-number">
816 <span>-</span>
817 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($expcoupon[1]), $currencysymb, ['<span class="vbo_currency' . $extra_css . '">%s</span>', '<span class="vbo_price' . $extra_css . '">%s</span>']); ?>
818 </span>
819 </div>
820 </div>
821 <?php
822 }
823 if ($ord['refund'] > 0) {
824 ?>
825 <div class="vbo-booking-cost-detail vbo-booking-cost-detail-refund">
826 <div class="vbo-booking-cost-lbl">
827 <span><?php echo JText::translate('VBO_AMOUNT_REFUNDED'); ?></span>
828 </div>
829 <div class="vbo-booking-cost-val">
830 <span class="vbo-booking-cost-val-number">
831 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($ord['refund']), $currencysymb, ['<span class="vbo_currency' . $extra_css . '">%s</span>', '<span class="vbo_price' . $extra_css . '">%s</span>']); ?>
832 </span>
833 </div>
834 </div>
835 <?php
836 }
837 ?>
838 <div class="vbo-booking-cost-detail vbo-booking-cost-detail-total">
839 <div class="vbo-booking-cost-lbl">
840 <span><?php echo JText::translate('VBTOTAL'); ?></span>
841 </div>
842 <div class="vbo-booking-cost-val">
843 <span class="vbo-booking-cost-val-number">
844 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat(($ord['status'] == 'confirmed' ? $ord['total'] : $isdue)), $currencysymb, ['<span class="vbo_currency' . $extra_css . '">%s</span>', '<span class="vbo_price' . $extra_css . '">%s</span>']); ?>
845 </span>
846 </div>
847 </div>
848 <?php
849 /**
850 * We allow the payment for confirmed bookings when a payment method is assigned, the configuration setting is enabled,
851 * the payment counter is greater than 0 (some tasks will force it to 1 when empty) and the amount paid is greater than
852 * zero but less than the total amount, or when the 'payable' property is greater than zero.
853 *
854 * @since 1.13 (J) - 1.3.0 (WP)
855 *
856 * We no longer need the payment counter to be greater than zero to allow a payment, as the payable amount can be defined by the admin.
857 *
858 * @since 1.14 (J) - 1.4.0 (WP)
859 *
860 * Some OTA bookings using an OTA-Collect business model may look as not entirely paid when they actually are, due to commissions.
861 * However, upselling events are taken into account in case a payable amount is set.
862 *
863 * @since 1.16.5 (J) - 1.6.5 (WP)
864 *
865 * Channels supporting payout notifications will not allow to pay the outstanding balance unless a payable amount is set.
866 *
867 * @since 1.16.9 (J) - 1.6.9 (WP)
868 *
869 * Damage deposit configured to be paid separately will not count as a payable remaining balance.
870 *
871 * @since 1.17.6 (J) - 1.7.6 (WP)
872 */
873 $payable = (($ord['totpaid'] > 0 && ($ord['totpaid'] + ($this->damage_deposit_payment['damagedep_gross'] ?? 0)) < $ord['total'] && $ord['paymcount'] > 0) || $ord['payable'] > 0);
874 $ota_will_pay = false;
875 $dd_payable_later = false;
876 if ($payable && $ord['status'] == 'confirmed' && !empty($ord['idorderota']) && $ord['payable'] > 0 && !$this->prev_dd_payments) {
877 if (($this->damage_deposit_payment['damagedep_gross'] ?? 0) == $ord['payable'] && ($this->damage_deposit_payment['payment_window']['pay_id'] ?? 0)) {
878 // upselling event must have added the damage deposit to an OTA booking, and this is the only outstanding amount that will be paid separately
879 $payable = false;
880 // check if the damage deposit is payable later
881 if (!($this->damage_deposit_payment['payment_window']['payable'] ?? 0) && ($this->damage_deposit_payment['payment_window']['payment_from_dt'] ?? null)) {
882 $dd_payable_later = true;
883 }
884 }
885 }
886 if ($payable && !empty($ord['idorderota']) && !empty($ord['channel']) && $ord['cmms'] && ($ord['total'] - $ord['totpaid'] - $ord['cmms']) < 1) {
887 // the difference of the amount paid is equal to the OTA commissions amount
888 $payable = false;
889 if ($ord['payable'] > 0 && $ord['total'] > $ord['totpaid'] && round(($ord['total'] - $ord['totpaid']), 0) == round($ord['payable'], 0)) {
890 // there must have been an upselling event or a payment request
891 $payable = true;
892 }
893 }
894 if ($payable && $isotabooking && !((float) $ord['payable'])) {
895 // access OTA payout events
896 $prev_ota_payments = VikBooking::getBookingHistoryInstance($ord['id'])
897 ->getEventsWithData('PO', null, false);
898 if (!$prev_ota_payments) {
899 // the OTA will pay the remaining balance
900 $payable = false;
901 $ota_will_pay = true;
902 }
903 }
904
905 /**
906 * Check if we have an outstanding balance after a deposit paid for a direct booking.
907 *
908 * @since 1.18.6 (J) - 1.8.6 (WP)
909 */
910 $pay_balance_days_adv = (int) VBOFactory::getConfig()->get('depbalancedays');
911 if ($pay_balance_days_adv > 0 && !((float) $ord['payable']) && $ord['status'] == 'confirmed' && empty($ord['idorderota']) && $ord['totpaid'] > 0 && $ord['total'] > $ord['totpaid']) {
912 // ensure the outstanding balance for direct booking is payable at this time
913 if ($ord['ts'] < strtotime(sprintf('-%d days', $pay_balance_days_adv), $ord['checkin'])) {
914 // outstanding balance not yet payable according to settings
915 $payable = false;
916 }
917 }
918
919 if ($ord['status'] == 'confirmed' && is_array($payment) && VikBooking::multiplePayments() && $ord['total'] > 0 && $payable) {
920 // write again the payment form because the order was not fully paid
921
922 if (VBOPlatformDetection::isWordPress()) {
923 /**
924 * @wponly
925 *
926 * @since 1.0.5
927 */
928 $return_url = JUri::root() . "index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'];
929 $error_url = JUri::root() . "index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'];
930 $notify_url = JUri::root() . "index.php?option=com_vikbooking&task=notifypayment&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts']."&tmpl=component";
931 /**
932 * @wponly the URLs must be routed differently for WP
933 */
934 $model = JModel::getInstance('vikbooking', 'shortcodes', 'admin');
935 $itemid = $model->best(['booking'], (!empty($ord['lang']) ? $ord['lang'] : null));
936 if ($itemid) {
937 $return_url = str_replace(JUri::root(), '', $return_url);
938 $error_url = str_replace(JUri::root(), '', $error_url);
939 $notify_url = str_replace(JUri::root(), '', $notify_url);
940 $return_url = JRoute::rewrite($return_url . "&Itemid={$itemid}", false);
941 $error_url = JRoute::rewrite($error_url . "&Itemid={$itemid}", false);
942 $notify_url = JRoute::rewrite($notify_url . "&Itemid={$itemid}", false);
943 }
944 } else {
945 $return_url = VikBooking::externalroute("index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'], false, (!empty($bestitemid) ? $bestitemid : null));
946 $error_url = VikBooking::externalroute("index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'], false, (!empty($bestitemid) ? $bestitemid : null));
947 $notify_url = VikBooking::externalroute("index.php?option=com_vikbooking&task=notifypayment&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts']."&tmpl=component", false, null);
948 }
949
950 $transaction_name = VikBooking::getPaymentName();
951 $leave_deposit = 0;
952 $percentdeposit = "";
953
954 // calculate the outstanding balance to pay
955 if ($ord['payable'] > 0) {
956 $remainingamount = $ord['payable'];
957 } else {
958 $prev_dd_paid = 0;
959 if ($this->prev_dd_payments || ($this->damage_deposit_payment['payment_window'] ?? [])) {
960 $prev_dd_paid = $this->damage_deposit_payment['damagedep_gross'] ?? 0;
961 }
962 $prev_recorded_payment = $ord['totpaid'] + $prev_dd_paid;
963 $remainingamount = $ord['total'] - $prev_recorded_payment;
964 }
965
966 $array_order = [];
967 $array_order['details'] = $ord;
968 if (empty($array_order['details']['sid']) && !empty($array_order['details']['idorderota']) && !empty($array_order['details']['channel'])) {
969 $array_order['details']['sid'] = $array_order['details']['idorderota'];
970 $ord['sid'] = $ord['idorderota'];
971 }
972 $array_order['customer_email'] = $ord['custmail'];
973 $array_order['account_name'] = VikBooking::getPaypalAcc();
974 $array_order['transaction_currency'] = VikBooking::getCurrencyCodePp();
975 $array_order['rooms_name'] = implode(", ", $roomsnames);
976 $array_order['transaction_name'] = !empty($transaction_name) ? $transaction_name : (JText::translate('VBORDERNUMBER') . ' ' . $ord['id']);
977 $array_order['order_total'] = $remainingamount;
978 $array_order['currency_symb'] = $currencysymb;
979 $array_order['net_price'] = $remainingamount;
980 $array_order['tax'] = 0;
981 $array_order['return_url'] = $return_url;
982 $array_order['error_url'] = $error_url;
983 $array_order['notify_url'] = $notify_url;
984 $array_order['total_to_pay'] = $remainingamount;
985 $array_order['total_net_price'] = $remainingamount;
986 $array_order['total_tax'] = 0;
987 $array_order['leave_deposit'] = $leave_deposit;
988 $array_order['percentdeposit'] = $percentdeposit;
989 $array_order['payment_info'] = $payment;
990 $array_order = array_merge($ord, $array_order);
991 ?>
992 <div class="vbo-booking-cost-detail vbo-booking-cost-detail-amountpaid">
993 <div class="vbo-booking-cost-lbl">
994 <span><?php echo JText::translate('VBAMOUNTPAID'); ?></span>
995 </div>
996 <div class="vbo-booking-cost-val">
997 <span class="vbo-booking-cost-val-number">
998 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($ord['totpaid']), $currencysymb, ['<span class="vbo_currency vbo_keepcost">%s</span>', '<span class="vbo_price vbo_keepcost">%s</span>']); ?>
999 </span>
1000 </div>
1001 </div>
1002 <div class="vbo-booking-cost-detail vbo-booking-cost-detail-remainingbalance">
1003 <div class="vbo-booking-cost-lbl">
1004 <span><?php echo JText::translate('VBTOTALREMAINING'); ?></span>
1005 </div>
1006 <div class="vbo-booking-cost-val">
1007 <span class="vbo-booking-cost-val-number">
1008 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($remainingamount), $currencysymb, ['<span class="vbo_currency vbo_keepcost">%s</span>', '<span class="vbo_price vbo_keepcost">%s</span>']); ?>
1009 </span>
1010 </div>
1011 </div>
1012
1013 <div class="vbvordpaybutton">
1014 <?php
1015 // build and inject transaction metadata
1016 $array_order['tn_metadata'] = [
1017 'booking_id' => $ord['id'],
1018 'source' => (($ord['channel'] ?? '') ?: 'Website'),
1019 'ota_booking_id' => (($ord['idorderota'] ?? '') ?: ''),
1020 ];
1021
1022 // increase payment processor instances
1023 $payProcessorInstances++;
1024
1025 /**
1026 * Trigger event to allow third-party plugins to manipulate the transaction data.
1027 *
1028 * @since 1.18.5 (J) - 1.8.5 (WP)
1029 */
1030 VBOFactory::getPlatform()->getDispatcher()->trigger('onInitPaymentTransaction', [&$array_order, &$payment['params'], []]);
1031
1032 if (VBOPlatformDetection::isWordPress()) {
1033 /**
1034 * @wponly The payment gateway is now loaded
1035 * using the apposite dispatcher.
1036 *
1037 * @since 1.0.5
1038 */
1039 JLoader::import('adapter.payment.dispatcher');
1040
1041 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $array_order, $payment['params']);
1042 // remember to echo the payment
1043 echo $obj->showPayment();
1044 } else {
1045 /**
1046 * @joomlaonly The Payment Factory library will invoke the gateway.
1047 *
1048 * @since 1.14.3
1049 */
1050 require_once VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'payments' . DIRECTORY_SEPARATOR . 'libraries' . DIRECTORY_SEPARATOR . 'factory.php';
1051 $obj = VBOPaymentFactory::getPaymentInstance($payment['file'], $array_order, $payment['params']);
1052
1053 $obj->showPayment();
1054 }
1055 ?>
1056 </div>
1057 <?php
1058 } elseif ($ord['status'] == 'confirmed') {
1059 if ($ptmpl != 'component' && $ord['total'] > 0 && $ord['totpaid'] > 0 && $ord['totpaid'] < $ord['total']) {
1060 /**
1061 * Calculate the amount paid so far, by considering the damage deposit and its payment.
1062 *
1063 * @since 1.17.6 (J) - 1.7.6 (WP)
1064 */
1065 $paid_so_far = $ord['totpaid'];
1066 if (($this->damage_deposit_payment['damagedep_gross'] ?? 0) > 0 && $this->prev_dd_payments) {
1067 $paid_so_far += $this->damage_deposit_payment['damagedep_gross'];
1068 }
1069
1070 // calculate the remainig balance to be paid
1071 $remainingamount = $ord['total'] - $paid_so_far;
1072 ?>
1073 <div class="vbo-booking-cost-detail vbo-booking-cost-detail-amountpaid">
1074 <div class="vbo-booking-cost-lbl">
1075 <span><?php echo JText::translate('VBAMOUNTPAID'); ?></span>
1076 </div>
1077 <div class="vbo-booking-cost-val">
1078 <span class="vbo-booking-cost-val-number">
1079 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($ord['totpaid']), $currencysymb, ['<span class="vbo_currency vbo_keepcost">%s</span>', '<span class="vbo_price vbo_keepcost">%s</span>']); ?>
1080 </span>
1081 </div>
1082 </div>
1083 <?php
1084 $is_rembal_ota_cmms = $isotabooking && (round($remainingamount, 2) == round($ord['cmms'], 2) || (!VikBooking::ivaInclusa() && round($remainingamount, 2) == round($ord['cmms'] + $ord['tot_taxes'], 2)));
1085 if (!$ota_will_pay && $remainingamount > 0 && !$is_rembal_ota_cmms) {
1086 ?>
1087 <div class="vbo-booking-cost-detail vbo-booking-cost-detail-remainingbalance">
1088 <div class="vbo-booking-cost-lbl">
1089 <span><?php echo JText::translate('VBTOTALREMAINING'); ?></span>
1090 </div>
1091 <div class="vbo-booking-cost-val">
1092 <span class="vbo-booking-cost-val-number">
1093 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($remainingamount), $currencysymb, ['<span class="vbo_currency vbo_keepcost">%s</span>', '<span class="vbo_price vbo_keepcost">%s</span>']); ?>
1094 </span>
1095 </div>
1096 </div>
1097 <?php
1098 if ($dd_payable_later === true) {
1099 // display message for when the damage deposit amount will be payable
1100 ?>
1101 <div class="vbo-booking-cost-detail vbo-booking-cost-detail-dd-payable-later">
1102 <div class="vbo-booking-cost-lbl">
1103 <span><?php echo JText::translate('VBO_DAMAGE_DEPOSIT'); ?></span>
1104 </div>
1105 <div class="vbo-booking-cost-val">
1106 <span class="vbo-booking-cost-val-number">
1107 <span><?php echo JText::sprintf('VBO_PAYABLE_FROM_DT', ($this->damage_deposit_payment['payment_window']['payment_from_dt'] ?? '')); ?></span>
1108 </span>
1109 </div>
1110 </div>
1111 <?php
1112 }
1113 }
1114 }
1115 if ($ptmpl == 'component') {
1116 ?>
1117 <script type="text/javascript">
1118 window.print();
1119 </script>
1120 <?php
1121 }
1122 }
1123
1124 ?>
1125 </div>
1126 <?php
1127
1128 // booking modification/cancellation request, cancellation form or upsell animation
1129 if (($ord['status'] == 'confirmed' && $resmodcanc > 0 && $this->days_to_arrival >= $resmodcancmin) || count($this->upselling)) {
1130 ?>
1131 <script type="text/javascript">
1132 function vbOpenCancOrdForm() {
1133 location.hash = 'bmodreqf';
1134 document.getElementById('vbordcancformbox').style.display = 'block';
1135 }
1136 function vbValidateCancForm() {
1137 if (!document.getElementById('vbcancemail').value.match(/\S/)) {
1138 document.getElementById('vbformcancemail').style.color='#ff0000';
1139 return false;
1140 } else {
1141 document.getElementById('vbformcancemail').style.color='';
1142 }
1143 if (!document.getElementById('vbcancreason').value.match(/\S/)) {
1144 document.getElementById('vbformcancreason').style.color='#ff0000';
1145 return false;
1146 } else {
1147 document.getElementById('vbformcancreason').style.color='';
1148 }
1149 return true;
1150 }
1151 function vbGotoUpsell() {
1152 jQuery('html,body').animate({scrollTop: jQuery('.vbo-booking-upsell-container').offset().top - 20}, {duration: 400});
1153 }
1154 </script>
1155 <?php
1156 }
1157 if ($ord['status'] == 'confirmed' && $resmodcanc === 1 && $this->days_to_arrival >= $resmodcancmin) {
1158 ?>
1159 <a name="bmodreqf"></a>
1160 <div class="vbordcancformbox" id="vbordcancformbox">
1161 <div class="vbo-booking-cancform-inner">
1162 <h4><?php echo JText::translate('VBREQUESTCANCMOD'); ?></h4>
1163 <form action="<?php echo JRoute::rewrite('index.php?option=com_vikbooking'.(!empty($pitemid) ? '&Itemid='.$pitemid : '')); ?>" name="vbcanc" method="post" onsubmit="javascript: return vbValidateCancForm();">
1164 <div class="vbordcancform-inner">
1165 <div class="vbordcancform-entry">
1166 <div class="vbordcancform-entry-label">
1167 <label for="vbcancemail" id="vbformcancemail"><?php echo JText::translate('VBREQUESTCANCMODEMAIL'); ?></label>
1168 </div>
1169 <div class="vbordcancform-entry-inp">
1170 <input type="text" class="vbinput" name="email" id="vbcancemail" value="<?php echo $ord['custmail']; ?>"/>
1171 </div>
1172 </div>
1173 <div class="vbordcancform-entry">
1174 <div class="vbordcancform-entry-label">
1175 <label for="vbcancreason" id="vbformcancreason"><?php echo JText::translate('VBREQUESTCANCMODREASON'); ?></label>
1176 </div>
1177 <div class="vbordcancform-entry-inp">
1178 <textarea name="reason" id="vbcancreason" rows="7" cols="30" class="vbtextarea"></textarea>
1179 </div>
1180 </div>
1181 <div class="vbordcancform-entry-submit">
1182 <input type="submit" name="sendrequest" value="<?php echo JText::translate('VBREQUESTCANCMODSUBMIT'); ?>" class="btn vbo-pref-color-btn"/>
1183 </div>
1184 </div>
1185 <?php
1186 if (!empty($pitemid)) {
1187 ?>
1188 <input type="hidden" name="Itemid" value="<?php echo $pitemid; ?>"/>
1189 <?php
1190 }
1191 ?>
1192 <input type="hidden" name="sid" value="<?php echo $ord['sid']; ?>"/>
1193 <input type="hidden" name="idorder" value="<?php echo $ord['id']; ?>"/>
1194 <input type="hidden" name="option" value="com_vikbooking"/>
1195 <input type="hidden" name="task" value="cancelrequest"/>
1196 <?php echo JHtml::fetch('form.token'); ?>
1197 </form>
1198 </div>
1199 </div>
1200 <?php
1201 }
1202 //booking cancellation
1203 if ($ord['status'] == 'confirmed' && $canc_allowed) {
1204 ?>
1205 <a name="bcancf"></a>
1206 <div class="vbo-booking-cancform-container" id="vbo-booking-cancform-container" style="display: none;">
1207 <div class="vbo-booking-cancform-inner">
1208 <h4><?php echo JText::translate('VBOCANCYOURBOOKING'); ?></h4>
1209 <div class="vbo-booking-cancform-details">
1210 <div class="vbo-booking-canc-details-policy">
1211 <?php echo $this->canc_policy; ?>
1212 </div>
1213 <form action="<?php echo JRoute::rewrite('index.php?option=com_vikbooking'.(!empty($pitemid) ? '&Itemid='.$pitemid : '')); ?>" name="vbcanc" method="post" onsubmit="javascript: return vbValidateCancForm();">
1214 <div class="vbordcancform-inner vbo-booking-canc">
1215 <div class="vbordcancform-entry">
1216 <div class="vbordcancform-entry-label">
1217 <label for="vbcancemail" id="vbformcancemail"><?php echo JText::translate('VBREQUESTCANCMODEMAIL'); ?></label>
1218 </div>
1219 <div class="vbordcancform-entry-inp">
1220 <input type="text" class="vbinput" name="email" id="vbcancemail" value="<?php echo $ord['custmail']; ?>"/>
1221 </div>
1222 </div>
1223 <div class="vbordcancform-entry">
1224 <div class="vbordcancform-entry-label">
1225 <label for="vbcancreason" id="vbformcancreason"><?php echo JText::translate('VBOCANCBOOKINGREASON'); ?></label>
1226 </div>
1227 <div class="vbordcancform-entry-inp">
1228 <textarea name="reason" id="vbcancreason" rows="7" cols="30" class="vbtextarea"></textarea>
1229 </div>
1230 </div>
1231 <div class="vbo-booking-canc-submit">
1232 <input type="submit" name="sendrequest" value="<?php echo JText::translate('VBOCANCYOURBOOKING'); ?>" class="vbo-btn-cancelbooking"/>
1233 </div>
1234 </div>
1235 <?php
1236 if (!empty($pitemid)) {
1237 ?>
1238 <input type="hidden" name="Itemid" value="<?php echo $pitemid; ?>"/>
1239 <?php
1240 }
1241 ?>
1242 <input type="hidden" name="sid" value="<?php echo $ord['sid']; ?>"/>
1243 <input type="hidden" name="idorder" value="<?php echo $ord['id']; ?>"/>
1244 <input type="hidden" name="option" value="com_vikbooking"/>
1245 <input type="hidden" name="task" value="docancelbooking"/>
1246 <?php echo JHtml::fetch('form.token'); ?>
1247 </form>
1248 </div>
1249 </div>
1250 </div>
1251 <?php
1252 }
1253
1254 // stand-by booking payment rendering
1255 if (is_array($payment) && $ord['status'] == 'standby') {
1256 // render the selected payment method
1257 $lang = JFactory::getLanguage();
1258 $langtag = substr($lang->getTag(), 0, 2);
1259
1260 if (VBOPlatformDetection::isWordPress()) {
1261 /**
1262 * @wponly
1263 *
1264 * @since 1.0.5
1265 */
1266 $return_url = JUri::root() . "index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts']."&lang=".$langtag;
1267 $error_url = JUri::root() . "index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts']."&lang=".$langtag;
1268 $notify_url = JUri::root() . "index.php?option=com_vikbooking&task=notifypayment&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts']."&lang=".$langtag."&tmpl=component";
1269 /**
1270 * @wponly the URLs must be routed differently for WP
1271 */
1272 $model = JModel::getInstance('vikbooking', 'shortcodes', 'admin');
1273 $itemid = $model->best(['booking'], (!empty($ord['lang']) ? $ord['lang'] : null));
1274 if ($itemid) {
1275 $return_url = str_replace(JUri::root(), '', $return_url);
1276 $error_url = str_replace(JUri::root(), '', $error_url);
1277 $notify_url = str_replace(JUri::root(), '', $notify_url);
1278 $return_url = JRoute::rewrite($return_url . "&Itemid={$itemid}", false);
1279 $error_url = JRoute::rewrite($error_url . "&Itemid={$itemid}", false);
1280 $notify_url = JRoute::rewrite($notify_url . "&Itemid={$itemid}", false);
1281 }
1282 } else {
1283 $return_url = VikBooking::externalroute("index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'] ."&lang=" . $langtag, false, (!empty($bestitemid) ? $bestitemid : null));
1284 $error_url = VikBooking::externalroute("index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'] ."&lang=" . $langtag, false, (!empty($bestitemid) ? $bestitemid : null));
1285 $notify_url = VikBooking::externalroute("index.php?option=com_vikbooking&task=notifypayment&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'] . "&lang=" . $langtag . "&tmpl=component", false);
1286 }
1287
1288 $transaction_name = VikBooking::getPaymentName();
1289 $leave_deposit = 0;
1290 $percentdeposit = "";
1291
1292 $array_order = [];
1293 $array_order['details'] = $ord;
1294 if (empty($array_order['details']['sid']) && !empty($array_order['details']['idorderota']) && !empty($array_order['details']['channel'])) {
1295 $array_order['details']['sid'] = $array_order['details']['idorderota'];
1296 $ord['sid'] = $ord['idorderota'];
1297 }
1298 $array_order['customer_email'] = $ord['custmail'];
1299 $array_order['account_name'] = VikBooking::getPaypalAcc();
1300 $array_order['transaction_currency'] = VikBooking::getCurrencyCodePp();
1301 $array_order['rooms_name'] = implode(", ", $roomsnames);
1302 $array_order['transaction_name'] = !empty($transaction_name) ? $transaction_name : (JText::translate('VBORDERNUMBER') . ' ' . $ord['id']);
1303 $array_order['order_total'] = $isdue;
1304 $array_order['currency_symb'] = $currencysymb;
1305 $array_order['net_price'] = $imp;
1306 $array_order['tax'] = $tax;
1307 $array_order['return_url'] = $return_url;
1308 $array_order['error_url'] = $error_url;
1309 $array_order['notify_url'] = $notify_url;
1310 $array_order['total_to_pay'] = $isdue;
1311 $array_order['total_net_price'] = $imp;
1312 $array_order['total_tax'] = $tax;
1313
1314 /**
1315 * Check for damage deposit payment data and eventually deduct payment amounts.
1316 *
1317 * @since 1.17.6 (J) - 1.7.6 (WP)
1318 */
1319 if (($this->damage_deposit_payment['payment_window'] ?? []) && ($this->damage_deposit_payment['damagedep_gross'] ?? 0) > 0 && $this->damage_deposit_payment['damagedep_gross'] < $array_order['total_to_pay']) {
1320 // damage deposit will have to be paid separately
1321 $array_order['total_to_pay'] -= $this->damage_deposit_payment['damagedep_gross'];
1322 if (($this->damage_deposit_payment['damagedep_net'] ?? 0) > 0 && $this->damage_deposit_payment['damagedep_net'] < $array_order['total_tax']) {
1323 $array_order['total_net_price'] -= $this->damage_deposit_payment['damagedep_net'];
1324 }
1325 if (($this->damage_deposit_payment['damagedep_tax'] ?? 0) > 0 && $this->damage_deposit_payment['damagedep_tax'] < $array_order['total_tax']) {
1326 $array_order['total_tax'] -= $this->damage_deposit_payment['damagedep_tax'];
1327 }
1328 }
1329
1330 $totalchanged = false;
1331 if ($payment['charge'] > 0.00) {
1332 $totalchanged = true;
1333 if ($payment['ch_disc'] == 1) {
1334 // charge
1335 if ($payment['val_pcent'] == 1) {
1336 // fixed value
1337 $array_order['total_net_price'] += $payment['charge'];
1338 $array_order['total_tax'] += $payment['charge'];
1339 $array_order['total_to_pay'] += $payment['charge'];
1340 $newtotaltopay = $array_order['total_to_pay'];
1341 } else {
1342 // percent value
1343 $percent_net = $array_order['total_net_price'] * $payment['charge'] / 100;
1344 $percent_tax = $array_order['total_tax'] * $payment['charge'] / 100;
1345 $percent_to_pay = $array_order['total_to_pay'] * $payment['charge'] / 100;
1346 $array_order['total_net_price'] += $percent_net;
1347 $array_order['total_tax'] += $percent_tax;
1348 $array_order['total_to_pay'] += $percent_to_pay;
1349 $newtotaltopay = $array_order['total_to_pay'];
1350 }
1351 } else {
1352 // discount
1353 if ($payment['val_pcent'] == 1) {
1354 // fixed value
1355 $array_order['total_net_price'] -= $payment['charge'];
1356 $array_order['total_tax'] -= $payment['charge'];
1357 $array_order['total_to_pay'] -= $payment['charge'];
1358 $newtotaltopay = $array_order['total_to_pay'];
1359 } else {
1360 // percent value
1361 $percent_net = $array_order['total_net_price'] * $payment['charge'] / 100;
1362 $percent_tax = $array_order['total_tax'] * $payment['charge'] / 100;
1363 $percent_to_pay = $array_order['total_to_pay'] * $payment['charge'] / 100;
1364 $array_order['total_net_price'] -= $percent_net;
1365 $array_order['total_tax'] -= $percent_tax;
1366 $array_order['total_to_pay'] -= $percent_to_pay;
1367 $newtotaltopay = $array_order['total_to_pay'];
1368 }
1369 }
1370 }
1371 $percentdeposit = false;
1372 if (!VikBooking::payTotal() && $this->nodep != 1 && VikBooking::allowDepositFromRates($tars)) {
1373 $percentdeposit = VikBooking::getAccPerCent();
1374 $percentdeposit = VikBooking::calcDepositOverride($percentdeposit, $ord['days']);
1375 if ($percentdeposit > 0 && VikBooking::depositAllowedDaysAdv($ord['checkin'])) {
1376 $leave_deposit = 1;
1377 if (VikBooking::getTypeDeposit() == "fixed") {
1378 $array_order['total_to_pay'] = $percentdeposit;
1379 $array_order['total_net_price'] = $percentdeposit;
1380 $array_order['total_tax'] = ($array_order['total_to_pay'] - $array_order['total_net_price']);
1381 } else {
1382 $array_order['total_to_pay'] = $array_order['total_to_pay'] * $percentdeposit / 100;
1383 $array_order['total_net_price'] = $array_order['total_net_price'] * $percentdeposit / 100;
1384 $array_order['total_tax'] = ($array_order['total_to_pay'] - $array_order['total_net_price']);
1385 }
1386 }
1387 }
1388 $array_order['leave_deposit'] = $leave_deposit;
1389 $array_order['percentdeposit'] = $percentdeposit;
1390 $array_order['payment_info'] = $payment;
1391 $array_order = array_merge($ord, $array_order);
1392
1393 if (VBOPlatformDetection::isWordPress()) {
1394 $elapsed_redirect_uri = $return_url;
1395 } else {
1396 $elapsed_redirect_uri = JRoute::rewrite('index.php?option=com_vikbooking&view=booking&sid='.(!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']).'&ts='.$ord['ts'].(!empty($bestitemid) ? '&Itemid='.$bestitemid : (!empty($pitemid) ? '&Itemid='.$pitemid : '')), false);
1397 }
1398
1399 // count minutes elapsed from booking creation date
1400 $mins_elapsed = floor(($now_info[0] - $ord['ts']) / 60);
1401
1402 /**
1403 * Check if we are dealing with a pending booking solution of a quote.
1404 *
1405 * @since 1.18.8 (J) - 1.8.8 (WP)
1406 */
1407 if ($this->quoteValidUntilDt) {
1408 // get the date interval of difference between valid until date and current date
1409 $validityDiff = $this->quoteValidUntilDt->diff(JFactory::getDate('now'));
1410 // count the number of minutes still available (expected validity to be in the future)
1411 $minautoremove = ($validityDiff->days * 1440) + ($validityDiff->h * 60) + $validityDiff->i;
1412 // add up the minutes elapsed to allow an accurate calcilation of the remaining minutes
1413 $minautoremove += $mins_elapsed;
1414 } else {
1415 // global booking auto-removal minutes
1416 $minautoremove = VikBooking::getMinutesAutoRemove();
1417 }
1418
1419 // check if we should display a countdown for the automatic booking cancellation
1420 $remainmin = $minautoremove - $mins_elapsed;
1421 $remainmin = $remainmin < 1 ? 1 : $remainmin;
1422 if ($minautoremove > 0 && $minautoremove < 35791) {
1423 /**
1424 * Ensure the timeout milliseconds in 32-bit do not exceed
1425 * the maximum value of 2,147,483,647ms (~35791,39 minutes).
1426 *
1427 * @since 1.16.10 (J) - 1.6.10 (WP)
1428 */
1429 $booktime_info = getdate($ord['ts']);
1430 $booktime_offset = date('Z', $ord['ts']) / 60;
1431 $remainmilsec = intval($remainmin * 60 * 1000) + 100;
1432 $remainmilsec = $remainmilsec < 100 ? 100 : $remainmilsec;
1433 // calculate the values for the timer
1434 $days_left = $remainmin > 1440 ? floor($remainmin / 1440) : 0;
1435 $remainmin -= $days_left * 1440;
1436 $hours_left = $remainmin > 59 ? floor($remainmin / 60) : 0;
1437 $minutes_left = $remainmin - ($hours_left * 60);
1438 $lbl_hour = strtolower(JText::translate('VBHOUR'));
1439 $lbl_hours = strtolower(JText::translate('VBHOURS'));
1440 $lbl_minute = strtolower(JText::translate('VBMINUTE'));
1441 $lbl_minutes = strtolower(JText::translate('VBMINUTES'));
1442 $lbl_day = strtolower(JText::translate('VBO_DAY'));
1443 $lbl_days = strtolower(JText::translate('VBO_DAYS'));
1444 $timer_str = $days_left > 0 ? '<span id="vbo-timer-days">' . $days_left . ' ' . ($days_left == 1 ? $lbl_day : $lbl_days) . '</span> ' : '';
1445 $timer_str .= $days_left > 0 || $hours_left > 0 ? '<span id="vbo-timer-hours">' . $hours_left . ' ' . ($hours_left == 1 ? $lbl_hour : $lbl_hours) . '</span> ' : '';
1446 $timer_str .= '<span id="vbo-timer-minutes">' . $minutes_left . ' ' . ($minutes_left == 1 ? $lbl_minute : $lbl_minutes) . '</span>';
1447 ?>
1448 <script type="text/javascript">
1449 var vboPayTimerLbl = {
1450 "hour": "<?php echo addslashes($lbl_hour); ?>",
1451 "hours": "<?php echo addslashes($lbl_hours); ?>",
1452 "minute": "<?php echo addslashes($lbl_minute); ?>",
1453 "minutes": "<?php echo addslashes($lbl_minutes); ?>",
1454 "day": "<?php echo addslashes($lbl_day); ?>",
1455 "days": "<?php echo addslashes($lbl_days); ?>",
1456 }
1457 var vboPayTimeout = setTimeout(function() {
1458 document.location.href = '<?php echo $elapsed_redirect_uri; ?>';
1459 }, <?php echo $remainmilsec; ?>);
1460 var vboPayInterval = setInterval("vboRefreshPayTimer()", 60000);
1461 var vboBookInfo = new Date(<?php echo $booktime_info['year']; ?>, <?php echo ($booktime_info['mon'] - 1); ?>, <?php echo $booktime_info['mday']; ?>, <?php echo $booktime_info['hours']; ?>, <?php echo $booktime_info['minutes']; ?>, <?php echo $booktime_info['seconds']; ?>, 0);
1462 var vboPayTimerOffsetSet = false;
1463 function vboPauseTimeout() {
1464 clearTimeout(vboPayTimeout);
1465 }
1466 function vboRefreshPayTimer() {
1467 const vboNow = new Date();
1468 if (!vboPayTimerOffsetSet) {
1469 let tzoffset = vboNow.getTimezoneOffset() * -1 - <?php echo $booktime_offset; ?>;
1470 vboBookInfo.setMinutes(vboBookInfo.getMinutes() + tzoffset);
1471 vboPayTimerOffsetSet = true;
1472 }
1473
1474 let mins_elapsed = Math.floor((vboNow - vboBookInfo) / 1000 / 60);
1475 let remainmin = <?php echo $minautoremove; ?> - mins_elapsed;
1476 let days_left = remainmin > 1440 ? Math.floor(remainmin / 1440) : 0;
1477 remainmin -= days_left * 1440;
1478 let hours_left = remainmin > 59 ? Math.floor(remainmin / 60) : 0;
1479 let minutes_left = remainmin - (hours_left * 60);
1480 if (days_left < 1 && hours_left < 1 && minutes_left < 1) {
1481 clearInterval(vboPayInterval);
1482 if (document.getElementById('vbo-timer-payment')) {
1483 document.getElementById('vbo-timer-payment').style.display = 'none';
1484 }
1485 return false;
1486 }
1487 if (document.getElementById('vbo-timer-days')) {
1488 if (days_left < 1) {
1489 document.getElementById('vbo-timer-days').style.display = 'none';
1490 } else {
1491 document.getElementById('vbo-timer-days').textContent = days_left + ' ' + (days_left == 1 ? vboPayTimerLbl['day'] : vboPayTimerLbl['days']);
1492 }
1493 }
1494 if (document.getElementById('vbo-timer-hours')) {
1495 if (hours_left < 1) {
1496 document.getElementById('vbo-timer-hours').style.display = 'none';
1497 } else {
1498 document.getElementById('vbo-timer-hours').textContent = hours_left + ' ' + (hours_left == 1 ? vboPayTimerLbl['hour'] : vboPayTimerLbl['hours']);
1499 }
1500 }
1501 document.getElementById('vbo-timer-minutes').textContent = minutes_left + ' ' + (minutes_left == 1 ? vboPayTimerLbl['minute'] : vboPayTimerLbl['minutes']);
1502 }
1503 </script>
1504
1505 <div class="vbo-timer-payment" id="vbo-timer-payment">
1506 <span class="vbo-timer-payment-str">
1507 <?php echo JText::sprintf('VBOTIMERPAYMENTSTR', $timer_str); ?>
1508 </span>
1509 </div>
1510 <?php
1511 } elseif ($minautoremove > 0) {
1512 // we expect a very high number of remaining minutes to be expressed in days
1513 ?>
1514 <div class="vbo-timer-payment" id="vbo-timer-payment">
1515 <span class="vbo-timer-payment-str">
1516 <?php
1517 $days_left = max(0, floor($remainmin / 1440));
1518 echo JText::sprintf('VBOTIMERPAYMENTSTR', sprintf(
1519 '~%d %s',
1520 $days_left,
1521 JText::translate($days_left == 1 ? 'VBO_DAY' : 'VBO_DAYS')
1522 ));
1523 ?>
1524 </span>
1525 </div>
1526 <?php
1527 }
1528
1529 ?>
1530 <div class="vbvordpaybutton">
1531 <?php
1532 if ($totalchanged) {
1533 $chdecimals = $payment['charge'] - (int)$payment['charge'];
1534 ?>
1535 <p class="vbpaymentchangetot">
1536 <span class="vbpaymentnamediff">
1537 <span><?php echo $payment['name']; ?></span>
1538 (<?php
1539 echo $payment['ch_disc'] == 1 ? '+' : '-';
1540 if ($payment['val_pcent'] == 1) {
1541 echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($payment['charge']), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']);
1542 } else {
1543 echo '<span class="vbo_price">' . VikBooking::numberFormat($payment['charge']) . '</span> %';
1544 }
1545 ?>)
1546 </span>
1547 <span class="vborddiffpayment"><?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($newtotaltopay), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']); ?></span>
1548 </p>
1549 <?php
1550 }
1551
1552 // build and inject transaction metadata
1553 $array_order['tn_metadata'] = [
1554 'booking_id' => $ord['id'],
1555 'source' => (($ord['channel'] ?? '') ?: 'Website'),
1556 'ota_booking_id' => (($ord['idorderota'] ?? '') ?: ''),
1557 ];
1558
1559 // increase payment processor instances
1560 $payProcessorInstances++;
1561
1562 /**
1563 * Trigger event to allow third-party plugins to manipulate the transaction data.
1564 *
1565 * @since 1.18.5 (J) - 1.8.5 (WP)
1566 */
1567 VBOFactory::getPlatform()->getDispatcher()->trigger('onInitPaymentTransaction', [&$array_order, &$payment['params'], []]);
1568
1569 if (VBOPlatformDetection::isWordPress()) {
1570 /**
1571 * @wponly The payment gateway is now loaded
1572 * using the apposite dispatcher.
1573 *
1574 * @since 1.0.5
1575 */
1576 JLoader::import('adapter.payment.dispatcher');
1577
1578 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $array_order, $payment['params']);
1579 // remember to echo the payment
1580 echo $obj->showPayment();
1581 } else {
1582 /**
1583 * @joomlaonly The Payment Factory library will invoke the gateway.
1584 *
1585 * @since 1.14.3
1586 */
1587 require_once VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'payments' . DIRECTORY_SEPARATOR . 'libraries' . DIRECTORY_SEPARATOR . 'factory.php';
1588 $obj = VBOPaymentFactory::getPaymentInstance($payment['file'], $array_order, $payment['params']);
1589
1590 $obj->showPayment();
1591 }
1592 ?>
1593 </div>
1594 <?php
1595 }
1596
1597 /**
1598 * Check if damage deposit should be paid separately and whether it can be paid right now.
1599 *
1600 * @since 1.17.6 (J) - 1.7.6 (WP)
1601 * @since 1.18.6 (J) - 1.8.6 (WP) allow damage deposit payment button only as single instance.
1602 */
1603 if (!$payProcessorInstances && $ord['status'] == 'confirmed' && ($this->damage_deposit_payment['damagedep_gross'] ?? 0) > 0 && ($this->damage_deposit_payment['payment_window']['payable'] ?? false) && !$this->prev_dd_payments) {
1604 // damage deposit can be paid separately
1605 $dd_payment = !empty($this->damage_deposit_payment['payment_window']['pay_id']) ? VikBooking::getPayment($this->damage_deposit_payment['payment_window']['pay_id'], $vbo_tn) : $payment;
1606
1607 // build transaction URIs
1608 if (VBOPlatformDetection::isWordPress()) {
1609 $return_url = JUri::root() . "index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'];
1610 $error_url = JUri::root() . "index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'];
1611 $notify_url = JUri::root() . "index.php?option=com_vikbooking&task=notifypayment&dd=1&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts']."&tmpl=component";
1612 $model = JModel::getInstance('vikbooking', 'shortcodes', 'admin');
1613 $itemid = $model->best(['booking'], (!empty($ord['lang']) ? $ord['lang'] : null));
1614 if ($itemid) {
1615 $return_url = str_replace(JUri::root(), '', $return_url);
1616 $error_url = str_replace(JUri::root(), '', $error_url);
1617 $notify_url = str_replace(JUri::root(), '', $notify_url);
1618 $return_url = JRoute::rewrite($return_url . "&Itemid={$itemid}", false);
1619 $error_url = JRoute::rewrite($error_url . "&Itemid={$itemid}", false);
1620 $notify_url = JRoute::rewrite($notify_url . "&Itemid={$itemid}", false);
1621 }
1622 } else {
1623 $return_url = VikBooking::externalroute("index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'], false, (!empty($bestitemid) ? $bestitemid : null));
1624 $error_url = VikBooking::externalroute("index.php?option=com_vikbooking&view=booking&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts'], false, (!empty($bestitemid) ? $bestitemid : null));
1625 $notify_url = VikBooking::externalroute("index.php?option=com_vikbooking&task=notifypayment&dd=1&sid=" . (!empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']) . "&ts=" . $ord['ts']."&tmpl=component", false, null);
1626 }
1627
1628 // build payment instructions
1629 $array_order = [];
1630 $array_order['details'] = $ord;
1631 if (empty($array_order['details']['sid']) && !empty($array_order['details']['idorderota']) && !empty($array_order['details']['channel'])) {
1632 $array_order['details']['sid'] = $array_order['details']['idorderota'];
1633 $ord['sid'] = $ord['idorderota'];
1634 }
1635 $array_order['customer_email'] = $ord['custmail'];
1636 $array_order['account_name'] = VikBooking::getPaypalAcc();
1637 $array_order['transaction_currency'] = VikBooking::getCurrencyCodePp();
1638 $array_order['rooms_name'] = implode(", ", $roomsnames);
1639 $array_order['transaction_name'] = !empty($transaction_name) ? $transaction_name : (JText::translate('VBORDERNUMBER') . ' ' . $ord['id']);
1640 $array_order['transaction_name'] .= ' - ' . JText::translate('VBO_DAMAGE_DEPOSIT');
1641 $array_order['order_total'] = $this->damage_deposit_payment['damagedep_gross'];
1642 $array_order['currency_symb'] = $currencysymb;
1643 $array_order['net_price'] = $this->damage_deposit_payment['damagedep_net'];
1644 $array_order['tax'] = $this->damage_deposit_payment['damagedep_tax'];
1645 $array_order['return_url'] = $return_url;
1646 $array_order['error_url'] = $error_url;
1647 $array_order['notify_url'] = $notify_url;
1648 $array_order['total_to_pay'] = $this->damage_deposit_payment['damagedep_gross'];
1649 $array_order['total_net_price'] = $this->damage_deposit_payment['damagedep_net'];
1650 $array_order['total_tax'] = $this->damage_deposit_payment['damagedep_tax'];
1651 $array_order['leave_deposit'] = 0;
1652 $array_order['percentdeposit'] = '';
1653 $array_order['payment_info'] = $dd_payment;
1654 $array_order = array_merge($ord, $array_order);
1655
1656 if (is_array($dd_payment) && !empty($dd_payment['note'])) {
1657 ?>
1658 <div class="vbvordpaynote">
1659 <?php
1660 /**
1661 * @wponly we need to let WordPress parse the paragraphs in the message.
1662 */
1663 if (VBOPlatformDetection::isWordPress()) {
1664 echo wpautop($dd_payment['note']);
1665 } else {
1666 echo $dd_payment['note'];
1667 }
1668 ?>
1669 </div>
1670 <?php
1671 }
1672 ?>
1673 <div class="vbvordpaybutton vbo-damage-deposit-payment">
1674 <?php
1675 // build and inject transaction metadata
1676 $array_order['tn_metadata'] = [
1677 'booking_id' => $ord['id'],
1678 'source' => (($ord['channel'] ?? '') ?: 'Website'),
1679 'ota_booking_id' => (($ord['idorderota'] ?? '') ?: ''),
1680 'damage_deposit' => 1,
1681 ];
1682
1683 // increase payment processor instances
1684 $payProcessorInstances++;
1685
1686 /**
1687 * Trigger event to allow third-party plugins to manipulate the transaction data.
1688 *
1689 * @since 1.18.5 (J) - 1.8.5 (WP)
1690 */
1691 VBOFactory::getPlatform()->getDispatcher()->trigger('onInitPaymentTransaction', [&$array_order, &$payment['params'], []]);
1692
1693 if (VBOPlatformDetection::isWordPress()) {
1694 /**
1695 * @wponly The payment gateway is now loaded
1696 * using the apposite dispatcher.
1697 *
1698 * @since 1.0.5
1699 */
1700 JLoader::import('adapter.payment.dispatcher');
1701
1702 $obj = JPaymentDispatcher::getInstance('vikbooking', $dd_payment['file'], $array_order, $dd_payment['params']);
1703 // remember to echo the payment
1704 echo $obj->showPayment();
1705 } else {
1706 /**
1707 * @joomlaonly The Payment Factory library will invoke the gateway.
1708 *
1709 * @since 1.14.3
1710 */
1711 require_once VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'payments' . DIRECTORY_SEPARATOR . 'libraries' . DIRECTORY_SEPARATOR . 'factory.php';
1712 $obj = VBOPaymentFactory::getPaymentInstance($dd_payment['file'], $array_order, $dd_payment['params']);
1713
1714 $obj->showPayment();
1715 }
1716 ?>
1717 </div>
1718 <?php
1719 }
1720
1721 /**
1722 * Booking review left by the guest
1723 *
1724 * @since 1.13
1725 */
1726 $review = VikBooking::getBookingReview($ord);
1727 if (is_array($review) && $review) {
1728 $rev_services = VikBooking::guestReviewsServices();
1729 $raw_rev_services = array();
1730 foreach ($rev_services as $sk => $sn) {
1731 $raw_rev_services[$sn['service_name']] = $sk;
1732 }
1733 // translate services
1734 $vbo_tn->translateContents($rev_services, '#__vikbooking_greview_service');
1735 ?>
1736 <div class="vbo-booking-guest-review">
1737 <div class="vbo-booking-guest-review-inner">
1738 <div class="vbo-booking-guest-review-top">
1739 <div class="vbo-booking-guest-review-time">
1740 <span><?php echo date(str_replace("/", $datesep, $df).' H:i', strtotime($review['dt'])); ?></span>
1741 </div>
1742 <div class="vbo-booking-guest-review-globalscore">
1743 <span><?php echo $review['score']; ?></span>
1744 </div>
1745 </div>
1746 <div class="vbo-booking-guest-review-bottom">
1747 <?php
1748 // scoring per service
1749 if (isset($review['content']['scoring']) && count($review['content']['scoring']) > 1) {
1750 // some services have been reviewed ("review_score" is always present)
1751 ?>
1752 <div class="vbo-booking-guest-review-services-score">
1753 <?php
1754 $counter = 0;
1755 foreach ($review['content']['scoring'] as $servicename => $servicescore) {
1756 if ($servicename == 'review_score') {
1757 // protected keyword for the global review score
1758 $counter++;
1759 continue;
1760 }
1761 $stars_count = floor($servicescore / 2);
1762 ?>
1763 <div class="vbo-booking-guest-review-service-score">
1764 <div class="vbo-booking-guest-review-service-score-inner">
1765 <div class="vbo-booking-guest-review-service-name">
1766 <span><?php echo isset($raw_rev_services[$servicename]) && isset($rev_services[$raw_rev_services[$servicename]]) ? $rev_services[$raw_rev_services[$servicename]]['service_name'] : ucwords(str_replace('_', ' ', $servicename)); ?></span>
1767 </div>
1768 <div class="vbo-booking-guest-review-service-stars">
1769 <?php
1770 for ($i = 1; $i <= $stars_count; $i++) {
1771 VikBookingIcons::e('star', 'vbo-review-star vbo-review-star-full');
1772 }
1773 for ($i = ($stars_count + 1); $i <= 5; $i++) {
1774 VikBookingIcons::e('star', 'vbo-review-star');
1775 }
1776 ?>
1777 </div>
1778 </div>
1779 </div>
1780 <?php
1781 $counter++;
1782 }
1783 ?>
1784 </div>
1785 <?php
1786 } elseif (isset($review['content']['scoring']) && isset($review['content']['scoring']['review_score'])) {
1787 // this is a global score for no services
1788 $stars_count = floor($review['content']['scoring']['review_score'] / 2);
1789 ?>
1790 <div class="vbo-booking-guest-review-services-score vbo-booking-guest-review-singleservice">
1791 <div class="vbo-booking-guest-review-service-name">
1792 <span><?php echo JText::translate('VBOREVIEWYOURRATING'); ?></span>
1793 </div>
1794 <div class="vbo-booking-guest-review-service-stars">
1795 <?php
1796 for ($i = 1; $i <= $stars_count; $i++) {
1797 VikBookingIcons::e('star', 'vbo-review-star vbo-review-star-full');
1798 }
1799 for ($i = ($stars_count + 1); $i <= 5; $i++) {
1800 VikBookingIcons::e('star', 'vbo-review-star');
1801 }
1802 ?>
1803 </div>
1804 </div>
1805 <?php
1806 }
1807 // guest review message
1808 if (isset($review['content']['content']) && !empty($review['content']['content']['message'])) {
1809 ?>
1810 <div class="vbo-booking-guest-review-message">
1811 <p><?php echo nl2br($review['content']['content']['message']); ?></p>
1812 </div>
1813 <?php
1814 }
1815 // owner reply
1816 if (isset($review['content']['reply']) && ((is_string($review['content']['reply']) && !empty($review['content']['reply'])) || (is_array($review['content']['reply']) && !empty($review['content']['reply']['text'])))) {
1817 $reply_text = is_array($review['content']['reply']) && isset($review['content']['reply']['text']) ? $review['content']['reply']['text'] : $review['content']['reply'];
1818 ?>
1819 <div class="vbo-booking-guest-review-owner-reply">
1820 <h5><?php echo JText::translate('VBOGREVOWNREPLY'); ?></h5>
1821 <p><?php echo nl2br($reply_text); ?></p>
1822 </div>
1823 <?php
1824 }
1825 ?>
1826 </div>
1827 </div>
1828 </div>
1829 <?php
1830 }
1831
1832 /**
1833 * Upselling Options/Extras block.
1834 *
1835 * @since 1.13 (J) - 1.3.0 (WP)
1836 */
1837 $tot_upselling = count($this->upselling);
1838 if ($tot_upselling) {
1839 // at least one room has options that can be up-sold
1840 $formatparts = explode(':', VikBooking::getNumberFormatData());
1841 ?>
1842 <div class="vbo-hidein-print vbo-booking-upsell-container">
1843 <h3><?php echo JText::translate('VBOUPSELLTITLE'); ?></h3>
1844 <form method="post" action="<?php echo JRoute::rewrite('index.php?option=com_vikbooking&task=upsellextras' . (!empty($pitemid) ? '&Itemid='.$pitemid : '')); ?>">
1845 <div class="vbo-booking-upsell-inner <?php echo $tot_upselling > 1 ? 'vbo-booking-upsell-inner-multi' : 'vbo-booking-upsell-inner-single'; ?>">
1846 <?php
1847 foreach ($this->upselling as $kor => $uproom) {
1848 if (!isset($uproom->upsellable) || !count($uproom->upsellable)) {
1849 // no upsellable options for this room
1850 continue;
1851 }
1852 ?>
1853 <div class="vbo-booking-upsell-room-wrap">
1854 <?php
1855 if ($tot_upselling > 1) {
1856 // write the room name and adults/children in case of multiple rooms booked
1857 ?>
1858 <h5 class="vbo-booking-upsell-room-details">
1859 <span class="vbo-booking-upsell-room-name"><?php echo $uproom->name; ?></span>
1860 <span class="vbo-booking-upsell-room-adults"><?php echo $uproom->adults; ?> <?php echo ($uproom->adults == 1 ? JText::translate('VBSEARCHRESADULT') : JText::translate('VBSEARCHRESADULTS')); ?></span>
1861 <?php
1862 if ($orderrooms[$kor]['children'] > 0) {
1863 ?>
1864 <span class="vbo-booking-upsell-room-children"><?php echo $orderrooms[$kor]['children'] . " " . ($orderrooms[$kor]['children'] == 1 ? JText::translate('VBSEARCHRESCHILD') : JText::translate('VBSEARCHRESCHILDREN')); ?></span>
1865 <?php
1866 }
1867 ?>
1868 </h5>
1869 <?php
1870 }
1871 ?>
1872 <div class="vbo-upsell-options-wrap">
1873 <?php
1874 // determine proper nights of stay
1875 $room_stay_nights = $ord['days'];
1876 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $uproom->id) {
1877 $room_stay_nights = $room_stay_dates[$kor]['nights'];
1878 }
1879
1880 foreach ($uproom->upsellable as $o) {
1881 if ((int)$o['pcentroom']) {
1882 // make sure we have a cost for the room, or we should skip this type of option for "incomplete" bookings
1883 if (!isset($orderrooms[$kor]) || (empty($orderrooms[$kor]['cust_cost']) && empty($orderrooms[$kor]['room_cost']))) {
1884 continue;
1885 }
1886 $o['cost'] = ((!empty($orderrooms[$kor]['cust_cost']) ? $orderrooms[$kor]['cust_cost'] : $orderrooms[$kor]['room_cost']) * $o['cost'] / 100);
1887 }
1888 $optcost = intval($o['perday']) == 1 ? ($o['cost'] * $room_stay_nights) : $o['cost'];
1889 if (!empty($o['maxprice']) && $o['maxprice'] > 0 && $optcost > $o['maxprice']) {
1890 $optcost = $o['maxprice'];
1891 }
1892 if ($o['perperson'] == 1) {
1893 $optcost = $optcost * $orderrooms[$kor]['adults'];
1894 }
1895 $optcost = $optcost * 1;
1896
1897 /**
1898 * Trigger event to allow third party plugins to apply a custom calculation for the option/extra fee or tax.
1899 *
1900 * @since 1.17.7 (J) - 1.7.7 (WP)
1901 */
1902 $custom_calculation = VBOFactory::getPlatform()->getDispatcher()->filter('onCalculateBookingOptionFeeCost', [$optcost, &$o, $ord, $orderrooms[$kor]]);
1903 if ($custom_calculation) {
1904 $optcost = (float) $custom_calculation[0];
1905 }
1906
1907 $optquaninp = '';
1908 $optquanbtn = '';
1909 if (intval($o['hmany']) == 1) {
1910 if (intval($o['maxquant']) > 0) {
1911 $optquaninp = "<select id=\"vboaddextra-{$kor}-{$o['id']}\">\n";
1912 for ($ojj = 0; $ojj <= intval($o['maxquant']); $ojj++) {
1913 $optquaninp .= "<option value=\"" . $ojj . "\">" . $ojj . "</option>\n";
1914 }
1915 $optquaninp .= "</select>\n";
1916 } else {
1917 $optquaninp = "<input type=\"number\" min=\"0\" step=\"any\" id=\"vboaddextra-{$kor}-{$o['id']}\" value=\"0\" size=\"5\"/>";
1918 }
1919 $optquanbtn = '<button type="button" class="btn vbo-pref-color-btn" onclick="vboAddExtra(' . $kor . ', ' . $o['id'] . ', -1);"><i class="' . VikBookingIcons::i('cart-plus') . '"></i> ' . JText::translate('VBOUPSELLADD') . '</button>';
1920 } else {
1921 $optquanbtn = '<button type="button" class="btn vbo-pref-color-btn" onclick="vboAddExtra(' . $kor . ', ' . $o['id'] . ', 1);"><i class="' . VikBookingIcons::i('cart-plus') . '"></i> ' . JText::translate('VBOUPSELLADD') . '</button>';
1922 }
1923 ?>
1924 <div class="vbo-upsell-option-entry" id="vbo-option-upsell-<?php echo $kor . '-' . $o['id']; ?>">
1925 <?php
1926 if (!empty($o['img'])) {
1927 ?>
1928 <div class="vbo-upsell-option-entry-img">
1929 <?php echo '<img class="maxthirty" src="' . VBO_SITE_URI . 'resources/uploads/' . $o['img'] . '"/>'; ?>
1930 </div>
1931 <?php
1932 }
1933 ?>
1934 <div class="vbo-upsell-option-entry-name">
1935 <span><?php echo $o['name']; ?></span>
1936 <?php
1937 if (!empty($o['descr'])) {
1938 ?>
1939 <div class="vbo-upsell-option-entry-descr">
1940 <?php echo $o['descr']; ?>
1941 </div>
1942 <?php
1943 }
1944 $floatoptprice = VikBooking::sayOptionalsPlusIva($optcost, $o['idiva']);
1945 ?>
1946 </div>
1947 <div class="vbo-upsell-option-entry-cost" data-currency="<?php echo $currencysymb; ?>" data-floatprice="<?php echo (float)$floatoptprice; ?>">
1948 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($floatoptprice), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']); ?>
1949 </div>
1950 <div class="vbo-upsell-option-entry-input">
1951 <?php echo $optquaninp; ?>
1952 </div>
1953 <div class="vbo-option-upsell-add">
1954 <?php echo $optquanbtn; ?>
1955 </div>
1956 </div>
1957 <?php
1958 }
1959 ?>
1960 </div>
1961 <div class="vbo-room-upsell-cart" id="vbo-room-upsell-cart-<?php echo $kor; ?>"></div>
1962 </div>
1963 <?php
1964 }
1965 ?>
1966 </div>
1967 <input type="hidden" name="task" value="upsellextras">
1968 <input type="hidden" name="sid" value="<?php echo !empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']; ?>">
1969 <input type="hidden" name="ts" value="<?php echo $ord['ts']; ?>">
1970 <div class="vbo-booking-upsell-confirm" style="display: none;">
1971 <div class="vbo-booking-upsell-confirm-inner">
1972 <div class="vbo-booking-upsell-confirm-total">
1973 <span class="vbo-booking-upsell-confirm-txt"><?php echo JText::translate('VBTOTAL'); ?></span>
1974 <span class="vbo_currency vbo-booking-upsell-confirm-currency"><?php echo $currencysymb; ?></span>
1975 <span class="vbo_price vbo-booking-upsell-confirm-amount"></span>
1976 </div>
1977 <div class="vbo-booking-upsell-confirm-btn">
1978 <button type="submit" class="btn btn-large vbo-pref-color-btn" onclick="return confirm('<?php echo addslashes(JText::translate('VBOUPSELLCONFIRM')); ?>');"><?php VikBookingIcons::e('check-circle'); ?> <?php echo JText::translate('VBOUPSELLUPDATE'); ?></button>
1979 </div>
1980 </div>
1981 </div>
1982 </form>
1983 </div>
1984
1985 <script type="text/javascript">
1986 var vbototextras = 0;
1987 function vboAddExtra(kor, optid, quant) {
1988 if (quant < 0) {
1989 // get the quantity from the input/select tag
1990 quant = jQuery('#vboaddextra-' + kor + '-' + optid).val();
1991 if (!quant || isNaN(quant)) {
1992 console.error('input not found', kor, optid, quant);
1993 return false;
1994 }
1995 if (quant < 1) {
1996 alert('<?php echo addslashes(JText::translate('VBOUPSELLQUANTOPT0')); ?>');
1997 return false;
1998 }
1999 }
2000 var cartelem = jQuery('#vbo-room-upsell-option-' + kor + '-' + optid);
2001 if (cartelem.length) {
2002 // remove element from cart if already existed for later appending it to the cart again
2003 vboRemoveExtra(kor, optid);
2004 }
2005 // add element to the cart
2006 var optelem = jQuery('#vbo-option-upsell-' + kor + '-' + optid);
2007 if (!optelem.length) {
2008 console.error('option not found', kor, optid);
2009 return false;
2010 }
2011 // price
2012 var optprice = parseFloat(optelem.find('.vbo-upsell-option-entry-cost').attr('data-floatprice')) * quant;
2013 //
2014 var newcartelem = '<div class="vbo-room-upsell-cart-option" id="vbo-room-upsell-option-' + kor + '-' + optid + '" data-floatprice="' + optprice + '">';
2015 newcartelem += '<div class="vbo-room-upsell-cart-option-name">' + optelem.find('.vbo-upsell-option-entry-name span').text() + (quant > 1 ? ' (x' + quant + ')' : '') + '</div>';
2016 if (quant < 2) {
2017 // single quantity can take the formatted option price
2018 newcartelem += '<div class="vbo-room-upsell-cart-option-cost">' + optelem.find('.vbo-upsell-option-entry-cost').html() + '</div>';
2019 } else {
2020 // multiple quantities should multiply the single raw cost not formatted
2021 var optcurrency = optelem.find('.vbo-upsell-option-entry-cost').attr('data-currency');
2022 if ('<?php echo VikBooking::getCurrencyPosition(); ?>' === 'after') {
2023 newcartelem += '<div class="vbo-room-upsell-cart-option-cost">' + optprice.toFixed(<?php echo (int)$formatparts[0]; ?>) + ' ' + optcurrency + '</div>';
2024 } else {
2025 newcartelem += '<div class="vbo-room-upsell-cart-option-cost">' + optcurrency + ' ' + optprice.toFixed(<?php echo (int)$formatparts[0]; ?>) + '</div>';
2026 }
2027 }
2028 // increase global total
2029 vbototextras += optprice;
2030 //
2031 newcartelem += '<div class="vbo-room-upsell-cart-option-rm"><button type="button" class="btn btn-danger" onclick="vboRemoveExtra(' + kor + ', ' + optid + ');"><i class="<?php echo VikBookingIcons::i('trash-alt'); ?>"></i></button></div>';
2032 // the necessary input field that will be submitted with the form
2033 newcartelem += '<input type="hidden" name="addopt[' + kor + '][' + optid + ']" value="' + quant + '"/>';
2034 //
2035 newcartelem += '</div>';
2036 // append new element to the cart and make sure the full class is set
2037 jQuery('#vbo-room-upsell-cart-' + kor).append(newcartelem).addClass('vbo-room-upsell-cart-full');
2038 // highlight the option so that we can see it was reserved by adding a class to the container
2039 optelem.addClass('vbo-option-upsell-addedtocart');
2040 // display the save button
2041 jQuery('.vbo-booking-upsell-confirm').fadeIn();
2042 // refresh total
2043 vboRefreshTotal();
2044 }
2045 function vboRemoveExtra(kor, optid) {
2046 var cartelem = jQuery('#vbo-room-upsell-option-' + kor + '-' + optid);
2047 if (!cartelem.length) {
2048 console.error('could not find option to remove from the cart', kor, optid);
2049 return false;
2050 }
2051 // decrease global total
2052 vbototextras -= parseFloat(cartelem.attr('data-floatprice'));
2053 //
2054 cartelem.remove();
2055 // remove class that highlights that the option was reserved
2056 jQuery('#vbo-option-upsell-' + kor + '-' + optid).removeClass('vbo-option-upsell-addedtocart');
2057 // check if the cart for this room is no longer full
2058 if (!jQuery('#vbo-room-upsell-cart-' + kor).find('.vbo-room-upsell-cart-option').length) {
2059 jQuery('#vbo-room-upsell-cart-' + kor).removeClass('vbo-room-upsell-cart-full');
2060 }
2061 // hide the save button if no options in the cart
2062 if (!jQuery('.vbo-room-upsell-cart-option').length) {
2063 jQuery('.vbo-booking-upsell-confirm').fadeOut();
2064 }
2065 // refresh total
2066 vboRefreshTotal();
2067 }
2068 function vboRefreshTotal() {
2069 jQuery('.vbo-booking-upsell-confirm-amount').text(vbototextras.toFixed(<?php echo (int)$formatparts[0]; ?>));
2070 }
2071 </script>
2072 <?php
2073 }
2074
2075 /**
2076 * Render the chat with the front-end handler 'vikbooking'.
2077 * OTA bookings cannot be displayed in front-end so we cannot
2078 * use any other chat handler. Chat can be disabled from config.
2079 * Using the chat via front-end imposes the guest to be the sender.
2080 *
2081 * @since 1.12 (J) - 1.1.7 (WP)
2082 */
2083 $messaging = null;
2084 if (VikBooking::chatEnabled() > 0) {
2085 // -1 means that VCM is not enabled
2086 $chat_available = true;
2087 // check if chat can still be displayed to the guest
2088 $chat_params = VikBooking::getChatParams();
2089 if (!isset($chat_params->res_status) || !in_array($ord['status'], $chat_params->res_status)) {
2090 // chat is disabled for this reservation status
2091 $chat_available = false;
2092 }
2093 if (isset($chat_params->av_type) && isset($chat_params->av_days)) {
2094 // check days of validity after checkin or checkout
2095 $chat_lim_ts = $chat_params->av_type == 'checkin' ? strtotime("+{$chat_params->av_days} days", $ord['checkin']) : strtotime("+{$chat_params->av_days} days", $ord['checkout']);
2096 // compare limits at midnight
2097 $now_midnight = mktime(0, 0, 0, date('n'), date('j'), date('Y'));
2098 $lim_midnight = mktime(0, 0, 0, date('n', $chat_lim_ts), date('j', $chat_lim_ts), date('Y', $chat_lim_ts));
2099 if ($now_midnight > $lim_midnight) {
2100 // limit date is in the past
2101 $chat_available = false;
2102 }
2103 }
2104 if ($chat_available) {
2105 // attempt to get the class instance
2106 $messaging = VikBooking::getVcmChatInstance([$ord['id'], $ord['ts']], 'vikbooking');
2107 }
2108 }
2109 if (!is_null($messaging)) {
2110 $tot_unread = VCMChatHandler::countUnreadMessages($ord['id']);
2111 ?>
2112 <div class="vbo-booking-chat-wrap vbo-booking-chat-closed">
2113 <div class="vbo-booking-chat-inner">
2114 <div class="vbo-booking-chat-control" data-message-count="<?php echo $tot_unread; ?>"><?php VikBookingIcons::e('commenting'); ?></div>
2115 <div class="vbo-booking-chat-container" style="display: none;">
2116 <h4 class="vbo-booking-chat-intro"><?php echo JText::sprintf('VBOCHATWITH', VikBooking::getFrontTitle()); ?></h4>
2117 <?php echo $messaging->renderChat(); ?>
2118 </div>
2119 </div>
2120 </div>
2121 <script type="text/javascript">
2122 jQuery(function() {
2123 jQuery('.vbo-booking-chat-control').click(function() {
2124 jQuery(this).remove();
2125 jQuery('.vbo-booking-chat-wrap').removeClass('vbo-booking-chat-closed');
2126 jQuery('.vbo-booking-chat-container').fadeIn(400, function() {
2127 // animate to that position
2128 jQuery('html,body').animate({scrollTop: jQuery('.vbo-booking-chat-container').offset().top - 20}, {duration: 400});
2129 if (typeof VCMChat !== 'undefined') {
2130 VCMChat.getInstance().scrollToBottom();
2131 }
2132 });
2133 });
2134 jQuery(window).on('chatsync', function(e) {
2135 // VCMChat event listener to update notifications badge for new messages
2136 var newNotifications = e.detail.notifications;
2137 var currentMessages = parseInt(jQuery('.vbo-booking-chat-control').attr('data-message-count'));
2138 jQuery('.vbo-booking-chat-control').attr('data-message-count', (newNotifications + currentMessages));
2139 });
2140
2141 if (window.location.hash == '#messaging') {
2142 const trigger = document.querySelector('.vbo-booking-chat-control');
2143 if (trigger) {
2144 trigger.click();
2145 }
2146 }
2147 });
2148 </script>
2149 <?php
2150 }
2151
2152 /**
2153 * If necessary, move the payment form onto the selected position.
2154 *
2155 * @since 1.14 (J) - 1.4.0 (WP)
2156 * @since 1.17.6 (J) - 1.7.6 (WP) added support for damage deposit payment
2157 */
2158 if ((is_array($this->payment) && $this->payment['outposition'] != 'bottom') || (isset($dd_payment) && is_array($dd_payment) && $dd_payment['outposition'] != 'bottom')) {
2159 // move the payment window, if available
2160 $payment_position = isset($dd_payment) && is_array($dd_payment) && $dd_payment['outposition'] != 'bottom' ? $dd_payment['outposition'] : $this->payment['outposition'];
2161 ?>
2162 <script type="text/javascript">
2163
2164 VBOCore.DOMLoaded(() => {
2165
2166 setTimeout(() => {
2167 let payment_output = document.querySelectorAll('.vbvordpaybutton'),
2168 payment_notes = document.querySelectorAll('.vbvordpaynote'),
2169 payment_ctimer = document.querySelector('.vbo-timer-payment'),
2170 payment_wrappr = document.querySelector('.vbo-paycontainer-pos-<?php echo $payment_position; ?>');
2171
2172 if (payment_output.length && payment_wrappr) {
2173 // display final target
2174 payment_wrappr.style.display = '';
2175
2176 if (payment_notes.length) {
2177 payment_notes.forEach((payment_notes_block) => {
2178 // prepend notes first
2179 payment_wrappr.prepend(payment_notes_block);
2180 });
2181 }
2182
2183 if (payment_ctimer) {
2184 // prepend countdown timer first
2185 payment_wrappr.prepend(payment_ctimer);
2186 }
2187
2188 payment_output.forEach((payment_output_block) => {
2189 // append payment output
2190 payment_wrappr.append(payment_output_block);
2191 });
2192 }
2193 }, 50);
2194
2195 });
2196
2197 </script>
2198 <?php
2199 }
2200 //
2201