PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.7
VikBooking Hotel Booking Engine & PMS v1.8.7
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / site / views / booking / tmpl / default.php

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

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