PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.8
VikBooking Hotel Booking Engine & PMS v1.8.8
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.8, at site/views/booking/tmpl/default.php

2,119 lines 89.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 && !((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 && 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 // count minutes elapsed from booking creation date
1325 $mins_elapsed = floor(($now_info[0] - $ord['ts']) / 60);
1326
1327 /**
1328 * Check if we are dealing with a pending booking solution of a quote.
1329 *
1330 * @since 1.18.8 (J) - 1.8.8 (WP)
1331 */
1332 if ($this->quoteValidUntilDt) {
1333 // get the date interval of difference between valid until date and current date
1334 $validityDiff = $this->quoteValidUntilDt->diff(JFactory::getDate('now'));
1335 // count the number of minutes still available (expected validity to be in the future)
1336 $minautoremove = ($validityDiff->days * 1440) + ($validityDiff->h * 60) + $validityDiff->i;
1337 // add up the minutes elapsed to allow an accurate calcilation of the remaining minutes
1338 $minautoremove += $mins_elapsed;
1339 } else {
1340 // global booking auto-removal minutes
1341 $minautoremove = VikBooking::getMinutesAutoRemove();
1342 }
1343
1344 // check if we should display a countdown for the automatic booking cancellation
1345 $remainmin = $minautoremove - $mins_elapsed;
1346 $remainmin = $remainmin < 1 ? 1 : $remainmin;
1347 if ($minautoremove > 0 && $minautoremove < 35791) {
1348 /**
1349 * Ensure the timeout milliseconds in 32-bit do not exceed
1350 * the maximum value of 2,147,483,647ms (~35791,39 minutes).
1351 *
1352 * @since 1.16.10 (J) - 1.6.10 (WP)
1353 */
1354 $booktime_info = getdate($ord['ts']);
1355 $booktime_offset = date('Z', $ord['ts']) / 60;
1356 $remainmilsec = intval($remainmin * 60 * 1000) + 100;
1357 $remainmilsec = $remainmilsec < 100 ? 100 : $remainmilsec;
1358 // calculate the values for the timer
1359 $days_left = $remainmin > 1440 ? floor($remainmin / 1440) : 0;
1360 $remainmin -= $days_left * 1440;
1361 $hours_left = $remainmin > 59 ? floor($remainmin / 60) : 0;
1362 $minutes_left = $remainmin - ($hours_left * 60);
1363 $lbl_hour = strtolower(JText::translate('VBHOUR'));
1364 $lbl_hours = strtolower(JText::translate('VBHOURS'));
1365 $lbl_minute = strtolower(JText::translate('VBMINUTE'));
1366 $lbl_minutes = strtolower(JText::translate('VBMINUTES'));
1367 $lbl_day = strtolower(JText::translate('VBO_DAY'));
1368 $lbl_days = strtolower(JText::translate('VBO_DAYS'));
1369 $timer_str = $days_left > 0 ? '<span id="vbo-timer-days">' . $days_left . ' ' . ($days_left == 1 ? $lbl_day : $lbl_days) . '</span> ' : '';
1370 $timer_str .= $days_left > 0 || $hours_left > 0 ? '<span id="vbo-timer-hours">' . $hours_left . ' ' . ($hours_left == 1 ? $lbl_hour : $lbl_hours) . '</span> ' : '';
1371 $timer_str .= '<span id="vbo-timer-minutes">' . $minutes_left . ' ' . ($minutes_left == 1 ? $lbl_minute : $lbl_minutes) . '</span>';
1372 ?>
1373 <script type="text/javascript">
1374 var vboPayTimerLbl = {
1375 "hour": "<?php echo addslashes($lbl_hour); ?>",
1376 "hours": "<?php echo addslashes($lbl_hours); ?>",
1377 "minute": "<?php echo addslashes($lbl_minute); ?>",
1378 "minutes": "<?php echo addslashes($lbl_minutes); ?>",
1379 "day": "<?php echo addslashes($lbl_day); ?>",
1380 "days": "<?php echo addslashes($lbl_days); ?>",
1381 }
1382 var vboPayTimeout = setTimeout(function() {
1383 document.location.href = '<?php echo $elapsed_redirect_uri; ?>';
1384 }, <?php echo $remainmilsec; ?>);
1385 var vboPayInterval = setInterval("vboRefreshPayTimer()", 60000);
1386 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);
1387 var vboPayTimerOffsetSet = false;
1388 function vboPauseTimeout() {
1389 clearTimeout(vboPayTimeout);
1390 }
1391 function vboRefreshPayTimer() {
1392 const vboNow = new Date();
1393 if (!vboPayTimerOffsetSet) {
1394 let tzoffset = vboNow.getTimezoneOffset() * -1 - <?php echo $booktime_offset; ?>;
1395 vboBookInfo.setMinutes(vboBookInfo.getMinutes() + tzoffset);
1396 vboPayTimerOffsetSet = true;
1397 }
1398
1399 let mins_elapsed = Math.floor((vboNow - vboBookInfo) / 1000 / 60);
1400 let remainmin = <?php echo $minautoremove; ?> - mins_elapsed;
1401 let days_left = remainmin > 1440 ? Math.floor(remainmin / 1440) : 0;
1402 remainmin -= days_left * 1440;
1403 let hours_left = remainmin > 59 ? Math.floor(remainmin / 60) : 0;
1404 let minutes_left = remainmin - (hours_left * 60);
1405 if (days_left < 1 && hours_left < 1 && minutes_left < 1) {
1406 clearInterval(vboPayInterval);
1407 if (document.getElementById('vbo-timer-payment')) {
1408 document.getElementById('vbo-timer-payment').style.display = 'none';
1409 }
1410 return false;
1411 }
1412 if (document.getElementById('vbo-timer-days')) {
1413 if (days_left < 1) {
1414 document.getElementById('vbo-timer-days').style.display = 'none';
1415 } else {
1416 document.getElementById('vbo-timer-days').textContent = days_left + ' ' + (days_left == 1 ? vboPayTimerLbl['day'] : vboPayTimerLbl['days']);
1417 }
1418 }
1419 if (document.getElementById('vbo-timer-hours')) {
1420 if (hours_left < 1) {
1421 document.getElementById('vbo-timer-hours').style.display = 'none';
1422 } else {
1423 document.getElementById('vbo-timer-hours').textContent = hours_left + ' ' + (hours_left == 1 ? vboPayTimerLbl['hour'] : vboPayTimerLbl['hours']);
1424 }
1425 }
1426 document.getElementById('vbo-timer-minutes').textContent = minutes_left + ' ' + (minutes_left == 1 ? vboPayTimerLbl['minute'] : vboPayTimerLbl['minutes']);
1427 }
1428 </script>
1429
1430 <div class="vbo-timer-payment" id="vbo-timer-payment">
1431 <span class="vbo-timer-payment-str">
1432 <?php echo JText::sprintf('VBOTIMERPAYMENTSTR', $timer_str); ?>
1433 </span>
1434 </div>
1435 <?php
1436 } elseif ($minautoremove > 0) {
1437 // we expect a very high number of remaining minutes to be expressed in days
1438 ?>
1439 <div class="vbo-timer-payment" id="vbo-timer-payment">
1440 <span class="vbo-timer-payment-str">
1441 <?php
1442 $days_left = max(0, floor($remainmin / 1440));
1443 echo JText::sprintf('VBOTIMERPAYMENTSTR', sprintf(
1444 '~%d %s',
1445 $days_left,
1446 JText::translate($days_left == 1 ? 'VBO_DAY' : 'VBO_DAYS')
1447 ));
1448 ?>
1449 </span>
1450 </div>
1451 <?php
1452 }
1453
1454 ?>
1455 <div class="vbvordpaybutton">
1456 <?php
1457 if ($totalchanged) {
1458 $chdecimals = $payment['charge'] - (int)$payment['charge'];
1459 ?>
1460 <p class="vbpaymentchangetot">
1461 <span class="vbpaymentnamediff">
1462 <span><?php echo $payment['name']; ?></span>
1463 (<?php
1464 echo $payment['ch_disc'] == 1 ? '+' : '-';
1465 if ($payment['val_pcent'] == 1) {
1466 echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($payment['charge']), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']);
1467 } else {
1468 echo '<span class="vbo_price">' . VikBooking::numberFormat($payment['charge']) . '</span> %';
1469 }
1470 ?>)
1471 </span>
1472 <span class="vborddiffpayment"><?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($newtotaltopay), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']); ?></span>
1473 </p>
1474 <?php
1475 }
1476
1477 // build and inject transaction metadata
1478 $array_order['tn_metadata'] = [
1479 'booking_id' => $ord['id'],
1480 'source' => (($ord['channel'] ?? '') ?: 'Website'),
1481 'ota_booking_id' => (($ord['idorderota'] ?? '') ?: ''),
1482 ];
1483
1484 // increase payment processor instances
1485 $payProcessorInstances++;
1486
1487 /**
1488 * Trigger event to allow third-party plugins to manipulate the transaction data.
1489 *
1490 * @since 1.18.5 (J) - 1.8.5 (WP)
1491 */
1492 VBOFactory::getPlatform()->getDispatcher()->trigger('onInitPaymentTransaction', [&$array_order, &$payment['params'], []]);
1493
1494 if (VBOPlatformDetection::isWordPress()) {
1495 /**
1496 * @wponly The payment gateway is now loaded
1497 * using the apposite dispatcher.
1498 *
1499 * @since 1.0.5
1500 */
1501 JLoader::import('adapter.payment.dispatcher');
1502
1503 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $array_order, $payment['params']);
1504 // remember to echo the payment
1505 echo $obj->showPayment();
1506 } else {
1507 /**
1508 * @joomlaonly The Payment Factory library will invoke the gateway.
1509 *
1510 * @since 1.14.3
1511 */
1512 require_once VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'payments' . DIRECTORY_SEPARATOR . 'libraries' . DIRECTORY_SEPARATOR . 'factory.php';
1513 $obj = VBOPaymentFactory::getPaymentInstance($payment['file'], $array_order, $payment['params']);
1514
1515 $obj->showPayment();
1516 }
1517 ?>
1518 </div>
1519 <?php
1520 }
1521
1522 /**
1523 * Check if damage deposit should be paid separately and whether it can be paid right now.
1524 *
1525 * @since 1.17.6 (J) - 1.7.6 (WP)
1526 * @since 1.18.6 (J) - 1.8.6 (WP) allow damage deposit payment button only as single instance.
1527 */
1528 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) {
1529 // damage deposit can be paid separately
1530 $dd_payment = !empty($this->damage_deposit_payment['payment_window']['pay_id']) ? VikBooking::getPayment($this->damage_deposit_payment['payment_window']['pay_id'], $vbo_tn) : $payment;
1531
1532 // build transaction URIs
1533 if (VBOPlatformDetection::isWordPress()) {
1534 $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'];
1535 $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'];
1536 $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";
1537 $model = JModel::getInstance('vikbooking', 'shortcodes', 'admin');
1538 $itemid = $model->best(['booking'], (!empty($ord['lang']) ? $ord['lang'] : null));
1539 if ($itemid) {
1540 $return_url = str_replace(JUri::root(), '', $return_url);
1541 $error_url = str_replace(JUri::root(), '', $error_url);
1542 $notify_url = str_replace(JUri::root(), '', $notify_url);
1543 $return_url = JRoute::rewrite($return_url . "&Itemid={$itemid}", false);
1544 $error_url = JRoute::rewrite($error_url . "&Itemid={$itemid}", false);
1545 $notify_url = JRoute::rewrite($notify_url . "&Itemid={$itemid}", false);
1546 }
1547 } else {
1548 $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));
1549 $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));
1550 $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);
1551 }
1552
1553 // build payment instructions
1554 $array_order = [];
1555 $array_order['details'] = $ord;
1556 if (empty($array_order['details']['sid']) && !empty($array_order['details']['idorderota']) && !empty($array_order['details']['channel'])) {
1557 $array_order['details']['sid'] = $array_order['details']['idorderota'];
1558 $ord['sid'] = $ord['idorderota'];
1559 }
1560 $array_order['customer_email'] = $ord['custmail'];
1561 $array_order['account_name'] = VikBooking::getPaypalAcc();
1562 $array_order['transaction_currency'] = VikBooking::getCurrencyCodePp();
1563 $array_order['rooms_name'] = implode(", ", $roomsnames);
1564 $array_order['transaction_name'] = !empty($transaction_name) ? $transaction_name : (JText::translate('VBORDERNUMBER') . ' ' . $ord['id']);
1565 $array_order['transaction_name'] .= ' - ' . JText::translate('VBO_DAMAGE_DEPOSIT');
1566 $array_order['order_total'] = $this->damage_deposit_payment['damagedep_gross'];
1567 $array_order['currency_symb'] = $currencysymb;
1568 $array_order['net_price'] = $this->damage_deposit_payment['damagedep_net'];
1569 $array_order['tax'] = $this->damage_deposit_payment['damagedep_tax'];
1570 $array_order['return_url'] = $return_url;
1571 $array_order['error_url'] = $error_url;
1572 $array_order['notify_url'] = $notify_url;
1573 $array_order['total_to_pay'] = $this->damage_deposit_payment['damagedep_gross'];
1574 $array_order['total_net_price'] = $this->damage_deposit_payment['damagedep_net'];
1575 $array_order['total_tax'] = $this->damage_deposit_payment['damagedep_tax'];
1576 $array_order['leave_deposit'] = 0;
1577 $array_order['percentdeposit'] = '';
1578 $array_order['payment_info'] = $dd_payment;
1579 $array_order = array_merge($ord, $array_order);
1580
1581 if (is_array($dd_payment) && !empty($dd_payment['note'])) {
1582 ?>
1583 <div class="vbvordpaynote">
1584 <?php
1585 /**
1586 * @wponly we need to let WordPress parse the paragraphs in the message.
1587 */
1588 if (VBOPlatformDetection::isWordPress()) {
1589 echo wpautop($dd_payment['note']);
1590 } else {
1591 echo $dd_payment['note'];
1592 }
1593 ?>
1594 </div>
1595 <?php
1596 }
1597 ?>
1598 <div class="vbvordpaybutton vbo-damage-deposit-payment">
1599 <?php
1600 // build and inject transaction metadata
1601 $array_order['tn_metadata'] = [
1602 'booking_id' => $ord['id'],
1603 'source' => (($ord['channel'] ?? '') ?: 'Website'),
1604 'ota_booking_id' => (($ord['idorderota'] ?? '') ?: ''),
1605 'damage_deposit' => 1,
1606 ];
1607
1608 // increase payment processor instances
1609 $payProcessorInstances++;
1610
1611 /**
1612 * Trigger event to allow third-party plugins to manipulate the transaction data.
1613 *
1614 * @since 1.18.5 (J) - 1.8.5 (WP)
1615 */
1616 VBOFactory::getPlatform()->getDispatcher()->trigger('onInitPaymentTransaction', [&$array_order, &$payment['params'], []]);
1617
1618 if (VBOPlatformDetection::isWordPress()) {
1619 /**
1620 * @wponly The payment gateway is now loaded
1621 * using the apposite dispatcher.
1622 *
1623 * @since 1.0.5
1624 */
1625 JLoader::import('adapter.payment.dispatcher');
1626
1627 $obj = JPaymentDispatcher::getInstance('vikbooking', $dd_payment['file'], $array_order, $dd_payment['params']);
1628 // remember to echo the payment
1629 echo $obj->showPayment();
1630 } else {
1631 /**
1632 * @joomlaonly The Payment Factory library will invoke the gateway.
1633 *
1634 * @since 1.14.3
1635 */
1636 require_once VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'payments' . DIRECTORY_SEPARATOR . 'libraries' . DIRECTORY_SEPARATOR . 'factory.php';
1637 $obj = VBOPaymentFactory::getPaymentInstance($dd_payment['file'], $array_order, $dd_payment['params']);
1638
1639 $obj->showPayment();
1640 }
1641 ?>
1642 </div>
1643 <?php
1644 }
1645
1646 /**
1647 * Booking review left by the guest
1648 *
1649 * @since 1.13
1650 */
1651 $review = VikBooking::getBookingReview($ord);
1652 if (is_array($review) && $review) {
1653 $rev_services = VikBooking::guestReviewsServices();
1654 $raw_rev_services = array();
1655 foreach ($rev_services as $sk => $sn) {
1656 $raw_rev_services[$sn['service_name']] = $sk;
1657 }
1658 // translate services
1659 $vbo_tn->translateContents($rev_services, '#__vikbooking_greview_service');
1660 ?>
1661 <div class="vbo-booking-guest-review">
1662 <div class="vbo-booking-guest-review-inner">
1663 <div class="vbo-booking-guest-review-top">
1664 <div class="vbo-booking-guest-review-time">
1665 <span><?php echo date(str_replace("/", $datesep, $df).' H:i', strtotime($review['dt'])); ?></span>
1666 </div>
1667 <div class="vbo-booking-guest-review-globalscore">
1668 <span><?php echo $review['score']; ?></span>
1669 </div>
1670 </div>
1671 <div class="vbo-booking-guest-review-bottom">
1672 <?php
1673 // scoring per service
1674 if (isset($review['content']['scoring']) && count($review['content']['scoring']) > 1) {
1675 // some services have been reviewed ("review_score" is always present)
1676 ?>
1677 <div class="vbo-booking-guest-review-services-score">
1678 <?php
1679 $counter = 0;
1680 foreach ($review['content']['scoring'] as $servicename => $servicescore) {
1681 if ($servicename == 'review_score') {
1682 // protected keyword for the global review score
1683 $counter++;
1684 continue;
1685 }
1686 $stars_count = floor($servicescore / 2);
1687 ?>
1688 <div class="vbo-booking-guest-review-service-score">
1689 <div class="vbo-booking-guest-review-service-score-inner">
1690 <div class="vbo-booking-guest-review-service-name">
1691 <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>
1692 </div>
1693 <div class="vbo-booking-guest-review-service-stars">
1694 <?php
1695 for ($i = 1; $i <= $stars_count; $i++) {
1696 VikBookingIcons::e('star', 'vbo-review-star vbo-review-star-full');
1697 }
1698 for ($i = ($stars_count + 1); $i <= 5; $i++) {
1699 VikBookingIcons::e('star', 'vbo-review-star');
1700 }
1701 ?>
1702 </div>
1703 </div>
1704 </div>
1705 <?php
1706 $counter++;
1707 }
1708 ?>
1709 </div>
1710 <?php
1711 } elseif (isset($review['content']['scoring']) && isset($review['content']['scoring']['review_score'])) {
1712 // this is a global score for no services
1713 $stars_count = floor($review['content']['scoring']['review_score'] / 2);
1714 ?>
1715 <div class="vbo-booking-guest-review-services-score vbo-booking-guest-review-singleservice">
1716 <div class="vbo-booking-guest-review-service-name">
1717 <span><?php echo JText::translate('VBOREVIEWYOURRATING'); ?></span>
1718 </div>
1719 <div class="vbo-booking-guest-review-service-stars">
1720 <?php
1721 for ($i = 1; $i <= $stars_count; $i++) {
1722 VikBookingIcons::e('star', 'vbo-review-star vbo-review-star-full');
1723 }
1724 for ($i = ($stars_count + 1); $i <= 5; $i++) {
1725 VikBookingIcons::e('star', 'vbo-review-star');
1726 }
1727 ?>
1728 </div>
1729 </div>
1730 <?php
1731 }
1732 // guest review message
1733 if (isset($review['content']['content']) && !empty($review['content']['content']['message'])) {
1734 ?>
1735 <div class="vbo-booking-guest-review-message">
1736 <p><?php echo nl2br($review['content']['content']['message']); ?></p>
1737 </div>
1738 <?php
1739 }
1740 // owner reply
1741 if (isset($review['content']['reply']) && ((is_string($review['content']['reply']) && !empty($review['content']['reply'])) || (is_array($review['content']['reply']) && !empty($review['content']['reply']['text'])))) {
1742 $reply_text = is_array($review['content']['reply']) && isset($review['content']['reply']['text']) ? $review['content']['reply']['text'] : $review['content']['reply'];
1743 ?>
1744 <div class="vbo-booking-guest-review-owner-reply">
1745 <h5><?php echo JText::translate('VBOGREVOWNREPLY'); ?></h5>
1746 <p><?php echo nl2br($reply_text); ?></p>
1747 </div>
1748 <?php
1749 }
1750 ?>
1751 </div>
1752 </div>
1753 </div>
1754 <?php
1755 }
1756
1757 /**
1758 * Upselling Options/Extras block.
1759 *
1760 * @since 1.13 (J) - 1.3.0 (WP)
1761 */
1762 $tot_upselling = count($this->upselling);
1763 if ($tot_upselling) {
1764 // at least one room has options that can be up-sold
1765 $formatparts = explode(':', VikBooking::getNumberFormatData());
1766 ?>
1767 <div class="vbo-hidein-print vbo-booking-upsell-container">
1768 <h3><?php echo JText::translate('VBOUPSELLTITLE'); ?></h3>
1769 <form method="post" action="<?php echo JRoute::rewrite('index.php?option=com_vikbooking&task=upsellextras' . (!empty($pitemid) ? '&Itemid='.$pitemid : '')); ?>">
1770 <div class="vbo-booking-upsell-inner <?php echo $tot_upselling > 1 ? 'vbo-booking-upsell-inner-multi' : 'vbo-booking-upsell-inner-single'; ?>">
1771 <?php
1772 foreach ($this->upselling as $kor => $uproom) {
1773 if (!isset($uproom->upsellable) || !count($uproom->upsellable)) {
1774 // no upsellable options for this room
1775 continue;
1776 }
1777 ?>
1778 <div class="vbo-booking-upsell-room-wrap">
1779 <?php
1780 if ($tot_upselling > 1) {
1781 // write the room name and adults/children in case of multiple rooms booked
1782 ?>
1783 <h5 class="vbo-booking-upsell-room-details">
1784 <span class="vbo-booking-upsell-room-name"><?php echo $uproom->name; ?></span>
1785 <span class="vbo-booking-upsell-room-adults"><?php echo $uproom->adults; ?> <?php echo ($uproom->adults == 1 ? JText::translate('VBSEARCHRESADULT') : JText::translate('VBSEARCHRESADULTS')); ?></span>
1786 <?php
1787 if ($orderrooms[$kor]['children'] > 0) {
1788 ?>
1789 <span class="vbo-booking-upsell-room-children"><?php echo $orderrooms[$kor]['children'] . " " . ($orderrooms[$kor]['children'] == 1 ? JText::translate('VBSEARCHRESCHILD') : JText::translate('VBSEARCHRESCHILDREN')); ?></span>
1790 <?php
1791 }
1792 ?>
1793 </h5>
1794 <?php
1795 }
1796 ?>
1797 <div class="vbo-upsell-options-wrap">
1798 <?php
1799 // determine proper nights of stay
1800 $room_stay_nights = $ord['days'];
1801 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $uproom->id) {
1802 $room_stay_nights = $room_stay_dates[$kor]['nights'];
1803 }
1804
1805 foreach ($uproom->upsellable as $o) {
1806 if ((int)$o['pcentroom']) {
1807 // make sure we have a cost for the room, or we should skip this type of option for "incomplete" bookings
1808 if (!isset($orderrooms[$kor]) || (empty($orderrooms[$kor]['cust_cost']) && empty($orderrooms[$kor]['room_cost']))) {
1809 continue;
1810 }
1811 $o['cost'] = ((!empty($orderrooms[$kor]['cust_cost']) ? $orderrooms[$kor]['cust_cost'] : $orderrooms[$kor]['room_cost']) * $o['cost'] / 100);
1812 }
1813 $optcost = intval($o['perday']) == 1 ? ($o['cost'] * $room_stay_nights) : $o['cost'];
1814 if (!empty($o['maxprice']) && $o['maxprice'] > 0 && $optcost > $o['maxprice']) {
1815 $optcost = $o['maxprice'];
1816 }
1817 if ($o['perperson'] == 1) {
1818 $optcost = $optcost * $orderrooms[$kor]['adults'];
1819 }
1820 $optcost = $optcost * 1;
1821
1822 /**
1823 * Trigger event to allow third party plugins to apply a custom calculation for the option/extra fee or tax.
1824 *
1825 * @since 1.17.7 (J) - 1.7.7 (WP)
1826 */
1827 $custom_calculation = VBOFactory::getPlatform()->getDispatcher()->filter('onCalculateBookingOptionFeeCost', [$optcost, &$o, $ord, $orderrooms[$kor]]);
1828 if ($custom_calculation) {
1829 $optcost = (float) $custom_calculation[0];
1830 }
1831
1832 $optquaninp = '';
1833 $optquanbtn = '';
1834 if (intval($o['hmany']) == 1) {
1835 if (intval($o['maxquant']) > 0) {
1836 $optquaninp = "<select id=\"vboaddextra-{$kor}-{$o['id']}\">\n";
1837 for ($ojj = 0; $ojj <= intval($o['maxquant']); $ojj++) {
1838 $optquaninp .= "<option value=\"" . $ojj . "\">" . $ojj . "</option>\n";
1839 }
1840 $optquaninp .= "</select>\n";
1841 } else {
1842 $optquaninp = "<input type=\"number\" min=\"0\" step=\"any\" id=\"vboaddextra-{$kor}-{$o['id']}\" value=\"0\" size=\"5\"/>";
1843 }
1844 $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>';
1845 } else {
1846 $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>';
1847 }
1848 ?>
1849 <div class="vbo-upsell-option-entry" id="vbo-option-upsell-<?php echo $kor . '-' . $o['id']; ?>">
1850 <?php
1851 if (!empty($o['img'])) {
1852 ?>
1853 <div class="vbo-upsell-option-entry-img">
1854 <?php echo '<img class="maxthirty" src="' . VBO_SITE_URI . 'resources/uploads/' . $o['img'] . '"/>'; ?>
1855 </div>
1856 <?php
1857 }
1858 ?>
1859 <div class="vbo-upsell-option-entry-name">
1860 <span><?php echo $o['name']; ?></span>
1861 <?php
1862 if (!empty($o['descr'])) {
1863 ?>
1864 <div class="vbo-upsell-option-entry-descr">
1865 <?php echo $o['descr']; ?>
1866 </div>
1867 <?php
1868 }
1869 $floatoptprice = VikBooking::sayOptionalsPlusIva($optcost, $o['idiva']);
1870 ?>
1871 </div>
1872 <div class="vbo-upsell-option-entry-cost" data-currency="<?php echo $currencysymb; ?>" data-floatprice="<?php echo (float)$floatoptprice; ?>">
1873 <?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($floatoptprice), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']); ?>
1874 </div>
1875 <div class="vbo-upsell-option-entry-input">
1876 <?php echo $optquaninp; ?>
1877 </div>
1878 <div class="vbo-option-upsell-add">
1879 <?php echo $optquanbtn; ?>
1880 </div>
1881 </div>
1882 <?php
1883 }
1884 ?>
1885 </div>
1886 <div class="vbo-room-upsell-cart" id="vbo-room-upsell-cart-<?php echo $kor; ?>"></div>
1887 </div>
1888 <?php
1889 }
1890 ?>
1891 </div>
1892 <input type="hidden" name="task" value="upsellextras">
1893 <input type="hidden" name="sid" value="<?php echo !empty($ord['idorderota']) && !empty($ord['channel']) ? $ord['idorderota'] : $ord['sid']; ?>">
1894 <input type="hidden" name="ts" value="<?php echo $ord['ts']; ?>">
1895 <div class="vbo-booking-upsell-confirm" style="display: none;">
1896 <div class="vbo-booking-upsell-confirm-inner">
1897 <div class="vbo-booking-upsell-confirm-total">
1898 <span class="vbo-booking-upsell-confirm-txt"><?php echo JText::translate('VBTOTAL'); ?></span>
1899 <span class="vbo_currency vbo-booking-upsell-confirm-currency"><?php echo $currencysymb; ?></span>
1900 <span class="vbo_price vbo-booking-upsell-confirm-amount"></span>
1901 </div>
1902 <div class="vbo-booking-upsell-confirm-btn">
1903 <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>
1904 </div>
1905 </div>
1906 </div>
1907 </form>
1908 </div>
1909
1910 <script type="text/javascript">
1911 var vbototextras = 0;
1912 function vboAddExtra(kor, optid, quant) {
1913 if (quant < 0) {
1914 // get the quantity from the input/select tag
1915 quant = jQuery('#vboaddextra-' + kor + '-' + optid).val();
1916 if (!quant || isNaN(quant)) {
1917 console.error('input not found', kor, optid, quant);
1918 return false;
1919 }
1920 if (quant < 1) {
1921 alert('<?php echo addslashes(JText::translate('VBOUPSELLQUANTOPT0')); ?>');
1922 return false;
1923 }
1924 }
1925 var cartelem = jQuery('#vbo-room-upsell-option-' + kor + '-' + optid);
1926 if (cartelem.length) {
1927 // remove element from cart if already existed for later appending it to the cart again
1928 vboRemoveExtra(kor, optid);
1929 }
1930 // add element to the cart
1931 var optelem = jQuery('#vbo-option-upsell-' + kor + '-' + optid);
1932 if (!optelem.length) {
1933 console.error('option not found', kor, optid);
1934 return false;
1935 }
1936 // price
1937 var optprice = parseFloat(optelem.find('.vbo-upsell-option-entry-cost').attr('data-floatprice')) * quant;
1938 //
1939 var newcartelem = '<div class="vbo-room-upsell-cart-option" id="vbo-room-upsell-option-' + kor + '-' + optid + '" data-floatprice="' + optprice + '">';
1940 newcartelem += '<div class="vbo-room-upsell-cart-option-name">' + optelem.find('.vbo-upsell-option-entry-name span').text() + (quant > 1 ? ' (x' + quant + ')' : '') + '</div>';
1941 if (quant < 2) {
1942 // single quantity can take the formatted option price
1943 newcartelem += '<div class="vbo-room-upsell-cart-option-cost">' + optelem.find('.vbo-upsell-option-entry-cost').html() + '</div>';
1944 } else {
1945 // multiple quantities should multiply the single raw cost not formatted
1946 var optcurrency = optelem.find('.vbo-upsell-option-entry-cost').attr('data-currency');
1947 if ('<?php echo VikBooking::getCurrencyPosition(); ?>' === 'after') {
1948 newcartelem += '<div class="vbo-room-upsell-cart-option-cost">' + optprice.toFixed(<?php echo (int)$formatparts[0]; ?>) + ' ' + optcurrency + '</div>';
1949 } else {
1950 newcartelem += '<div class="vbo-room-upsell-cart-option-cost">' + optcurrency + ' ' + optprice.toFixed(<?php echo (int)$formatparts[0]; ?>) + '</div>';
1951 }
1952 }
1953 // increase global total
1954 vbototextras += optprice;
1955 //
1956 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>';
1957 // the necessary input field that will be submitted with the form
1958 newcartelem += '<input type="hidden" name="addopt[' + kor + '][' + optid + ']" value="' + quant + '"/>';
1959 //
1960 newcartelem += '</div>';
1961 // append new element to the cart and make sure the full class is set
1962 jQuery('#vbo-room-upsell-cart-' + kor).append(newcartelem).addClass('vbo-room-upsell-cart-full');
1963 // highlight the option so that we can see it was reserved by adding a class to the container
1964 optelem.addClass('vbo-option-upsell-addedtocart');
1965 // display the save button
1966 jQuery('.vbo-booking-upsell-confirm').fadeIn();
1967 // refresh total
1968 vboRefreshTotal();
1969 }
1970 function vboRemoveExtra(kor, optid) {
1971 var cartelem = jQuery('#vbo-room-upsell-option-' + kor + '-' + optid);
1972 if (!cartelem.length) {
1973 console.error('could not find option to remove from the cart', kor, optid);
1974 return false;
1975 }
1976 // decrease global total
1977 vbototextras -= parseFloat(cartelem.attr('data-floatprice'));
1978 //
1979 cartelem.remove();
1980 // remove class that highlights that the option was reserved
1981 jQuery('#vbo-option-upsell-' + kor + '-' + optid).removeClass('vbo-option-upsell-addedtocart');
1982 // check if the cart for this room is no longer full
1983 if (!jQuery('#vbo-room-upsell-cart-' + kor).find('.vbo-room-upsell-cart-option').length) {
1984 jQuery('#vbo-room-upsell-cart-' + kor).removeClass('vbo-room-upsell-cart-full');
1985 }
1986 // hide the save button if no options in the cart
1987 if (!jQuery('.vbo-room-upsell-cart-option').length) {
1988 jQuery('.vbo-booking-upsell-confirm').fadeOut();
1989 }
1990 // refresh total
1991 vboRefreshTotal();
1992 }
1993 function vboRefreshTotal() {
1994 jQuery('.vbo-booking-upsell-confirm-amount').text(vbototextras.toFixed(<?php echo (int)$formatparts[0]; ?>));
1995 }
1996 </script>
1997 <?php
1998 }
1999
2000 /**
2001 * Render the chat with the front-end handler 'vikbooking'.
2002 * OTA bookings cannot be displayed in front-end so we cannot
2003 * use any other chat handler. Chat can be disabled from config.
2004 * Using the chat via front-end imposes the guest to be the sender.
2005 *
2006 * @since 1.12 (J) - 1.1.7 (WP)
2007 */
2008 $messaging = null;
2009 if (VikBooking::chatEnabled() > 0) {
2010 // -1 means that VCM is not enabled
2011 $chat_available = true;
2012 // check if chat can still be displayed to the guest
2013 $chat_params = VikBooking::getChatParams();
2014 if (!isset($chat_params->res_status) || !in_array($ord['status'], $chat_params->res_status)) {
2015 // chat is disabled for this reservation status
2016 $chat_available = false;
2017 }
2018 if (isset($chat_params->av_type) && isset($chat_params->av_days)) {
2019 // check days of validity after checkin or checkout
2020 $chat_lim_ts = $chat_params->av_type == 'checkin' ? strtotime("+{$chat_params->av_days} days", $ord['checkin']) : strtotime("+{$chat_params->av_days} days", $ord['checkout']);
2021 // compare limits at midnight
2022 $now_midnight = mktime(0, 0, 0, date('n'), date('j'), date('Y'));
2023 $lim_midnight = mktime(0, 0, 0, date('n', $chat_lim_ts), date('j', $chat_lim_ts), date('Y', $chat_lim_ts));
2024 if ($now_midnight > $lim_midnight) {
2025 // limit date is in the past
2026 $chat_available = false;
2027 }
2028 }
2029 if ($chat_available) {
2030 // attempt to get the class instance
2031 $messaging = VikBooking::getVcmChatInstance($ord['id'], 'vikbooking');
2032 }
2033 }
2034 if (!is_null($messaging)) {
2035 $tot_unread = VCMChatHandler::countUnreadMessages($ord['id']);
2036 ?>
2037 <div class="vbo-booking-chat-wrap vbo-booking-chat-closed">
2038 <div class="vbo-booking-chat-inner">
2039 <div class="vbo-booking-chat-control" data-message-count="<?php echo $tot_unread; ?>"><?php VikBookingIcons::e('commenting'); ?></div>
2040 <div class="vbo-booking-chat-container" style="display: none;">
2041 <h4 class="vbo-booking-chat-intro"><?php echo JText::sprintf('VBOCHATWITH', VikBooking::getFrontTitle()); ?></h4>
2042 <?php echo $messaging->renderChat(); ?>
2043 </div>
2044 </div>
2045 </div>
2046 <script type="text/javascript">
2047 jQuery(function() {
2048 jQuery('.vbo-booking-chat-control').click(function() {
2049 jQuery(this).remove();
2050 jQuery('.vbo-booking-chat-wrap').removeClass('vbo-booking-chat-closed');
2051 jQuery('.vbo-booking-chat-container').fadeIn(400, function() {
2052 // animate to that position
2053 jQuery('html,body').animate({scrollTop: jQuery('.vbo-booking-chat-container').offset().top - 20}, {duration: 400});
2054 if (typeof VCMChat !== 'undefined') {
2055 VCMChat.getInstance().scrollToBottom();
2056 }
2057 });
2058 });
2059 jQuery(window).on('chatsync', function(e) {
2060 // VCMChat event listener to update notifications badge for new messages
2061 var newNotifications = e.detail.notifications;
2062 var currentMessages = parseInt(jQuery('.vbo-booking-chat-control').attr('data-message-count'));
2063 jQuery('.vbo-booking-chat-control').attr('data-message-count', (newNotifications + currentMessages));
2064 });
2065 });
2066 </script>
2067 <?php
2068 }
2069
2070 /**
2071 * If necessary, move the payment form onto the selected position.
2072 *
2073 * @since 1.14 (J) - 1.4.0 (WP)
2074 * @since 1.17.6 (J) - 1.7.6 (WP) added support for damage deposit payment
2075 */
2076 if ((is_array($this->payment) && $this->payment['outposition'] != 'bottom') || (isset($dd_payment) && is_array($dd_payment) && $dd_payment['outposition'] != 'bottom')) {
2077 // move the payment window, if available
2078 $payment_position = isset($dd_payment) && is_array($dd_payment) && $dd_payment['outposition'] != 'bottom' ? $dd_payment['outposition'] : $this->payment['outposition'];
2079 ?>
2080 <script type="text/javascript">
2081
2082 VBOCore.DOMLoaded(() => {
2083
2084 setTimeout(() => {
2085 let payment_output = document.querySelectorAll('.vbvordpaybutton'),
2086 payment_notes = document.querySelectorAll('.vbvordpaynote'),
2087 payment_ctimer = document.querySelector('.vbo-timer-payment'),
2088 payment_wrappr = document.querySelector('.vbo-paycontainer-pos-<?php echo $payment_position; ?>');
2089
2090 if (payment_output.length && payment_wrappr) {
2091 // display final target
2092 payment_wrappr.style.display = '';
2093
2094 if (payment_notes.length) {
2095 payment_notes.forEach((payment_notes_block) => {
2096 // prepend notes first
2097 payment_wrappr.prepend(payment_notes_block);
2098 });
2099 }
2100
2101 if (payment_ctimer) {
2102 // prepend countdown timer first
2103 payment_wrappr.prepend(payment_ctimer);
2104 }
2105
2106 payment_output.forEach((payment_output_block) => {
2107 // append payment output
2108 payment_wrappr.append(payment_output_block);
2109 });
2110 }
2111 }, 50);
2112
2113 });
2114
2115 </script>
2116 <?php
2117 }
2118 //
2119