PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 All 36 releases
vikbooking / admin / views / editorder / tmpl / default.php

default.php in VikBooking Hotel Booking Engine & PMS trunk, at admin/views/editorder/tmpl/default.php

4,569 lines 192.8 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 $row = $this->row;
14 $rooms = $this->rooms;
15 $busy = $this->busy;
16 $customer = $this->customer;
17 $payments = $this->payments;
18
19 $history_obj = VikBooking::getBookingHistoryInstance($row['id']);
20
21 // availability helper
22 $av_helper = VikBooking::getAvailabilityInstance();
23
24 // load datepicker for all CMS compatibility
25 JHtml::fetch('stylesheet', VBO_SITE_URI.'resources/jquery-ui.min.css');
26 JHtml::fetch('jquery.framework', true, true);
27 JHtml::fetch('script', VBO_SITE_URI.'resources/jquery-ui.min.js');
28
29 // js lang def
30 JText::script('VBO_CONV_RES_OTA_CURRENCY_APPLY');
31 JText::script('VBDELCONFIRM');
32 JText::script('VBSENDCANCORDEMAIL');
33 JText::script('VBO_SET_STANDBY');
34 JText::script('VBO_CONF_RM_OVERBOOKING_FLAG');
35 JText::script('VBO_NEW_PAYSCHEDULE');
36 JText::script('VBANNULLA');
37 JText::script('VBOCLOSE');
38 JText::script('VBSAVE');
39 JText::script('VBELIMINA');
40 JText::script('VBO_REG_NEW_PAYMENT');
41 JText::script('VBO_UPDATE_PAYMENT');
42 JText::script('VBSENDSMSACTION');
43 JText::script('VBSENDEMAILACTION');
44 JText::script('VBO_AI_AUTO_GUEST_REV_EXCLUDE');
45 JText::script('VBO_AI_AUTO_GUEST_REV_INCLUDE');
46
47 $dbo = JFactory::getDbo();
48
49 $vbo_app = VikBooking::getVboApplication();
50 $vbo_app->loadVisualEditorAssets();
51 $vbo_app->prepareJavaScriptCurrency();
52
53 // preload chat assets
54 VBOFactory::getChatMediator()->useAssets();
55
56 /**
57 * This View can render within a modal the "bookingcheckin" View, and with WP
58 * this is loaded via AJAX. In order to not interfere or reset the contextual menu,
59 * we load the assets from the parent View. Context menu may also be used in this View.
60 *
61 * @since 1.16.0 (J) - 1.6.0 (WP)
62 */
63 $vbo_app->loadContextMenuAssets();
64 if (VBOPlatformDetection::isWordPress()) {
65 JText::script('VBRENTALORD');
66 JText::script('VBPVIEWORDERSPEOPLE');
67 }
68
69 $canDo = JFactory::getUser();
70 $vbo_auth_bookings = $canDo->authorise('core.vbo.bookings', 'com_vikbooking');
71
72 // check if automatic payment collection is enabled for all bookings
73 $automatic_payment_collection = VBOFactory::getConfig()->getBool('auto_payment_collection', false);
74
75 $booking_has_damage_dep = 0;
76 $current_ts = time();
77 $ota_type_data = !empty($row['ota_type_data']) ? ((array) json_decode($row['ota_type_data'], true)) : [];
78 $currencyname = VikBooking::getCurrencyName();
79 $currencysymb = VikBooking::getCurrencySymb();
80 $after_tax = VikBooking::ivaInclusa();
81 $nowdf = VikBooking::getDateFormat(true);
82 if ($nowdf == "%d/%m/%Y") {
83 $df = 'd/m/Y';
84 } elseif ($nowdf == "%m/%d/%Y") {
85 $df = 'm/d/Y';
86 } else {
87 $df = 'Y/m/d';
88 }
89 $datesep = VikBooking::getDateSeparator(true);
90 $vbo_modals_html = array();
91 $payment = VikBooking::getPayment($row['idpayment']);
92 $pactive_tab = VikRequest::getString('vbo_active_tab', 'vbo-tab-details', 'request');
93 $printreceipt = VikRequest::getInt('print', 0, 'request');
94 $printreceipt = ($printreceipt > 0);
95 if ($printreceipt) {
96 //we set a different page title when printing the receipt for the "PDF Printer" to give the file a good name.
97 JFactory::getDocument()->setTitle(VikBooking::getFrontTitle()." - ".JText::translate('VBOFISCRECEIPT')." #".$row['id']);
98 }
99 $gotouri = 'index.php?option=com_vikbooking&task=editorder&cid[]='.$row['id'];
100
101 if ($row['status'] == "confirmed") {
102 $use_js_bid = $row['id'];
103 JFactory::getDocument()->addScriptDeclaration(
104 <<<JS
105 window["vbo_current_bid"] = $use_js_bid;
106 JS
107 );
108 }
109
110 $tars = array();
111 $arrpeople = array();
112 $is_package = !empty($row['pkg']) ? true : false;
113 $is_cust_cost = false;
114 foreach ($rooms as $ind => $or) {
115 $num = $ind + 1;
116 $arrpeople[$num]['adults'] = $or['adults'];
117 $arrpeople[$num]['children'] = $or['children'];
118 $arrpeople[$num]['children_age'] = $or['childrenage'];
119 $arrpeople[$num]['t_first_name'] = $or['t_first_name'];
120 $arrpeople[$num]['t_last_name'] = $or['t_last_name'];
121 $arrpeople[$num]['pets'] = $or['pets'];
122 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
123 //package or custom cost set from the back-end
124 $is_cust_cost = true;
125 continue;
126 }
127 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `id`=".(int)$or['idtar'].";";
128 $dbo->setQuery($q);
129 $tar = $dbo->loadAssocList();
130 $tar = VikBooking::applySeasonsRoom($tar, $row['checkin'], $row['checkout']);
131
132 // apply OBP rules
133 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
134
135 $tars[$num] = $tar;
136 }
137 $pcheckin = $row['checkin'];
138 $pcheckout = $row['checkout'];
139 $secdiff = $pcheckout - $pcheckin;
140 $daysdiff = $secdiff / 86400;
141 if (is_int($daysdiff)) {
142 if ($daysdiff < 1) {
143 $daysdiff = 1;
144 }
145 } else {
146 if ($daysdiff < 1) {
147 $daysdiff = 1;
148 } else {
149 $sum = floor($daysdiff) * 86400;
150 $newdiff = $secdiff - $sum;
151 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
152 if ($maxhmore >= $newdiff) {
153 $daysdiff = floor($daysdiff);
154 } else {
155 $daysdiff = ceil($daysdiff);
156 }
157 }
158 }
159
160 $otachannel = '';
161 $otachannel_name = '';
162 $otachannel_bid = '';
163 $otacurrency = '';
164 if (!empty($row['channel'])) {
165 $channelparts = explode('_', $row['channel']);
166 $otachannel = array_key_exists(1, $channelparts) && strlen($channelparts[1]) > 0 ? $channelparts[1] : ucwords($channelparts[0]);
167 $otachannel_name = $otachannel;
168 $otachannel_bid = $otachannel.(!empty($row['idorderota']) ? ' - Booking ID: '.$row['idorderota'] : '');
169 if (strstr($otachannel, '.') !== false) {
170 $otaccparts = explode('.', $otachannel);
171 $otachannel = $otaccparts[0];
172 }
173 $otacurrency = strlen((string) $row['chcurrency']) > 0 ? $row['chcurrency'] : '';
174 }
175
176 /**
177 * Tell whether the current reservation has or may have a CC/VCC available.
178 */
179 $may_have_cc_details = false;
180 if (!empty($row['paymentlog']) && stripos($row['paymentlog'], 'card number') !== false && strpos($row['paymentlog'], '****') !== false) {
181 // turn flag on for partial card details available
182 $may_have_cc_details = true;
183 } elseif (!empty($row['channel']) && !strcasecmp($otachannel_name, 'Booking.com')) {
184 // the CM may be able to retrieve the CC details via API
185 $may_have_cc_details = true;
186 }
187
188 $status_type = '';
189 if (!empty($row['type'])) {
190 $status_type = JText::translate('VBO_BTYPE_' . strtoupper($row['type']));
191 if (!strcasecmp($row['type'], 'overbooking')) {
192 $status_type = '<span class="label label-error vbo-label-nested vbo-label-overbooking">' . $status_type . '</span>';
193 }
194 $status_type .= ' / ';
195 }
196 $extra_status = $row['refund'] > 0 ? ' / ' . JText::translate('VBO_STATUS_REFUNDED') : '';
197 if ($row['status'] == "confirmed") {
198 $saystaus = '<span class="label label-success">' . $status_type . JText::translate('VBCONFIRMED') . $extra_status . '</span>';
199 } elseif ($row['status'] == "standby") {
200 $saystaus = '<span class="label label-warning">' . $status_type . JText::translate('VBSTANDBY') . $extra_status . '</span>';
201 } else {
202 $saystaus = '<span class="label label-error">' . $status_type . JText::translate('VBCANCELLED') . $extra_status . '</span>';
203 }
204
205 // extend booking details main panel
206 $bookingPanelForms = $this->onDisplayView();
207
208 // extend booking details sidebar
209 $bookingSidebarForms = $this->onDisplayView('Sidebar');
210
211 // extend administration main panel
212 $adminFormsSetup = new stdClass;
213 $adminFormsSetup->icons = [];
214 $adminPanelForms = $this->onDisplayView('Administration', $adminFormsSetup);
215
216 // extend administration sidebar
217 $adminSidebarForms = $this->onDisplayView('AdministrationSidebar');
218
219 /**
220 * Check if messaging accounts have been configured through the E4jConnect Channel Manager.
221 * If some messaging API accounts have been configured, SMS fallback will no longer be displayed.
222 *
223 * @since 1.18.8 (J) - 1.8.8 (WP)
224 */
225 $messagingAccountConfigurations = [];
226 if (class_exists('VCMMessagingAccountsModel')) {
227 $registry = VBOBookingRegistry::getInstance($this->row, $this->rooms);
228 $messagingAccountConfigurations = VCMMessagingAccountsModel::getInstance()->getConfigurationsData(
229 new VCMMessagingTemplateDecoratorBooking($registry),
230 [
231 'listings' => $registry->getBookedListingIds(),
232 ]
233 );
234 }
235
236 //Prepare modal (used for the Registration and for reconstructing the credit card details through the channel manager)
237 echo $vbo_app->getJmodalScript();
238 //end Prepare modal
239 ?>
240 <script type="text/javascript">
241 function changePayment() {
242 var newpayment = document.getElementById('newpayment').value;
243 if (newpayment != '') {
244 var paymentname = document.getElementById('newpayment').options[document.getElementById('newpayment').selectedIndex].text;
245 if (confirm('<?php echo addslashes(JText::translate('VBCHANGEPAYCONFIRM')); ?>' + paymentname + '?')) {
246 document.adminForm.submit();
247 } else {
248 document.getElementById('newpayment').selectedIndex = 0;
249 }
250 }
251 }
252 function vbToggleLog(elem) {
253 vbToggleDynamicPanel(elem, '#vbpaymentlogdiv');
254 }
255 function vbToggleNotes(elem) {
256 vbToggleDynamicPanel(elem, '#vbadminnotesdiv');
257 }
258 function vbToggleHistory(elem) {
259 vbToggleDynamicPanel(elem, '#vbhistorydiv');
260 }
261 function vbToggleInvNotes(elem) {
262 vbToggleDynamicPanel(elem, '#vbinvnotesdiv');
263 }
264 function vbToggleMessaging(elem) {
265 vbToggleDynamicPanel(elem, '#vbmessagingdiv');
266 if (typeof VCMChat !== 'undefined') {
267 VCMChat.getInstance().scrollToBottom();
268 }
269 }
270 function vbToggleDynamicPanel(elem, target) {
271 if (jQuery(target).is(':visible')) {
272 return;
273 }
274
275 jQuery(".vbo-bookingdet-noteslogs-btn-active").removeClass("vbo-bookingdet-noteslogs-btn-active");
276
277 jQuery('.vbo-extra-panel').hide();
278 jQuery(target).show();
279
280 jQuery(elem).parent(".vbo-bookingdet-noteslogs-btn").addClass("vbo-bookingdet-noteslogs-btn-active");
281
282 if (typeof sessionStorage !== 'undefined') {
283 sessionStorage.setItem('vboEditOrderTab<?php echo $row['id']; ?>', jQuery(elem).parent().data('id'));
284 }
285 }
286 function toggleDiscount(elem) {
287 var discsp = document.getElementById('vbdiscenter').style.display;
288 if (discsp == 'block') {
289 document.getElementById('vbdiscenter').style.display = 'none';
290 jQuery(elem).find('i').attr('class', '<?php echo VikBookingIcons::i('chevron-down'); ?>');
291 } else {
292 document.getElementById('vbdiscenter').style.display = 'block';
293 jQuery(elem).find('i').attr('class', '<?php echo VikBookingIcons::i('chevron-up'); ?>');
294 }
295 }
296 </script>
297
298 <div class="vbo-bookingdet-topcontainer">
299 <form name="adminForm" id="adminForm" action="<?php echo VBOPlatformDetection::isWordPress() ? 'admin.php' : 'index.php'; ?>?option=com_vikbooking&amp;task=editorder&amp;cid[]=<?php echo $row['id']; ?>" method="post">
300 <?php
301 if ($printreceipt) {
302 //print the company details
303 $companylogo = VikBooking::getSiteLogo();
304 $next_receipt = VikBooking::getNextReceiptNumber($row['id']);
305 ?>
306 <div class="vbo-receipt-company-block-outer">
307 <div class="vbo-receipt-company-block">
308 <?php
309 if (!empty($companylogo)) {
310 ?>
311 <div class="vbo-receipt-company-logo"><img src="<?php echo VBO_ADMIN_URI.'resources/'.$companylogo; ?>" /></div>
312 <?php
313 }
314 ?>
315 <div class="vbo-receipt-company-info"><?php echo VikBooking::getInvoiceCompanyInfo(); ?></div>
316 </div>
317 <div class="vbo-receipt-numdate-block">
318 <div class="vbo-receipt-numdate-inner">
319 <div class="vbo-receipt-numdate-title">
320 <span><?php echo JText::translate('VBOFISCRECEIPT'); ?></span>
321 <span style="float: right; cursor: pointer; color: #ff0000;" onclick="vboMakePrintOnly();"><?php VikBookingIcons::e('times-circle'); ?></span>
322 </div>
323 <div class="vbo-receipt-numdate-num">
324 <span class="vbo-receipt-numdate-num-lbl"><?php echo JText::translate('VBOFISCRECEIPTNUM'); ?></span>
325 <span class="vbo-receipt-numdate-num-val">
326 <span class="vbo-showin-print" id="vbo-receipt-num"><?php echo $next_receipt; ?></span>
327 <input class="vbo-hidein-print" id="vbo-receipt-num-inp" type="number" min="0" value="<?php echo $next_receipt; ?>" onchange="document.getElementById('vbo-receipt-num').innerText = this.value;" />
328 </span>
329 </div>
330 <div class="vbo-receipt-numdate-date">
331 <span class="vbo-receipt-numdate-date-lbl"><?php echo JText::translate('VBOFISCRECEIPTDATE'); ?></span>
332 <span class="vbo-receipt-numdate-date-val"><?php echo date(str_replace("/", $datesep, $df)); ?></span>
333 </div>
334 </div>
335 </div>
336 <div class="vbo-receipt-print-confirm vbo-hidein-print">
337 <div class="vbo-receipt-print-btn">
338 <span onclick="vboLaunchPrintReceipt();">
339 <?php VikBookingIcons::e('print'); ?>
340 <span id="vbo-receipt-print-btn-name"><?php echo JText::translate('VBOPRINTRECEIPT'); ?></span>
341 </span>
342 </div>
343 </div>
344 </div>
345 <?php
346 }
347 ?>
348
349 <div class="vbo-bookdet-container">
350 <div class="vbo-bookdet-wrap">
351 <div class="vbo-bookdet-head">
352 <span>ID</span>
353 </div>
354 <div class="vbo-bookdet-foot">
355 <span><?php echo $row['id']; ?></span>
356 </div>
357 </div>
358 <div class="vbo-bookdet-wrap">
359 <div class="vbo-bookdet-head">
360 <span><?php echo JText::translate('VBEDITORDERONE'); ?></span>
361 </div>
362 <div class="vbo-bookdet-foot">
363 <span><?php echo date(str_replace("/", $datesep, $df).' H:i', $row['ts']); ?></span>
364 </div>
365 </div>
366 <?php
367 if (!$printreceipt && $customer) {
368 ?>
369 <div class="vbo-bookdet-wrap">
370 <div class="vbo-bookdet-head">
371 <span><?php echo JText::translate('VBCUSTOMERNOMINATIVE'); ?></span>
372 </div>
373 <div class="vbo-bookdet-foot">
374 <div class="vbo-customer-info-box">
375 <div class="vbo-customer-info-box-name">
376 <?php echo (isset($customer['country_img']) ? $customer['country_img'] . ' ' : ''); ?>
377
378 <?php if ($canDo->authorise('core.edit', 'com_vikbooking') && $canDo->authorise('core.vbo.management', 'com_vikbooking')): ?>
379 <a href="index.php?option=com_vikbooking&task=editcustomer&cid[]=<?php echo $customer['id']; ?>&goto=<?php echo base64_encode($gotouri); ?>"><?php echo ltrim($customer['first_name'] . ' ' . $customer['last_name']); ?></a>
380 <?php else: ?>
381 <?php echo ltrim($customer['first_name'] . ' ' . $customer['last_name']); ?>
382 <?php endif; ?>
383 </div>
384 <?php
385 if (!empty($customer['pic'])) {
386 $avatar_caption = ltrim($customer['first_name'] . ' ' . $customer['last_name']);
387 ?>
388 <div class="vbo-customer-info-box-avatar vbo-customer-avatar-small">
389 <span>
390 <img src="<?php echo strpos($customer['pic'], 'http') === 0 ? $customer['pic'] : VBO_SITE_URI . 'resources/uploads/' . $customer['pic']; ?>" data-caption="<?php echo htmlspecialchars($avatar_caption); ?>" />
391 </span>
392 </div>
393 <?php
394 }
395 ?>
396 </div>
397 </div>
398 </div>
399 <?php
400 }
401 if (!$printreceipt) {
402 ?>
403 <div class="vbo-bookdet-wrap">
404 <div class="vbo-bookdet-head">
405 <span><?php echo JText::translate('VBEDITORDERROOMSNUM'); ?></span>
406 </div>
407 <div class="vbo-bookdet-foot">
408 <?php echo $row['roomsnum']; ?>
409 </div>
410 </div>
411 <?php
412 }
413 ?>
414 <div class="vbo-bookdet-wrap">
415 <div class="vbo-bookdet-head">
416 <span><?php echo JText::translate('VBEDITORDERFOUR'); ?></span>
417 </div>
418 <div class="vbo-bookdet-foot">
419 <span><?php echo $row['days']; ?></span>
420 <?php
421 if ($row['split_stay']) {
422 ?>
423 <span class="hasTooltip" title="<?php echo JHtml::fetch('esc_attr', JText::translate('VBO_SPLIT_STAY')); ?>"><?php VikBookingIcons::e('random'); ?></span>
424 <?php
425 }
426 ?>
427 </div>
428 </div>
429 <div class="vbo-bookdet-wrap">
430 <div class="vbo-bookdet-head">
431 <span><?php echo JText::translate('VBEDITORDERFIVE'); ?></span>
432 </div>
433 <div class="vbo-bookdet-foot">
434 <?php
435 $checkin_info = getdate($row['checkin']);
436 $short_wday = JText::translate('VB'.strtoupper(substr($checkin_info['weekday'], 0, 3)));
437 ?>
438 <?php echo $short_wday.', '.date(str_replace("/", $datesep, $df).' H:i', $row['checkin']); ?>
439 </div>
440 </div>
441 <div class="vbo-bookdet-wrap">
442 <div class="vbo-bookdet-head">
443 <span><?php echo JText::translate('VBEDITORDERSIX'); ?></span>
444 </div>
445 <div class="vbo-bookdet-foot">
446 <?php
447 $checkout_info = getdate($row['checkout']);
448 $short_wday = JText::translate('VB'.strtoupper(substr($checkout_info['weekday'], 0, 3)));
449 ?>
450 <?php echo $short_wday.', '.date(str_replace("/", $datesep, $df).' H:i', $row['checkout']); ?>
451 </div>
452 </div>
453 <?php
454 if (!$printreceipt && $vbo_auth_bookings && $row['closure'] != 1 && $row['status'] == 'confirmed') {
455 // we don't need to check in the IF above "&& $row['checked'] != 0" because the registration is useful for all bookings.
456 $checked_btn = 'btn-primary';
457 switch ($row['checked']) {
458 case -1:
459 $checked_status = JText::translate('VBOCHECKEDSTATUSNOS');
460 $checked_btn = 'btn-danger';
461 break;
462 case 1:
463 $checked_status = JText::translate('VBOCHECKEDSTATUSIN');
464 $checked_btn = 'btn-success';
465 break;
466 case 2:
467 $checked_status = JText::translate('VBOCHECKEDSTATUSOUT');
468 $checked_btn = 'btn-warning';
469 break;
470 default:
471 $checked_status = JText::translate('VBOCHECKEDSTATUSZERO');
472 if ($customer && isset($customer['pax_data']) && !empty($customer['pax_data'])) {
473 // pre check-in performed via front-end
474 $checked_status = JText::translate('VBOCHECKEDSTATUSPRECHECKIN');
475 }
476 break;
477 }
478 ?>
479 <div class="vbo-bookdet-wrap pro-feature">
480 <div class="vbo-bookdet-head">
481 <span><?php echo JText::translate('VBOCHECKEDSTATUS'); ?></span>
482 </div>
483 <div class="vbo-bookdet-foot">
484 <button type="button" class="btn btn-small <?php echo $checked_btn; ?>" onclick="vboOpenJModal('vbo-checkin-booking', 'index.php?option=com_vikbooking&task=bookingcheckin&cid[]=<?php echo $row['id']; ?>&tmpl=component');">
485 <?php echo $checked_status; ?>
486 </button>
487 </div>
488 </div>
489 <?php
490 //Prepare modal (Registration)
491 array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-checkin-booking', JText::translate('VBOMANAGECHECKSINOUT')));
492 //end Prepare modal
493 }
494
495 /**
496 * Check whether the booking can be refunded or charged through an off-session capturing.
497 *
498 * @since 1.14 (J) - 1.4.0 (WP)
499 * @since 1.18.0 (J) - 1.8.0 (WP) added support to off-session capturing.
500 */
501
502 // refundable/capturable up to 7 days after check-out day
503 $max_refund_ts = mktime(23, 59, 59, $checkout_info['mon'], ($checkout_info['mday'] + 7), $checkout_info['year']);
504
505 // current payment driver must be set
506 $tn_driver = is_array($payment) ? $payment['file'] : null;
507
508 // transaction data validation callback
509 $tn_data_callback = function($data) use ($tn_driver) {
510 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
511 };
512 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
513
514 // whether it's refundable/capturable
515 $refundable = ($row['status'] != 'standby' && !empty($row['totpaid']) && $max_refund_ts >= $current_ts && is_array($prev_tn_data) && $prev_tn_data);
516 $off_session_capturing = ($row['status'] != 'standby' && $max_refund_ts >= $current_ts && is_array($prev_tn_data) && array_filter($prev_tn_data, function($data) {
517 return is_object($data) && ($data->future_usage ?? null);
518 }));
519
520 if ($off_session_capturing) {
521 ?>
522 <div class="vbo-bookdet-wrap">
523 <div class="vbo-bookdet-head">
524 <span><?php echo JText::translate('VBO_CREDIT_CARD'); ?></span>
525 </div>
526 <div class="vbo-bookdet-foot">
527 <button type="button" class="btn btn-small vbo-config-btn vbo-offsessioncapture-btn" onclick="VBOCore.handleDisplayWidgetNotification({widget_id: 'virtual_terminal'}, {bid: <?php echo $row['id']; ?>});">
528 <?php VikBookingIcons::e('credit-card'); ?>
529 <?php echo JText::translate('VBO_W_VIRTUALTERMINAL_TITLE'); ?>
530 </button>
531 </div>
532 </div>
533 <?php
534 }
535
536 if ($refundable) {
537 // prepare modal (refundtn) with a custom function to trigger the opening
538 array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-refund-tn', JText::translate('VBO_ISSUE_REFUND')));
539 echo $vbo_app->getJmodalScript('Refund', 'vboDetectRefundChanges();');
540 // count the number of refunds made
541 $refunds = $history_obj->getEventsWithData('RF', null, false);
542 $refunds = !is_array($refunds) ? array() : $refunds;
543 ?>
544 <script type="text/javascript">
545 var vbo_refund_performed = false;
546 function vboDetectRefundChanges() {
547 if (vbo_refund_performed === true) {
548 location.reload();
549 }
550 }
551 </script>
552
553 <div class="vbo-bookdet-wrap">
554 <div class="vbo-bookdet-head">
555 <span><?php echo JText::translate('VBO_ISSUE_REFUND'); ?></span>
556 </div>
557 <div class="vbo-bookdet-foot">
558 <button type="button" class="btn btn-small btn-danger vbo-dorefund-btn"<?php echo $refunds ? ' data-totrefunds="' . count($refunds) . '"' : ''; ?> onclick="vboOpenJModalRefund('vbo-refund-tn', 'index.php?option=com_vikbooking&task=refundtn&cid[]=<?php echo $row['id']; ?>&tmpl=component');">
559 <?php echo JText::translate('VBO_REFUND'); ?>
560 </button>
561 </div>
562 </div>
563 <?php
564 }
565
566 if (!$printreceipt && !empty($row['channel'])) {
567 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
568 if ($ota_logo_img === false) {
569 $ota_logo_img = $otachannel_name;
570 } else {
571 $ota_logo_img = '<img src="'.$ota_logo_img.'" class="vbo-channelimg-medium"/>';
572 }
573 ?>
574 <div class="vbo-bookdet-wrap">
575 <div class="vbo-bookdet-head">
576 <span><?php echo JText::translate('VBPVIEWORDERCHANNEL'); ?></span>
577 </div>
578 <div class="vbo-bookdet-foot">
579 <span><?php echo $ota_logo_img; ?></span>
580 </div>
581 </div>
582 <?php
583 } elseif (!$printreceipt && class_exists('VCMOtaBooking')) {
584 /**
585 * Vik Channel Manager booking assignable channels.
586 *
587 * @since 1.16.3 (J) - 1.6.3 (WP)
588 */
589 $assignable_channels = VCMOtaBooking::getInstance($row, true)->getChannelsAssignable();
590 if ($assignable_channels) {
591 JText::script('VBO_ASSIGN_BOOKING_TO_OTA_CONFIRM');
592 JFactory::getDocument()->addScriptDeclaration(
593 <<<JS
594 function vboConfirmAssignChannel(ch_key, ch_name) {
595 if (!ch_key || !ch_name) {
596 return true;
597 }
598 if (confirm(Joomla.JText._('VBO_ASSIGN_BOOKING_TO_OTA_CONFIRM').replace('%s', ch_name))) {
599 document.adminForm.submit();
600 return true;
601 } else {
602 return false;
603 }
604 }
605 JS
606 );
607 ?>
608 <div class="vbo-bookdet-wrap">
609 <div class="vbo-bookdet-head">
610 <span><?php echo JText::translate('VBPVIEWORDERCHANNEL'); ?></span>
611 </div>
612 <div class="vbo-bookdet-foot">
613 <select name="vcm_assign_channel" class="vbo-select-small" onchange="return vboConfirmAssignChannel(this.value, this.options[this.selectedIndex].text);">
614 <option value=""><?php echo JText::translate('VBORDFROMSITE'); ?></option>
615 <?php
616 foreach ($assignable_channels as $assign_ch_key => $assign_ch_name) {
617 ?>
618 <option value="<?php echo JHtml::fetch('esc_attr', $assign_ch_key); ?>"><?php echo $assign_ch_name; ?></option>
619 <?php
620 }
621 ?>
622 </select>
623 </div>
624 </div>
625 <?php
626 }
627 }
628 if (!$printreceipt) {
629 ?>
630 <div class="vbo-bookdet-wrap">
631 <div class="vbo-bookdet-head">
632 <span><?php echo JText::translate('VBSTATUS'); ?></span>
633 </div>
634 <div class="vbo-bookdet-foot">
635 <span><?php echo $saystaus; ?></span>
636 </div>
637 </div>
638 <?php
639 if (is_array($this->vcm_pre_approval)) {
640 ?>
641 <div class="vbo-bookdet-wrap">
642 <div class="vbo-bookdet-head">
643 <span><?php echo $this->vcm_pre_approval[1]; ?></span>
644 </div>
645 <div class="vbo-bookdet-foot">
646 <span>
647 <?php
648 if (empty($this->vcm_pre_approval[2]) || !empty($this->vcm_pre_approval[3])) {
649 // no pre-approvals before, or withdrawn before
650 ?>
651 <a href="index.php?option=com_vikchannelmanager&task=sendSpecialOffer&vbo_oid=<?php echo $row['id']; ?>&spo_type=preapproval&spo_action=send&ota_thread_id=<?php echo $this->vcm_pre_approval[0]; ?>" class="btn btn-small btn-primary vcm-btn-channel-<?php echo strtolower($this->vcm_pre_approval[1]); ?>"><?php VikBookingIcons::e('thumbs-up'); ?> <?php echo JText::translate('VBO_PREAPPROVE_INQUIRY'); ?></a>
652 <?php
653 } else {
654 // pre-approved before, pass the ID
655 ?>
656 <a href="index.php?option=com_vikchannelmanager&task=sendSpecialOffer&vbo_oid=<?php echo $row['id']; ?>&spo_type=preapproval&spo_action=withdraw&ota_thread_id=<?php echo $this->vcm_pre_approval[0]; ?>&spo_id=<?php echo $this->vcm_pre_approval[2]; ?>" class="btn btn-small btn-danger"><?php VikBookingIcons::e('thumbs-down'); ?> <?php echo JText::translate('VBO_WITHDRAW_PREAPPROVAL'); ?></a>
657 <?php
658 }
659 ?>
660 </span>
661 </div>
662 </div>
663 <?php
664 }
665 if (!empty($row['channel']) && stripos($row['channel'], 'booking.com') !== false && $row['checkin'] <= $current_ts && strtotime('+ 7 days', $row['checkout']) >= $current_ts) {
666 /**
667 * Guest misconduct reporting API for Booking.com.
668 * Only after reservation check-in date and no later than 7 days after check-out date.
669 *
670 * @since 1.13.5 - VCM 1.7.2
671 */
672 $misconduct_reported = $history_obj->hasEvent('GM');
673 ?>
674 <div class="vbo-bookdet-wrap">
675 <div class="vbo-bookdet-head">
676 <span><?php echo JText::translate('VBOGUESTMISCONDUCT'); ?></span>
677 </div>
678 <div class="vbo-bookdet-foot">
679 <?php
680 if ($misconduct_reported === false) {
681 // allow to report the guest misconduct
682 ?>
683 <button type="button" class="btn btn-small btn-danger" onclick="vboRenderGuestMisconduct();"><?php VikBookingIcons::e('user-slash'); ?> <?php echo JText::translate('VBOREPORTMISCONDUCT'); ?></button>
684 <?php
685 } else {
686 // guest misconduct already reported
687 ?>
688 <button type="button" class="btn btn-small btn-warning" onclick="vboShowGuestMisconductReported();"><?php VikBookingIcons::e('user-slash'); ?> <?php echo $misconduct_reported; ?></button>
689 <?php
690 }
691 ?>
692 <a id="vbo-gm-reloadlink" style="display: none;" href="index.php?option=com_vikbooking&task=editorder&cid[]=<?php echo $row['id']; ?>"></a>
693 </div>
694
695 <div class="vbo-modal-overlay-block vbo-modal-overlay-block-guestmisconduct">
696 <a class="vbo-modal-overlay-close" href="javascript: void(0);"></a>
697 <div class="vbo-modal-overlay-content vbo-modal-overlay-content-guestmisconduct">
698 <div class="vbo-modal-overlay-content-head vbo-modal-overlay-content-head-guestmisconduct">
699 <h3><?php VikBookingIcons::e('exclamation-circle'); ?> <?php echo JText::sprintf('VBOREPGUESTMISCONDUCTTO', 'Booking.com'); ?> <span class="vbo-modal-overlay-close-times" onclick="hideVboDialogGuestMisconduct();">&times;</span></h3>
700 </div>
701 <div class="vbo-modal-overlay-content-body">
702 <div class="vbo-modal-guestmisconduct-addnew" data-bid="<?php echo $row['id']; ?>" data-otabid="<?php echo $row['idorderota']; ?>">
703 <div class="vbo-modal-guestmisconduct-report-elems"></div>
704 <div class="vbo-modal-guestmisconduct-addnew-save">
705 <button type="button" id="vbo-guest-misconduct-submit-btn" class="btn btn-success" onclick="vboSubmitGuestMisconduct();" style="display: none;"><?php echo JText::translate('VBCHANNELMANAGERSENDRQ'); ?></button>
706 <button type="button" class="btn btn-secondary" onclick="hideVboDialogGuestMisconduct();"><?php echo JText::translate('VBOCLOSE'); ?></button>
707 </div>
708 </div>
709 </div>
710 </div>
711 </div>
712
713 <script type="text/javascript">
714 var vbodialogguestmisconduct_on = false;
715 var vbo_guest_misconduct_fields = new Array;
716
717 function vboShowGuestMisconductReported() {
718 // this is like simulating the navigation to the booking history tab
719 jQuery(".vbo-bookingdet-tab[data-vbotab='vbo-tab-admin']").trigger('click');
720 vbToggleHistory(document.getElementById('vbo-trig-bookhistory'));
721 }
722
723 function vboRenderGuestMisconduct() {
724 // empty content
725 jQuery('.vbo-modal-guestmisconduct-report-elems').html('<?php echo $this->escape(JText::translate('VIKLOADING') . '...'); ?>');
726 vbo_guest_misconduct_fields = new Array;
727
728 // display modal
729 jQuery('.vbo-modal-overlay-block-guestmisconduct').fadeIn();
730 vbodialogguestmisconduct_on = true;
731
732 // make AJAX request to VCM to always reload the form fields
733 VBOCore.doAjax(
734 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikchannelmanager&task=get_bcom_misconduct_categories'); ?>",
735 {
736 tmpl: "component"
737 },
738 (res) => {
739 // parse the JSON response that contains the categories object with all fields for the reporting
740 try {
741 var misconduct_fields_rs = typeof res === 'string' ? JSON.parse(res) : res;
742
743 // make sure the request was successful
744 if (!misconduct_fields_rs.status) {
745 alert(misconduct_fields_rs.error);
746 hideVboDialogGuestMisconduct();
747 return false;
748 }
749
750 // render form from response obtained
751 var misconduct_html = '';
752 var misconduct_fields = misconduct_fields_rs.data;
753 if (!misconduct_fields.hasOwnProperty('categories') || !misconduct_fields.hasOwnProperty('fields')) {
754 alert('Unexptected response. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
755 hideVboDialogGuestMisconduct();
756 return false;
757 }
758
759 // main category of misconduct
760 misconduct_html += '<div class="vbo-modal-form-addnew-elem vbo-modal-guestmisconduct-addnew-elem">' + "\n";
761 misconduct_html += '<label for="vbo-gm-category">' + misconduct_fields['labels']['category'] + '</label>';
762 misconduct_html += '<select id="vbo-gm-category" data-gmname="category_id" onchange="vboGuestMisconductChangeCategory(this.value);">' + "\n";
763 for (var category in misconduct_fields['categories']) {
764 if (!misconduct_fields['categories'].hasOwnProperty(category)) {
765 continue;
766 }
767 misconduct_html += '<option value="' + misconduct_fields['categories'][category]['id'] + '">' + misconduct_fields['categories'][category]['title'] + '</option>' + "\n";
768 }
769 misconduct_html += '</select>' + "\n";
770 misconduct_html += '</div>' + "\n";
771 // push category field in fields list for later submit
772 vbo_guest_misconduct_fields.push('vbo-gm-category');
773
774 // sub-categories or additional fields of misconduct categories
775 for (var category in misconduct_fields['categories']) {
776 if (!misconduct_fields['categories'].hasOwnProperty(category)) {
777 continue;
778 }
779 if (!misconduct_fields['categories'][category].hasOwnProperty('subcategories') && !misconduct_fields['categories'][category].hasOwnProperty('additional_fields')) {
780 // at least one of these two properties must be set
781 continue;
782 }
783 if (misconduct_fields['categories'][category].hasOwnProperty('subcategories') && misconduct_fields['categories'][category]['subcategories'].length) {
784 // sub-categories in drop down
785 var subcat_field_id = 'vbo-gm-subcategory' + misconduct_fields['categories'][category]['id'];
786 misconduct_html += '<div class="vbo-modal-form-addnew-elem vbo-modal-guestmisconduct-addnew-elem vbo-modal-guestmisconduct-addnew-cond" data-gmcid="' + misconduct_fields['categories'][category]['id'] + '" style="display: none;">' + "\n";
787 misconduct_html += '<label for="' + subcat_field_id + '">' + misconduct_fields['labels']['subcategory'] + '</label>';
788 misconduct_html += '<select id="' + subcat_field_id + '" data-gmname="subcategory_id">' + "\n";
789 for (var subcategory in misconduct_fields['categories'][category]['subcategories']) {
790 if (!misconduct_fields['categories'][category]['subcategories'].hasOwnProperty(subcategory)) {
791 continue;
792 }
793 misconduct_html += '<option value="' + misconduct_fields['categories'][category]['subcategories'][subcategory]['id'] + '">' + misconduct_fields['categories'][category]['subcategories'][subcategory]['title'] + '</option>' + "\n";
794 }
795 misconduct_html += '</select>' + "\n";
796 misconduct_html += '</div>' + "\n";
797 // push sub-category field in fields list for later submit
798 if (vbo_guest_misconduct_fields.indexOf(subcat_field_id) < 0) {
799 vbo_guest_misconduct_fields.push(subcat_field_id);
800 }
801 } else if (misconduct_fields['categories'][category].hasOwnProperty('additional_fields') && misconduct_fields['categories'][category]['additional_fields'].length) {
802 // additional fields
803 for (var extra_field in misconduct_fields['categories'][category]['additional_fields']) {
804 if (!misconduct_fields['categories'][category]['additional_fields'].hasOwnProperty(extra_field)) {
805 continue;
806 }
807 var field_id = 'vbo-gm-extrafield-' + misconduct_fields['categories'][category]['additional_fields'][extra_field]['name'];
808 var field_name = misconduct_fields['categories'][category]['additional_fields'][extra_field]['name'];
809 misconduct_html += '<div class="vbo-modal-form-addnew-elem vbo-modal-guestmisconduct-addnew-elem vbo-modal-guestmisconduct-addnew-cond" data-gmcid="' + misconduct_fields['categories'][category]['id'] + '" style="display: none;">' + "\n";
810 misconduct_html += '<label for="' + field_id + '">' + misconduct_fields['categories'][category]['additional_fields'][extra_field]['label'] + '</label>';
811 if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'number') {
812 misconduct_html += '<input data-gmname="' + field_name + '" type="number" id="' + field_id + '" value="" step="any" min="0" />';
813 } else if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'text') {
814 misconduct_html += '<input data-gmname="' + field_name + '" type="text" id="' + field_id + '" value="" />';
815 } else if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'text') {
816 misconduct_html += '<input data-gmname="' + field_name + '" type="text" id="' + field_id + '" value="" />';
817 } else if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'textarea') {
818 misconduct_html += '<textarea data-gmname="' + field_name + '" id="' + field_id + '" rows="5" cols="50" maxlength="240"></textarea>';
819 } else if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'select') {
820 misconduct_html += '<select data-gmname="' + field_name + '" id="' + field_id + '">';
821 for (var choicekey in misconduct_fields['categories'][category]['additional_fields'][extra_field]['choices']) {
822 // this is either an array when keys are numeric from 0, or an object when keys start from like 1, but with choicekey we take the proper key in the object
823 if (!misconduct_fields['categories'][category]['additional_fields'][extra_field]['choices'].hasOwnProperty(choicekey)) {
824 continue;
825 }
826 misconduct_html += '<option value="' + choicekey + '">' + misconduct_fields['categories'][category]['additional_fields'][extra_field]['choices'][choicekey] + '</option>';
827 }
828 misconduct_html += '</select>';
829 }
830 misconduct_html += '</div>' + "\n";
831 // push additional field in fields list for later submit
832 vbo_guest_misconduct_fields.push(field_id);
833 }
834 }
835 }
836
837 // mandatory fields for all categories of guest misconduct reporting
838 for (var mandfield in misconduct_fields['fields']) {
839 if (!misconduct_fields['fields'].hasOwnProperty(mandfield)) {
840 continue;
841 }
842 var field_id = 'vbo-gm-mandfield-' + misconduct_fields['fields'][mandfield]['name'];
843 var field_name = misconduct_fields['fields'][mandfield]['name'];
844 misconduct_html += '<div class="vbo-modal-form-addnew-elem vbo-modal-guestmisconduct-addnew-elem">' + "\n";
845 misconduct_html += '<label for="' + field_id + '">' + misconduct_fields['fields'][mandfield]['label'] + '</label>';
846 if (misconduct_fields['fields'][mandfield]['type'] == 'number') {
847 misconduct_html += '<input data-gmname="' + field_name + '" type="number" id="' + field_id + '" value="" step="any" min="0" />';
848 } else if (misconduct_fields['fields'][mandfield]['type'] == 'text') {
849 misconduct_html += '<input data-gmname="' + field_name + '" type="text" id="' + field_id + '" value="" />';
850 } else if (misconduct_fields['fields'][mandfield]['type'] == 'text') {
851 misconduct_html += '<input data-gmname="' + field_name + '" type="text" id="' + field_id + '" value="" />';
852 } else if (misconduct_fields['fields'][mandfield]['type'] == 'textarea') {
853 misconduct_html += '<textarea data-gmname="' + field_name + '" id="' + field_id + '" rows="5" cols="50" maxlength="240"></textarea>';
854 } else if (misconduct_fields['fields'][mandfield]['type'] == 'select') {
855 misconduct_html += '<select data-gmname="' + field_name + '" id="' + field_id + '">';
856 for (var choicekey in misconduct_fields['fields'][mandfield]['choices']) {
857 if (!misconduct_fields['fields'][mandfield]['choices'].hasOwnProperty(choicekey)) {
858 continue;
859 }
860 misconduct_html += '<option value="' + choicekey + '">' + misconduct_fields['fields'][mandfield]['choices'][choicekey] + '</option>';
861 }
862 misconduct_html += '</select>';
863 }
864 misconduct_html += '</div>' + "\n";
865 // push mandatory field in fields list for later submit
866 vbo_guest_misconduct_fields.push(field_id);
867 }
868
869 // display HTML content and submit button
870 jQuery('.vbo-modal-guestmisconduct-report-elems').html(misconduct_html);
871 jQuery('#vbo-guest-misconduct-submit-btn').show();
872 // trigger change of main category drop down
873 jQuery('#vbo-gm-category').trigger('change');
874 } catch (e) {
875 console.log(res);
876 alert('Invalid response. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
877 hideVboDialogGuestMisconduct();
878 return false;
879 }
880 },
881 (err) => {
882 hideVboDialogGuestMisconduct();
883 alert('Request failed. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
884 }
885 );
886 }
887
888 function vboSubmitGuestMisconduct() {
889 if (!vbo_guest_misconduct_fields.length) {
890 alert('Empty data to submit. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
891 return false;
892 }
893
894 // prevent double submissions
895 vboGuestMisconductDisableSubmit();
896 //
897
898 var submit_fields = {
899 tmpl: "component",
900 bid: jQuery('.vbo-modal-guestmisconduct-addnew').attr('data-bid'),
901 otabid: jQuery('.vbo-modal-guestmisconduct-addnew').attr('data-otabid'),
902 bcom_keys: new Array
903 };
904 for (var elemid in vbo_guest_misconduct_fields) {
905 if (!vbo_guest_misconduct_fields.hasOwnProperty(elemid)) {
906 continue;
907 }
908 if (!jQuery('#' + vbo_guest_misconduct_fields[elemid]).length || !jQuery('#' + vbo_guest_misconduct_fields[elemid]).closest('.vbo-modal-guestmisconduct-addnew-elem').length) {
909 // form element not found, or parent container not found
910 continue;
911 }
912 if (jQuery('#' + vbo_guest_misconduct_fields[elemid]).closest('.vbo-modal-guestmisconduct-addnew-elem').is(':visible')) {
913 // we include this value in the AJAX request
914 var field_name = jQuery('#' + vbo_guest_misconduct_fields[elemid]).attr('data-gmname');
915 var submit_key = 'bcom_' + field_name;
916 submit_fields[submit_key] = jQuery('#' + vbo_guest_misconduct_fields[elemid]).val();
917 submit_fields['bcom_keys'].push(submit_key);
918 }
919 }
920
921 // make the AJAX request to VCM
922 var jqxhr = jQuery.ajax({
923 type: "POST",
924 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikchannelmanager&task=submit_bcom_guestmisconduct'); ?>",
925 data: submit_fields
926 }).done(function(res) {
927 try {
928 var misconduct_rs = typeof res === 'string' ? JSON.parse(res) : res;
929 console.log(submit_fields, misconduct_rs);
930
931 // make sure the request was successful
932 if (!misconduct_rs.status) {
933 alert(misconduct_rs.error);
934 vboGuestMisconductEnableSubmit();
935 return false;
936 }
937
938 // make another AJAX request (now on VBO) to update the booking history
939 var event_descr = jQuery('#vbo-gm-mandfield-details_text').length ? jQuery('#vbo-gm-mandfield-details_text').val() : '';
940 jQuery.ajax({
941 type: "POST",
942 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=store_booking_history_event'); ?>",
943 data: {
944 tmpl: "component",
945 bid: jQuery('.vbo-modal-guestmisconduct-addnew').attr('data-bid'),
946 event: 'GM',
947 descr: event_descr
948 }
949 }).done(function(res) {
950 // just reload the page in case of success
951 document.location.href = jQuery('#vbo-gm-reloadlink').attr('href');
952 }).fail(function() {
953 // we reload the page even in case of failure
954 document.location.href = jQuery('#vbo-gm-reloadlink').attr('href');
955 });
956 } catch (e) {
957 console.log(res);
958 alert('Invalid update response. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
959 vboGuestMisconductEnableSubmit();
960 hideVboDialogGuestMisconduct();
961 return false;
962 }
963 }).fail(function() {
964 alert('Update Request failed. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
965 vboGuestMisconductEnableSubmit();
966 return false;
967 });
968 }
969
970 function hideVboDialogGuestMisconduct() {
971 if (vbodialogguestmisconduct_on === true) {
972 jQuery(".vbo-modal-overlay-block-guestmisconduct").fadeOut(400, function () {
973 jQuery(".vbo-modal-overlay-content-guestmisconduct").show();
974 });
975 // turn flag off
976 vbodialogguestmisconduct_on = false;
977 }
978 }
979
980 function vboGuestMisconductChangeCategory(gmcid) {
981 jQuery('.vbo-modal-guestmisconduct-addnew-cond').each(function() {
982 if (jQuery(this).attr('data-gmcid') == gmcid) {
983 jQuery(this).show();
984 } else {
985 jQuery(this).hide();
986 }
987 });
988 }
989
990 function vboGuestMisconductDisableSubmit() {
991 jQuery('#vbo-guest-misconduct-submit-btn').prepend('<i class="<?php echo VikBookingIcons::i('refresh', 'fa-spin fa-fw'); ?>"></i> ').prop('disabled', true);
992 }
993
994 function vboGuestMisconductEnableSubmit() {
995 jQuery('#vbo-guest-misconduct-submit-btn').prop('disabled', false).find('i').remove();
996 }
997 </script>
998
999 </div>
1000 <?php
1001 }
1002 if ($this->vcm_host_to_guest_review) {
1003 ?>
1004 <div class="vbo-bookdet-wrap">
1005 <div class="vbo-bookdet-head">
1006 <span><?php echo JText::translate('VBO_REVIEW_YOUR_GUEST'); ?></span>
1007 </div>
1008 <div class="vbo-bookdet-foot">
1009 <button type="button" class="btn btn-small btn-primary vcm-btn-channel-airbnbapi" onclick="vboOpenJModal('vbo-vcm-host-to-guest-review', 'index.php?option=com_vikchannelmanager&task=hostguestreview&cid[]=<?php echo $row['id']; ?>&tmpl=component');">
1010 <?php VikBookingIcons::e('smile'); ?>
1011 <?php echo JText::translate('VBO_WRITE_REVIEW'); ?>
1012 </button>
1013 </div>
1014 </div>
1015 <?php
1016 // prepare modal (host-to-guest review)
1017 array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-vcm-host-to-guest-review', JText::translate('VBO_REVIEW_YOUR_GUEST')));
1018
1019 // check if a notification was clicked
1020 if (VikRequest::getString('notif_action', '', 'request') == 'airbnb_host_guest_review') {
1021 JFactory::getDocument()->addScriptDeclaration(
1022 <<<JS
1023 jQuery(function() {
1024 setTimeout(() => {
1025 jQuery('.vcm-btn-channel-airbnbapi').trigger('click');
1026 }, 500);
1027 });
1028 JS
1029 );
1030 }
1031 }
1032 }
1033 ?>
1034 </div>
1035
1036 <?php
1037 if (!$printreceipt && $this->allows_conversion !== false) {
1038 ?>
1039 <div class="vbo-bookdet-container vbo-bookdet-conv-currency">
1040 <div class="vbo-bookdet-conv-currency-inner">
1041 <div class="vbo-bookdet-conv-currency-info">
1042 <span><?php echo JText::sprintf('VBO_CONV_RES_OTA_CURRENCY', $this->conv_from_currency, $this->conv_to_currency); ?></span>
1043 <span><?php echo JText::sprintf('VBO_CONV_RES_OTA_CURRENCY_EXC', ($this->conv_from_currency . ' ' . VikBooking::numberFormat($row['total'])), ($this->conv_to_currency . ' ' . VikBooking::numberFormat($this->allows_conversion))); ?></span>
1044 </div>
1045 <div class="vbo-bookdet-conv-currency-apply">
1046 <a class="btn vbo-config-btn" onclick="return confirm(Joomla.JText._('VBO_CONV_RES_OTA_CURRENCY_APPLY') + '?');" href="index.php?option=com_vikbooking&task=editorder&cid[]=<?php echo $row['id']; ?>&do_ota_curr_conv=1"><?php VikBookingIcons::e('exchange-alt'); ?> <?php echo JText::translate('VBO_CONV_RES_OTA_CURRENCY_APPLY'); ?></a>
1047 </div>
1048 </div>
1049 </div>
1050 <?php
1051 }
1052
1053 if (!$printreceipt && $row['status'] == "standby" && empty($row['idorderota']) && !strcasecmp((string)$row['type'], 'Inquiry')) {
1054 // website pending reservation inquiry
1055 $ir_data_callback = function($data) {
1056 return (is_object($data) && !empty($data->av_type));
1057 };
1058 $prev_ir_data = $history_obj->getEventsWithData('IR', $ir_data_callback, true);
1059 if (is_array($prev_ir_data) && $prev_ir_data) {
1060 // display a message about the availability type at the time of creation of the inquiry reservation
1061
1062 // parse original stay dates into DateTime objects
1063 $orig_checkin_dt_obj = new JDate($prev_ir_data[0]->checkin_date);
1064 $orig_checkout_dt_obj = new JDate($prev_ir_data[0]->checkout_date);
1065 ?>
1066 <div class="vbo-bookdet-container vbo-bookdet-inquiry-alert">
1067 <div class="vbo-bookdet-inquiry-alert-dismiss">
1068 <button type="button" class="btn btn-small btn-warning" onclick="jQuery('.vbo-bookdet-inquiry-alert').remove();"><?php VikBookingIcons::e('times-circle'); ?> <?php echo JText::translate('VBOBTNKEEPREMIND'); ?></button>
1069 </div>
1070 <div class="vbo-bookdet-inquiry-alert-message">
1071 <div class="vbo-bookdet-inquiry-alert-top">
1072 <span><?php echo JText::translate('VBO_WEB_INQUIRY_ALERT'); ?></span>
1073 </div>
1074 <div class="vbo-bookdet-inquiry-alert-avtype">
1075 <span class="vbo-bookdet-inquiry-alert-mess-avtype"><?php
1076 // explain what was the availability at the time of inquiry
1077 if ($prev_ir_data[0]->av_type === 1) {
1078 echo JText::translate('VBO_WEB_INQUIRY_AVTYPE_1');
1079 } elseif ($prev_ir_data[0]->av_type === 2) {
1080 echo JText::translate('VBO_WEB_INQUIRY_AVTYPE_2');
1081 } elseif ($prev_ir_data[0]->av_type === 3) {
1082 echo JText::translate('VBO_WEB_INQUIRY_AVTYPE_3');
1083 } else {
1084 echo JText::translate('VBO_WEB_INQUIRY_AVTYPE_4');
1085 }
1086 ?></span>
1087 <span class="vbo-bookdet-inquiry-alert-mess-origrq">
1088 <strong><?php echo JText::translate('VBO_WEB_INQUIRY_ORIGRQ') . ':'; ?></strong>
1089 <span class="badge"><?php echo JText::translate('VBPICKUPAT') . ': ' . $orig_checkin_dt_obj->format('D, d M Y', true); ?></span>
1090 <span class="badge"><?php echo JText::translate('VBRELEASEAT') . ': ' . $orig_checkout_dt_obj->format('D, d M Y', true); ?></span>
1091 <span class="badge"><?php echo JText::translate('VBEDITORDERADULTS') . ': ' . $prev_ir_data[0]->adults; ?></span>
1092 <?php
1093 if (!empty($prev_ir_data[0]->children)) {
1094 ?>
1095 <span class="badge"><?php echo JText::translate('VBEDITORDERCHILDREN') . ': ' . $prev_ir_data[0]->children; ?></span>
1096 <?php
1097 }
1098 ?>
1099 </span>
1100 </div>
1101 <div class="vbo-bookdet-inquiry-alert-bottom">
1102 <span><?php echo JText::translate('VBO_WEB_INQUIRY_SUGG'); ?></span>
1103 </div>
1104 <?php
1105 if (empty($row['idquote'])) {
1106 // even if it cannot be a quote, we make sure it's just an inquiry for now
1107 $createQuoteUri = 'index.php?option=com_vikbooking&view=managequote&' . http_build_query([
1108 'customer' => [
1109 'id' => $customer['id'] ?? null,
1110 'first_name' => $customer['first_name'] ?? null,
1111 'last_name' => $customer['last_name'] ?? null,
1112 'email' => $customer['email'] ?? null,
1113 'phone' => $customer['phone'] ?? null,
1114 'country' => $customer['country'] ?? null,
1115 ],
1116 'inquiry' => [
1117 'checkin' => date('Y-m-d', $row['checkin']),
1118 'checkout' => date('Y-m-d', $row['checkout']),
1119 'parties' => array_map(function($or) {
1120 return [
1121 'adults' => $or['adults'] ?? 1,
1122 'children' => $or['children'] ?? 0,
1123 ];
1124 }, $rooms),
1125 'rooms' => array_map(function($or) {
1126 return [
1127 'id' => $or['idroom'] ?? 0,
1128 ];
1129 }, $rooms),
1130 ],
1131 ]);
1132 ?>
1133 <div class="vbo-bookdet-inquiry-alert-bottom">
1134 <a class="btn vbo-config-btn" href="<?php echo VBOFactory::getPlatform()->getUri()->admin($createQuoteUri); ?>"><?php VikBookingIcons::e('file-alt'); ?> <?php echo JText::translate('VBO_CREATE_QUOTE'); ?></a>
1135 </div>
1136 <?php
1137 }
1138 ?>
1139 </div>
1140 </div>
1141 <?php
1142 }
1143 }
1144 ?>
1145
1146 <div class="vbo-bookingdet-innertop">
1147 <div class="vbo-bookingdet-commands">
1148 <?php
1149 if ($busy || $row['status'] == "standby") {
1150 ?>
1151 <div class="vbo-bookingdet-command">
1152 <button onclick="document.location.href='index.php?option=com_vikbooking&task=editbusy&cid[]=<?php echo $row['id']; ?>';" class="btn vbo-config-btn" type="button"><i class="icon-pencil"></i> <?php echo JText::translate('VBMODRES'); ?></button>
1153 </div>
1154 <?php
1155 }
1156 if (!empty($row['idquote'])) {
1157 ?>
1158 <div class="vbo-bookingdet-command">
1159 <button class="btn vbo-config-btn vbo-quote-details-btn" type="button"><?php VikBookingIcons::e('file-alt'); ?> <?php echo JText::translate('VBO_QUOTE_DETAILS'); ?></button>
1160 </div>
1161 <?php
1162 }
1163 if ((array_key_exists(1, $tars) && $tars[1]) || ($is_package || $is_cust_cost)) {
1164
1165 if (VBOPlatformDetection::isWordPress()) {
1166 /**
1167 * @wponly display warning message if no valid Shortcodes found
1168 */
1169 $model = JModel::getInstance('vikbooking', 'shortcodes');
1170 $itemid = $model->best('booking');
1171 if (!$itemid) {
1172 VikError::raiseWarning('', 'No Shortcodes found, or no Shortcodes being used in Pages/Posts.');
1173 }
1174 }
1175
1176 ?>
1177 <div class="vbo-bookingdet-command">
1178 <button onclick="window.open('<?php echo VikBooking::externalroute('index.php?option=com_vikbooking&view=booking&sid='.(!empty($row['sid']) ? $row['sid'] : $row['idorderota']).'&ts='.$row['ts'], false); ?>', '_blank');" type="button" class="btn vbo-config-btn"><?php VikBookingIcons::e('external-link'); ?> <?php echo JText::translate('VBVIEWORDFRONT'); ?></button>
1179 </div>
1180 <?php
1181 }
1182 if (($row['status'] == "confirmed" || ($row['status'] == "standby" && !empty($row['custmail']))) && ((array_key_exists(1, $tars) && $tars[1]) || ($is_package || $is_cust_cost))) {
1183 ?>
1184 <div class="vbo-bookingdet-command">
1185 <button class="btn vbo-config-btn" type="button" onclick="document.location.href='index.php?option=com_vikbooking&task=resendordemail&cid[]=<?php echo $row['id']; ?>';"><?php VikBookingIcons::e('envelope'); ?> <?php echo JText::translate('VBRESENDORDEMAIL'); ?></button>
1186 </div>
1187 <?php
1188 }
1189 if (is_array($this->vcm_special_offer)) {
1190 if (empty($this->vcm_special_offer[3]) || !empty($this->vcm_special_offer[4])) {
1191 // no special offer sent before, or withdrawn
1192 ?>
1193 <div class="vbo-bookingdet-command">
1194 <button type="button" class="btn btn-primary vcm-btn-channel-<?php echo strtolower($this->vcm_special_offer[2]); ?>" onclick="vboOpenJModal('vbo-vcm-special-offer', 'index.php?option=com_vikchannelmanager&task=specialoffer&bid=<?php echo $row['id']; ?>&listing_id=<?php echo $this->vcm_special_offer[0]; ?>&ota_thread_id=<?php echo $this->vcm_special_offer[1]; ?>&tmpl=component');"><?php VikBookingIcons::e('certificate'); ?> <?php echo JText::sprintf('VBO_VCM_SPECIAL_OFFER', $this->vcm_special_offer[2]); ?></button>
1195 </div>
1196 <?php
1197 // prepare modal (VCM prepare special offer)
1198 array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-vcm-special-offer', JText::sprintf('VBO_VCM_SPECIAL_OFFER', $this->vcm_special_offer[2])));
1199 // end prepare modal
1200 } else {
1201 // special offer sent before, link to withdraw it
1202 ?>
1203 <div class="vbo-bookingdet-command">
1204 <a href="index.php?option=com_vikchannelmanager&task=sendSpecialOffer&vbo_oid=<?php echo $row['id']; ?>&spo_type=special_offer&spo_action=withdraw&ota_thread_id=<?php echo $this->vcm_special_offer[1]; ?>&spo_id=<?php echo $this->vcm_special_offer[3]; ?>" class="btn btn-danger"><?php VikBookingIcons::e('ban'); ?> <?php echo JText::translate('VBO_WITHDRAW_SPOFFER'); ?></a>
1205 </div>
1206 <?php
1207 }
1208 }
1209 if ($row['status'] == "standby" || ($row['status'] == "cancelled" && $row['checkout'] >= $current_ts)) {
1210 ?>
1211 <div class="vbo-bookingdet-command">
1212 <button class="btn btn-success" type="button" onclick="if (confirm('<?php echo htmlspecialchars(JText::translate('VBSETORDCONFIRMED')); ?> ?')) {document.location.href='index.php?option=com_vikbooking&task=setordconfirmed&cid[]=<?php echo $row['id'] . ($row['status'] == "cancelled" ? '&skip_notification=1' : ''); ?>';}"><?php VikBookingIcons::e('check'); ?> <?php echo JText::translate('VBSETORDCONFIRMED'); ?></button>
1213 </div>
1214 <?php
1215 }
1216 if ($row['status'] == "cancelled" && !$row['closure']) {
1217 ?>
1218 <div class="vbo-bookingdet-command">
1219 <button type="button" class="btn btn-warning vbo-context-menu-btn vbo-context-menu-actionscanc">
1220 <span class="vbo-context-menu-lbl"><?php echo JText::translate('VBCRONACTIONS'); ?></span>
1221 <span class="vbo-context-menu-ico"><?php VikBookingIcons::e('sort-down'); ?></span>
1222 </button>
1223 </div>
1224
1225 <script type="text/javascript">
1226 jQuery(function() {
1227 jQuery('.vbo-context-menu-actionscanc').vboContextMenu({
1228 placement: 'bottom-right',
1229 buttons: [
1230 <?php
1231 if (!empty($row['custmail'])) :
1232 ?>
1233 {
1234 icon: '<?php echo VikBookingIcons::i('envelope'); ?>',
1235 text: Joomla.JText._('VBSENDCANCORDEMAIL'),
1236 class: 'vbo-context-menu-entry-danger',
1237 separator: true,
1238 action: (root, config) => {
1239 document.location.href = 'index.php?option=com_vikbooking&task=sendcancordemail&cid[]=<?php echo $row['id']; ?>';
1240 },
1241 },
1242 <?php
1243 endif;
1244 ?>
1245 {
1246 icon: '<?php echo VikBookingIcons::i('hourglass-half'); ?>',
1247 text: Joomla.JText._('VBO_SET_STANDBY'),
1248 class: 'vbo-context-menu-entry-warning',
1249 separator: false,
1250 action: (root, config) => {
1251 document.location.href = '<?php echo VBOFactory::getPlatform()->getUri()->addCSRF('index.php?option=com_vikbooking&task=bookings.set_to_pending&bid=' . $row['id']); ?>';
1252 },
1253 },
1254 ],
1255 });
1256 });
1257 </script>
1258 <?php
1259 }
1260 if ($row['status'] == 'confirmed' && $row['closure'] < 1) {
1261 ?>
1262 <div class="vbo-bookingdet-command pro-feature">
1263 <button type="button" class="btn vbo-config-btn" onclick="document.getElementById('invnotes-hid').value=document.getElementById('invnotes').value;document.getElementById('vbo-gen-invoice').submit();"><?php VikBookingIcons::e('file-text-o'); ?> <?php echo JText::translate('VBOGENBOOKINGINVOICE'); ?></button>
1264 </div>
1265 <?php
1266 }
1267 if ($row['status'] == 'confirmed' && $row['closure'] < 1) {
1268 ?>
1269 <div class="vbo-bookingdet-command pro-feature">
1270 <button type="button" class="btn vbo-config-btn" onclick="window.open('index.php?option=com_vikbooking&task=editorder&cid[]=<?php echo $row['id']; ?>&print=1&tmpl=component', '_blank');"><?php VikBookingIcons::e('print'); ?> <?php echo JText::translate('VBOPRINTRECEIPT'); ?></button>
1271 </div>
1272 <?php
1273 }
1274 if ($row['status'] != 'confirmed' || $row['closure'] > 0 || $this->vcm_cancel_active_res) {
1275 if ($this->vcm_decline_actions) {
1276 // this booking requires some decline actions before being removed
1277 ?>
1278 <div class="vbo-bookingdet-command">
1279 <button type="button" class="btn btn-danger" onclick="vboOpenJModal('vbo-vcm-decline-booking', 'index.php?option=com_vikchannelmanager&task=declinebooking&cid[]=<?php echo $row['id']; ?>&tmpl=component');"><?php VikBookingIcons::e('trash'); ?> <?php echo JText::translate('VBMAINEBUSYDEL'); ?></button>
1280 </div>
1281 <?php
1282 // prepare modal (VCM decline booking)
1283 array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-vcm-decline-booking', JText::translate('VBMAINEBUSYDEL')));
1284 // end prepare modal
1285 } elseif ($this->vcm_cancel_active_res) {
1286 // the active OTA booking can be cancelled
1287 ?>
1288 <div class="vbo-bookingdet-command">
1289 <button type="button" class="btn btn-danger" onclick="vboOpenJModal('vbo-vcm-cancel-reservation', 'index.php?option=com_vikchannelmanager&task=cancelreservation&vbo_oid=<?php echo $row['id']; ?>&tmpl=component');"><?php VikBookingIcons::e('trash'); ?> <?php echo JText::translate('VBMAINEBUSYDEL'); ?></button>
1290 </div>
1291 <?php
1292 // prepare modal (VCM cancel reservation)
1293 array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-vcm-cancel-reservation', JText::translate('VBMAINEBUSYDEL')));
1294 // end prepare modal
1295 } else {
1296 // regular remove button with confirmation
1297 ?>
1298 <div class="vbo-bookingdet-command">
1299 <button type="button" class="btn btn-danger" onclick="if (confirm(Joomla.JText._('VBDELCONFIRM'))){document.location.href='index.php?option=com_vikbooking&task=removeorders&cid[]=<?php echo $row['id']; ?>&goto=<?php echo $row['id']; ?>';}"><?php VikBookingIcons::e('trash'); ?> <?php echo $row['status'] == 'cancelled' ? JText::translate('VBO_PURGERM_RESERVATION') : JText::translate('VBMAINEBUSYDEL'); ?></button>
1300 </div>
1301 <?php
1302 }
1303 }
1304 ?>
1305
1306 <!-- Define role to detect the supported hook -->
1307 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorder","key":"buttons","type":"field"} -->
1308
1309 <?php
1310 if (isset($bookingPanelForms['buttons']))
1311 {
1312 echo $bookingPanelForms['buttons'];
1313 }
1314 ?>
1315 </div>
1316
1317 <div class="vbo-bookingdet-tabs">
1318 <div class="vbo-bookingdet-tab vbo-bookingdet-tab-active" data-vbotab="vbo-tab-details"><?php echo JText::translate('VBOBOOKDETTABDETAILS'); ?></div>
1319 <div class="vbo-bookingdet-tab" data-vbotab="vbo-tab-admin"><?php echo JText::translate('VBOBOOKDETTABADMIN'); ?></div>
1320 </div>
1321 </div>
1322
1323 <?php
1324 /**
1325 * Check if the booking has got some tasks assigned.
1326 *
1327 * @since 1.18.0 (J) - 1.8.0 (WP)
1328 */
1329 $taskManager = VBOFactory::getTaskManager();
1330 $bookingTasks = VBOTaskModelTask::getInstance()->filterItems(['id_order' => $row['id']]);
1331 ?>
1332
1333 <div class="vbo-bookingdet-tab-cont" id="vbo-tab-details" style="display: block;">
1334 <div class="vbo-bookingdet-innercontainer">
1335 <div class="vbo-bookingdet-customer">
1336 <?php
1337 if ($bookingTasks) {
1338 ?>
1339 <div class="vbo-bookingdet-detcont vbo-bookingdet-detcont-tm vbo-hidein-print">
1340 <div class="vbo-bookingdet-lblcont">
1341 <label><?php echo JText::translate('VBO_TASK_MANAGER'); ?></label>
1342 </div>
1343 <div class="vbo-bookingdet-inpwrap vbo-bookingdet-tasks-list">
1344 <?php
1345 foreach ($bookingTasks as $taskRecord) {
1346 $task = VBOTaskTaskregistry::getInstance((array) $taskRecord);
1347 ?>
1348 <div class="vbo-bookingdet-task-details" data-task-id="<?php echo $task->getID(); ?>">
1349 <div class="vbo-bookingdet-task-detail" data-type="info">
1350 <span class="vbo-bookingdet-task-title"><?php echo $task->getTitle(); ?></span>
1351 <span class="vbo-bookingdet-task-sub-title"><?php echo $task->getAreaName($task->getAreaID()); ?></span>
1352 </div>
1353 <?php
1354 $taskUnreadMessages = (bool) $task->get('hasUnreadMessages', false);
1355 if ($taskUnreadMessages) {
1356 ?>
1357 <div class="vbo-bookingdet-task-detail" data-type="unread-messages">
1358 <span class="unread-message-dot"><?php VikBookingIcons::e('comment'); ?></span>
1359 </div>
1360 <?php
1361 }
1362 if ($taskManager->statusTypeExists($task->getStatus())) {
1363 $taskStatus = $taskManager->getStatusTypeInstance($task->getStatus());
1364 ?>
1365 <div class="vbo-bookingdet-task-detail" data-type="status">
1366 <span class="vbo-tm-task-status-badge vbo-tm-color <?php echo $taskStatus->getColor(); ?>" data-status="<?php echo $this->escape($taskStatus->getEnum()); ?>"><?php echo $taskStatus->getName(); ?></span>
1367 </div>
1368 <?php
1369 }
1370 ?>
1371 </div>
1372 <?php
1373 }
1374 ?>
1375 </div>
1376 </div>
1377 <?php
1378 }
1379 ?>
1380 <div class="vbo-bookingdet-detcont<?php echo $row['closure'] > 0 ? ' vbo-bookingdet-closure' : ''; ?>">
1381 <?php
1382 $custdata_parts = explode("\n", $row['custdata']);
1383 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
1384 //attempt to format labels and values
1385 foreach ($custdata_parts as $custdet) {
1386 if (strlen($custdet) < 1) {
1387 continue;
1388 }
1389 $custdet_parts = explode(':', $custdet);
1390 $custd_lbl = '';
1391 $custd_val = '';
1392 if (count($custdet_parts) < 2) {
1393 $custd_val = $custdet;
1394 } else {
1395 $custd_lbl = $custdet_parts[0];
1396 if ($custd_lbl == 'http' || $custd_lbl == 'https') {
1397 // shift values
1398 $custdet_parts[2] = $custdet_parts[1];
1399 $custdet_parts[1] = $custdet_parts[0];
1400 $custd_lbl = '';
1401 }
1402 unset($custdet_parts[0]);
1403 if ((!strcasecmp(trim($custdet_parts[1]), 'http') || !strcasecmp(trim($custdet_parts[1]), 'https')) && !empty($custdet_parts[2]) && strpos($custdet_parts[2], '//') !== false) {
1404 // this is a URI
1405 $custd_val = '<a href="' . htmlspecialchars(trim(implode(':', $custdet_parts))) . '" target="_blank"><i class="' . VikBookingIcons::i('external-link') . '"></i></a>';
1406 } else {
1407 $custd_val = htmlspecialchars(trim(implode(':', $custdet_parts)));
1408 }
1409 }
1410 ?>
1411 <div class="vbo-bookingdet-userdetail">
1412 <?php
1413 if (strlen($custd_lbl)) {
1414 ?>
1415 <span class="vbo-bookingdet-userdetail-lbl"><?php echo VikBooking::tnCustomerRawDataLabel($custd_lbl); ?></span>
1416 <?php
1417 }
1418 if (strlen($custd_val)) {
1419 ?>
1420 <span class="vbo-bookingdet-userdetail-val"><?php echo $custd_val; ?></span>
1421 <?php
1422 }
1423 ?>
1424 </div>
1425 <?php
1426 }
1427 } else {
1428 if ($row['closure'] > 0) {
1429 ?>
1430 <div class="vbo-bookingdet-userdetail">
1431 <span class="vbo-bookingdet-userdetail-val"><?php echo nl2br($row['custdata']); ?></span>
1432 </div>
1433 <?php
1434 } else {
1435 echo nl2br($row['custdata']);
1436 ?>
1437 <div class="vbo-bookingdet-userdetail">
1438 <span class="vbo-bookingdet-userdetail-val">&nbsp;</span>
1439 </div>
1440 <?php
1441 }
1442 }
1443 if (!empty($row['ujid'])) {
1444 $orig_user = JFactory::getUser($row['ujid']);
1445 $author_name = is_object($orig_user) && property_exists($orig_user, 'name') && !empty($orig_user->name) ? $orig_user->name : '';
1446 ?>
1447 <div class="vbo-bookingdet-userdetail">
1448 <span class="vbo-bookingdet-userdetail-val"><?php echo JText::sprintf('VBOBOOKINGCREATEDBY', $row['ujid'].(!empty($author_name) ? ' ('.$author_name.')' : '')); ?></span>
1449 </div>
1450 <?php
1451 }
1452 ?>
1453
1454 <!-- Define role to detect the supported hook -->
1455 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"userdetails","type":"field"} -->
1456
1457 <?php
1458 if (isset($bookingSidebarForms['userdetails']))
1459 {
1460 echo $bookingSidebarForms['userdetails'];
1461 }
1462 ?>
1463
1464 </div>
1465
1466 <?php
1467 // build the proper invoice SID for bc
1468 $inv_sid = $row['sid'] ?: $row['idorderota'] ?: '';
1469 if (empty($row['sid']) && is_file(implode(DIRECTORY_SEPARATOR, [VBO_SITE_PATH, 'helpers', 'invoices', 'generated', "{$row['id']}_{$row['sid']}.pdf"]))) {
1470 // use the old file name signature for OTA bookings
1471 $inv_sid = $row['sid'];
1472 }
1473
1474 // build list of invoice details (path/uri & label/button), one by default
1475 $invoice_details = [
1476 [
1477 'path' => implode(DIRECTORY_SEPARATOR, [VBO_SITE_PATH, 'helpers', 'invoices', 'generated', "{$row['id']}_{$inv_sid}.pdf"]),
1478 'uri' => VBO_SITE_URI . 'helpers/invoices/generated/' . "{$row['id']}_{$inv_sid}.pdf",
1479 'label' => JText::translate('VBOCOLORTAGRULEINVONE'),
1480 'btn' => JText::translate('VBOINVDOWNLOAD'),
1481 ]
1482 ];
1483
1484 /**
1485 * Merge the additional invoices generated by the e-invoicing drivers for this booking.
1486 *
1487 * @since 1.16.7 (J) - 1.6.7 (WP)
1488 */
1489 $invoice_details = array_merge($invoice_details, VBOEinvoicingFactory::getInstance()->getBookingExtraInvoices($row['id']));
1490
1491 /**
1492 * Trigger event to allow third-party plugins to define additional invoices or paths/urls.
1493 *
1494 * @since 1.16.7 (J) - 1.6.7 (WP)
1495 */
1496 VBOFactory::getPlatform()->getDispatcher()->trigger('onBeforeListInvoices', [$row, &$invoice_details]);
1497
1498 // check if an invoice exists
1499 $invoiced = false;
1500 foreach ((array) $invoice_details as $invoice_detail) {
1501 $invoiced = $invoiced || is_file($invoice_detail['path']);
1502 }
1503
1504 // extra booking details
1505 if (!$printreceipt && ((!empty($row['channel']) && !empty($row['idorderota'])) || strlen((string)$row['confirmnumber']) || $invoiced)) {
1506 ?>
1507 <div class="vbo-bookingdet-detcont vbo-bookingdet-detcont-labels-wrap vbo-hidein-print">
1508 <?php
1509 if (!empty($row['channel']) && !empty($row['idorderota'])) {
1510 $tiny_logo_url = '';
1511 $channelparts = explode('_', $row['channel']);
1512 if ($ch_logo = VikBooking::getVcmChannelsLogo($row['channel'], true)) {
1513 $tiny_logo_url = $ch_logo->getTinyLogoURL();
1514 }
1515 $displayOtaBid = !strcasecmp((string) $row['type'], 'Inquiry') && $row['status'] == 'standby' ? '' : $row['idorderota'];
1516 ?>
1517 <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-idorderota <?php echo strtolower(preg_replace('/[^a-z0-9]/i', '', $channelparts[0])); ?>">
1518 <span class="label label-info">
1519 <span class="vbo-bookingdet-ota-details">
1520 <?php
1521 if ($tiny_logo_url) {
1522 ?>
1523 <span class="vbo-bookingdet-ota-logo"><img src="<?php echo $tiny_logo_url; ?>" /></span>
1524 <?php
1525 }
1526 ?>
1527 <span class="vbo-bookingdet-ota-name"><?php echo $otachannel_name . ' ID'; ?></span>
1528 </span>
1529 <span class="badge<?php echo $displayOtaBid ? ' vbo-tooltip vbo-tooltip-top vbo-reservation-copy-otabid' : ''; ?>" data-tooltiptext="<?php echo JHtml::fetch('esc_attr', JText::translate('VBO_COPY')); ?>"><?php echo $displayOtaBid ? $row['idorderota'] : '-----'; ?></span>
1530 </span>
1531 <textarea class="vbo-textarea-copyable" data-copy="otabid"><?php echo htmlentities($displayOtaBid); ?></textarea>
1532 </div>
1533 <?php
1534 }
1535 if (strlen((string)$row['confirmnumber'])) {
1536 ?>
1537 <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-confirmnumber">
1538 <span class="label label-success">
1539 <span><?php echo JText::translate('VBCONFIRMNUMB'); ?></span>
1540 <span class="badge"><?php echo $row['confirmnumber']; ?></span>
1541 </span>
1542 </div>
1543 <?php
1544 }
1545
1546 /**
1547 * Check for AI automated host-to-guest reviews.
1548 *
1549 * @since 1.16.10 (J) - 1.6.10 (WP)
1550 */
1551 if (class_exists('VikChannelManager') && VikChannelManager::hostToGuestReviewSupported($row, $willbe = true)) {
1552 if (class_exists('VCMAiModelSettings') && (new VCMAiModelSettings)->isGuestReviewAutoResponderEnabled()) {
1553 // host-to-guest review will be supported and AI auto-guest-review is enabled
1554 $ai_auto_guest_review_opt = (array) VBOFactory::getConfig()->getArray('ai_auto_guest_review_opt_' . $row['id'], []);
1555 ?>
1556 <div class="vbo-bookingdet-detcont-ai-info">
1557 <p class="vbo-bookingdet-detcont-ai-info-status">
1558 <span class="vbo-bookingdet-detcont-ai-info-status-on" style="<?php echo ($ai_auto_guest_review_opt['ignore'] ?? 0) ? 'display: none;' : ''; ?>"><?php VikBookingIcons::e('check-circle'); ?> <span><?php echo JText::translate('VBO_AI_AUTO_GUEST_REV_WILLRUN'); ?></span></span>
1559 <span class="vbo-bookingdet-detcont-ai-info-status-off" style="<?php echo !($ai_auto_guest_review_opt['ignore'] ?? 0) ? 'display: none;' : ''; ?>"><?php VikBookingIcons::e('ban'); ?> <span><?php echo JText::translate('VBO_AI_AUTO_GUEST_REV_RESIGNORE'); ?></span></span>
1560 </p>
1561 <button type="button" class="btn btn-small btn-primary vbo-context-menu-btn vbo-context-menu-ai-autoreview">
1562 <span class="vbo-context-menu-lbl"><?php echo JText::translate('VBCRONACTIONS'); ?></span>
1563 <span class="vbo-context-menu-ico"><?php VikBookingIcons::e('sort-down'); ?></span>
1564 </button>
1565 </div>
1566
1567 <script type="text/javascript">
1568 // build context menu
1569 jQuery(function() {
1570
1571 // toggle ignore AI auto-review guest function
1572 let vbo_action_ignore_ai_autorg = (now_ignore) => {
1573 if (confirm(Joomla.JText._((now_ignore ? 'VBO_AI_AUTO_GUEST_REV_INCLUDE' : 'VBO_AI_AUTO_GUEST_REV_EXCLUDE')))) {
1574 // update the auto-review ignore status for this booking
1575 VBOCore.doAjax(
1576 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=bookings.set_ai_auto_guest_review_opt'); ?>",
1577 {
1578 bid: '<?php echo $row['id']; ?>',
1579 opt: {
1580 ignore: (now_ignore ? 0 : 1),
1581 },
1582 },
1583 (opt) => {
1584 // populate the new buttons
1585 let new_auto_review_opt = [];
1586 new_auto_review_opt.push({
1587 icon: ((opt.ignore || 0) ? '<?php echo VikBookingIcons::i('check-circle'); ?>' : '<?php echo VikBookingIcons::i('ban'); ?>'),
1588 text: Joomla.JText._((opt?.ignore ? 'VBO_AI_AUTO_GUEST_REV_INCLUDE' : 'VBO_AI_AUTO_GUEST_REV_EXCLUDE')),
1589 class: (opt?.ignore ? 'vbo-context-menu-entry-success' : 'vbo-context-menu-entry-danger'),
1590 separator: true,
1591 action: (root, config) => {
1592 // register callback
1593 vbo_action_ignore_ai_autorg(opt.ignore || 0);
1594 },
1595 });
1596
1597 // set new buttons in context menu
1598 jQuery('.vbo-context-menu-ai-autoreview').vboContextMenu('buttons', new_auto_review_opt);
1599
1600 // display the proper status label
1601 if (opt?.ignore) {
1602 jQuery('.vbo-bookingdet-detcont-ai-info-status-on').hide();
1603 jQuery('.vbo-bookingdet-detcont-ai-info-status-off').show();
1604 } else {
1605 jQuery('.vbo-bookingdet-detcont-ai-info-status-off').hide();
1606 jQuery('.vbo-bookingdet-detcont-ai-info-status-on').show();
1607 }
1608 },
1609 (error) => {
1610 // display error message
1611 alert(error.responseText);
1612 }
1613 );
1614 }
1615 };
1616
1617 // render context menu
1618 jQuery('.vbo-context-menu-ai-autoreview').vboContextMenu({
1619 placement: 'bottom-left',
1620 buttons: [
1621 {
1622 icon: '<?php echo VikBookingIcons::i(($ai_auto_guest_review_opt['ignore'] ?? 0) ? 'check-circle' : 'ban'); ?>',
1623 text: Joomla.JText._('<?php echo ($ai_auto_guest_review_opt['ignore'] ?? 0) ? 'VBO_AI_AUTO_GUEST_REV_INCLUDE' : 'VBO_AI_AUTO_GUEST_REV_EXCLUDE'; ?>'),
1624 class: '<?php echo ($ai_auto_guest_review_opt['ignore'] ?? 0) ? 'vbo-context-menu-entry-success' : 'vbo-context-menu-entry-danger'; ?>',
1625 separator: true,
1626 action: (root, config) => {
1627 // register callback
1628 vbo_action_ignore_ai_autorg(<?php echo ($ai_auto_guest_review_opt['ignore'] ?? 0); ?>);
1629 },
1630 }
1631 ],
1632 });
1633
1634 });
1635 </script>
1636 <?php
1637 }
1638 }
1639
1640 if ($invoiced) {
1641 foreach ($invoice_details as $invoice_detail) {
1642 ?>
1643 <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-invoice">
1644 <span class="label label-success">
1645 <span><?php echo $invoice_detail['label'] ?? JText::translate('VBOCOLORTAGRULEINVONE'); ?></span>
1646 <span class="badge"><a href="<?php echo $invoice_detail['uri'] . (strpos($invoice_detail['uri'], '?') === false ? '?' . rand() . '=1' : ''); ?>" target="_blank"><?php VikBookingIcons::e('download'); ?> <?php echo $invoice_detail['btn'] ?? JText::translate('VBOINVDOWNLOAD'); ?></a></span>
1647 </span>
1648 </div>
1649 <?php
1650 }
1651 }
1652 if ($this->vcm_review) {
1653 ?>
1654 <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-review">
1655 <span class="label label-warning" onclick="VBOCore.handleDisplayWidgetNotification({widget_id: 'guest_reviews'}, {review_id: '<?php echo $this->vcm_review['id']; ?>'});">
1656 <a href="javascript: void(0);" style="color: #fff;"><i class="vboicn-star-full"></i> <?php echo JText::translate('VBOSEEGUESTREVIEW'); ?></a>
1657 </span>
1658 </div>
1659 <?php
1660 // check if a notification was clicked
1661 if (VikRequest::getString('notif_action', '', 'request') == 'see_guest_review') {
1662 $vcm_review_link = VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikchannelmanager&task=reviews&revid=' . $this->vcm_review['id'], false);
1663 $vcm_review_id = $this->vcm_review['id'];
1664 JFactory::getDocument()->addScriptDeclaration(
1665 <<<JS
1666 jQuery(function() {
1667 setTimeout(() => {
1668 // document.location.href = '$vcm_review_link';
1669 VBOCore.handleDisplayWidgetNotification({widget_id: 'guest_reviews'}, {review_id: '$vcm_review_id'});
1670 }, 200);
1671 });
1672 JS
1673 );
1674 }
1675 }
1676 ?>
1677
1678 <!-- Define role to detect the supported hook -->
1679 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"invoice","type":"field"} -->
1680
1681 <?php
1682 if (isset($bookingSidebarForms['invoice'])) {
1683 echo $bookingSidebarForms['invoice'];
1684 }
1685 ?>
1686
1687 </div>
1688 <?php
1689 }
1690 if (!$printreceipt && $row['closure'] < 1) {
1691 ?>
1692 <div class="vbo-bookingdet-detcont vbo-hidein-print">
1693 <div class="vbo-bookingdet-lblcont">
1694 <label for="custmail"><?php echo JText::translate('VBCUSTEMAIL'); ?></label>
1695 </div>
1696 <div class="vbo-bookingdet-inpwrap">
1697 <div class="vbo-bookingdet-inpcont">
1698 <input type="text" name="custmail" id="custmail" value="<?php echo $this->escape($row['custmail']); ?>" size="25" onkeyup="vboKeyupEmail(event);"/>
1699 <div class="vbo-bookingdet-btncont vbo-bookingdet-save-email" style="display: none;">
1700 <button type="button" class="btn btn-success" onclick="document.adminForm.submit();"><?php VikBookingIcons::e('save'); ?> <?php echo JText::translate('VBSAVE'); ?></button>
1701 </div>
1702 </div>
1703 <?php if (!empty($row['custmail'])) : ?>
1704 <div class="vbo-bookingdet-btncont">
1705 <button type="button" class="btn vbo-config-btn" onclick="vboDisplaySendEmail();" style="vertical-align: top;"><?php VikBookingIcons::e('envelope'); ?> <?php echo JText::translate('VBSENDEMAILACTION'); ?></button>
1706 </div>
1707 <?php endif; ?>
1708 </div>
1709
1710 <!-- Define role to detect the supported hook -->
1711 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"email","type":"field"} -->
1712
1713 <?php
1714 if (isset($bookingSidebarForms['email'])) {
1715 echo $bookingSidebarForms['email'];
1716 }
1717 ?>
1718
1719 </div>
1720 <div class="vbo-bookingdet-detcont vbo-hidein-print">
1721 <div class="vbo-bookingdet-lblcont">
1722 <label for="custphone"><?php echo JText::translate('VBCUSTOMERPHONE'); ?></label>
1723 </div>
1724 <div class="vbo-bookingdet-inpwrap">
1725 <div class="vbo-bookingdet-inpcont">
1726 <?php echo $vbo_app->printPhoneInputField(array('name' => 'custphone', 'id' => 'custphone', 'value' => $this->escape($row['phone'])), array('nationalMode' => false, 'fullNumberOnBlur' => true)); ?>
1727 </div>
1728 <?php
1729 if (!empty($row['phone'])) {
1730 if ($messagingAccountConfigurations) {
1731 // send a message to the guest phone number through the messaging API account(s) configured
1732 ?>
1733 <div class="vbo-bookingdet-btncont">
1734 <button type="button" class="btn vbo-config-btn vbo-bookingdet-send-tplmessage-btn" style="vertical-align: top;"><?php VikBookingIcons::e('paper-plane'); ?> <?php echo JText::translate('VBO_SEND_MESSAGE'); ?></button>
1735 </div>
1736 <?php
1737 } else {
1738 // fallback onto SMS
1739 ?>
1740 <div class="vbo-bookingdet-btncont">
1741 <button type="button" class="btn vbo-config-btn" onclick="vboDisplaySendSMS();" style="vertical-align: top;"><?php VikBookingIcons::e('comment-dots'); ?> <?php echo JText::translate('VBSENDSMSACTION'); ?></button>
1742 </div>
1743 <?php
1744 }
1745 }
1746 ?>
1747 </div>
1748
1749 <!-- Define role to detect the supported hook -->
1750 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"phone","type":"field"} -->
1751
1752 <?php
1753 if (isset($bookingSidebarForms['phone'])) {
1754 echo $bookingSidebarForms['phone'];
1755 }
1756 ?>
1757
1758 </div>
1759
1760 <!-- Define role to detect the supported hook -->
1761 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","type":"fieldset"} -->
1762
1763 <?php
1764 foreach ($bookingSidebarForms as $legend => $form) {
1765 if (in_array($legend, ['userdetails', 'invoice', 'email', 'phone'])) {
1766 // skip default forms
1767 continue;
1768 }
1769 ?>
1770 <div class="vbo-bookingdet-detcont vbo-hidein-print">
1771 <h3><?php echo JText::translate($legend); ?></h3>
1772
1773 <?php echo $form; ?>
1774 </div>
1775 <?php
1776 }
1777 ?>
1778
1779 <?php
1780 }
1781 ?>
1782 </div>
1783
1784 <?php
1785 $all_id_prices = array();
1786 $used_indexes_map = array();
1787 ?>
1788 <div class="vbo-bookingdet-summary">
1789 <div class="table-responsive">
1790 <table class="table">
1791 <?php
1792 // room stay dates in case of split stay (or modified room nights)
1793 $room_stay_dates = [];
1794 $room_stay_records = [];
1795 if ($row['split_stay']) {
1796 if ($row['status'] == 'confirmed') {
1797 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($row['id']);
1798 } else {
1799 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $row['id'], []);
1800 }
1801 } elseif (!$row['split_stay'] && $row['roomsnum'] > 1 && $row['days'] > 1 && $row['status'] == 'confirmed') {
1802 // load the occupied stay dates for each room in case they were modified
1803 $room_stay_records = $av_helper->loadSplitStayBusyRecords($row['id']);
1804 }
1805
1806 // parse all rooms booked
1807 foreach ($rooms as $ind => $or) {
1808 $num = $ind + 1;
1809 $room_icon = $row['split_stay'] && $ind > 0 ? 'random' : 'bed';
1810 $room_stay_nights = $row['days'];
1811 ?>
1812 <tr class="vbo-bookingdet-summary-room">
1813 <td class="vbo-bookingdet-summary-room-firstcell">
1814 <div class="vbo-bookingdet-summary-room-wrap">
1815 <div class="vbo-bookingdet-summary-roomnum"><?php VikBookingIcons::e($room_icon); ?> <?php echo JText::translate('VBEDITORDERTHREE').' '.$num; ?></div>
1816 <?php
1817 // Room Specific Unit
1818 if ((!$row['closure'] || ($row['closure'] && count($rooms) === 1) && !empty($or['roomindex'])) && $row['status'] == "confirmed" && !empty($or['params'])) {
1819 $room_params = json_decode($or['params'], true);
1820 $arr_features = array();
1821 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
1822 if (is_array($room_params) && array_key_exists('features', $room_params) && !empty($room_params['features'])) {
1823 foreach ($room_params['features'] as $rind => $rfeatures) {
1824 if (in_array($rind, $unavailable_indexes) || (isset($used_indexes_map[$or['idroom']]) && in_array($rind, $used_indexes_map[$or['idroom']]))) {
1825 continue;
1826 }
1827 foreach ($rfeatures as $fname => $fval) {
1828 if (strlen($fval)) {
1829 $arr_features[$rind] = '#'.$rind.' - '.JText::translate($fname).': '.$fval;
1830 break;
1831 }
1832 }
1833 }
1834 }
1835 if ($arr_features) {
1836 // $or['id'] equals to the ID of each matching record in _ordersrooms
1837 ?>
1838 <div class="vbo-bookingdet-summary-roomnum-chunit">
1839 <?php echo !$printreceipt ? $vbo_app->getNiceSelect($arr_features, $or['roomindex'], 'roomindex['.$or['id'].']', JText::translate('VBOFEATASSIGNUNIT'), JText::translate('VBOFEATASSIGNUNITEMPTY'), '', 'document.adminForm.submit();', $or['id']) : (!empty($or['roomindex']) && isset($arr_features[$or['roomindex']]) ? $arr_features[$or['roomindex']] : ''); ?>
1840 </div>
1841 <?php
1842 if (!empty($or['idroom']) && !empty($or['roomindex'])) {
1843 if (!array_key_exists($or['idroom'], $used_indexes_map)) {
1844 $used_indexes_map[$or['idroom']] = array();
1845 }
1846 $used_indexes_map[$or['idroom']][] = $or['roomindex'];
1847 }
1848 }
1849 }
1850 //
1851 ?>
1852 </div>
1853 <div class="vbo-bookingdet-summary-roomguests">
1854 <?php VikBookingIcons::e('male'); ?>
1855 <div class="vbo-bookingdet-summary-roomadults">
1856 <span><?php echo JText::translate('VBEDITORDERADULTS'); ?>:</span> <?php echo $arrpeople[$num]['adults']; ?>
1857 </div>
1858 <?php
1859 if ($arrpeople[$num]['children'] > 0) {
1860 $age_str = '';
1861 if (!empty($arrpeople[$num]['children_age'])) {
1862 $json_child = json_decode($arrpeople[$num]['children_age'], true);
1863 if (is_array($json_child) && isset($json_child['age']) && is_array($json_child['age']) && $json_child['age']) {
1864 $age_str = ' '.JText::sprintf('VBORDERCHILDAGES', implode(', ', $json_child['age']));
1865 }
1866 }
1867 ?>
1868 <div class="vbo-bookingdet-summary-roomchildren">
1869 <span><?php echo JText::translate('VBEDITORDERCHILDREN'); ?>:</span> <?php echo $arrpeople[$num]['children'].$age_str; ?>
1870 </div>
1871 <?php
1872 }
1873 if ($arrpeople[$num]['pets'] > 0) {
1874 ?>
1875 <div class="vbo-bookingdet-summary-roompets">
1876 <span><?php VikBookingIcons::e('dog'); ?> <?php echo JText::translate('VBO_PETS'); ?>:</span> <?php echo $arrpeople[$num]['pets']; ?>
1877 </div>
1878 <?php
1879 }
1880 ?>
1881 </div>
1882 <?php
1883 if (!empty($arrpeople[$num]['t_first_name'])) {
1884 ?>
1885 <div class="vbo-bookingdet-summary-guestname">
1886 <span><?php echo $arrpeople[$num]['t_first_name'].' '.$arrpeople[$num]['t_last_name']; ?></span>
1887 </div>
1888 <?php
1889 }
1890 ?>
1891 </td>
1892 <td>
1893 <div class="vbo-bookingdet-summary-roomname"><?php echo $or['name']; ?></div>
1894 <div class="vbo-bookingdet-summary-roomrate">
1895 <?php
1896 $active_rplan_id = 0;
1897 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
1898 if (!empty($or['pkg_name'])) {
1899 //package
1900 echo $or['pkg_name'];
1901 } else {
1902 //custom cost can have an OTA Rate Plan name
1903 if (!empty($or['otarplan'])) {
1904 echo ucwords($or['otarplan']);
1905 } else {
1906 echo JText::translate('VBOROOMCUSTRATEPLAN');
1907 }
1908 }
1909 } elseif (!empty($tars[$num]) && !empty($tars[$num][0]['idprice'])) {
1910 $active_rplan_id = $tars[$num][0]['idprice'];
1911 $all_id_prices[] = $tars[$num][0]['idprice'];
1912 echo VikBooking::getPriceName($tars[$num][0]['idprice']);
1913 if (!empty($tars[$num][0]['attrdata'])) {
1914 ?>
1915 <div>
1916 <?php echo VikBooking::getPriceAttr($tars[$num][0]['idprice']).": ".$tars[$num][0]['attrdata']; ?>
1917 </div>
1918 <?php
1919 }
1920 } elseif (!empty($or['otarplan'])) {
1921 echo ucwords($or['otarplan']);
1922 } elseif ($row['closure'] < 1) {
1923 echo JText::translate('VBOROOMNORATE');
1924 }
1925 ?>
1926 </div>
1927 <?php
1928 // meals included in the room rate
1929 if (!empty($or['meals'])) {
1930 // display included meals defined at room-reservation record
1931 $included_meals = VBOMealplanManager::getInstance()->roomRateIncludedMeals($or);
1932 } else {
1933 // fetch default included meals in the selected rate plan
1934 $included_meals = $active_rplan_id ? VBOMealplanManager::getInstance()->ratePlanIncludedMeals($active_rplan_id) : [];
1935 }
1936 if (!$included_meals && empty($or['meals']) && !empty($row['idorderota']) && !empty($row['channel']) && !empty($row['custdata'])) {
1937 // attempt to fetch the included meal plans from the raw customer data or OTA reservation and room
1938 $included_meals = VBOMealplanManager::getInstance()->otaDataIncludedMeals($row, $or);
1939 }
1940 if ($included_meals) {
1941 ?>
1942 <div class="vbo-bookingdet-summary-roomrate vbo-bookingdet-summary-roommeals vbo-wider-badges-wrap">
1943 <?php
1944 foreach ($included_meals as $included_meal) {
1945 ?>
1946 <span class="badge badge-info"><?php echo $included_meal; ?></span>
1947 <?php
1948 }
1949 ?>
1950 </div>
1951 <?php
1952 }
1953
1954 if ($row['split_stay'] && $room_stay_dates && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
1955 // print split stay information for this room
1956 $room_stay_checkin = !empty($room_stay_dates[$ind]['checkin_ts']) ? $room_stay_dates[$ind]['checkin_ts'] : $room_stay_dates[$ind]['checkin'];
1957 $room_stay_checkout = !empty($room_stay_dates[$ind]['checkout_ts']) ? $room_stay_dates[$ind]['checkout_ts'] : $room_stay_dates[$ind]['checkout'];
1958 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
1959 ?>
1960 <div class="vbo-cal-splitstay-details vbo-bookdet-splitstay-details">
1961 <div class="vbo-cal-splitstay-dates">
1962 <span class="vbo-cal-splitstay-room-nights"><?php VikBookingIcons::e('moon'); ?> <?php echo $room_stay_nights . ' ' . ($room_stay_nights > 1 ? JText::translate('VBDAYS') : JText::translate('VBDAY')); ?></span>
1963 <span class="vbo-cal-splitstay-dates-in" title="<?php echo date('H:i', $room_stay_checkin); ?>"><?php VikBookingIcons::e('plane-arrival'); ?> <?php echo date(str_replace("/", $datesep, $df), $room_stay_checkin); ?></span>
1964 <span class="vbo-cal-splitstay-dates-out" title="<?php echo date('H:i', $room_stay_checkout); ?>"><?php VikBookingIcons::e('plane-departure'); ?> <?php echo date(str_replace("/", $datesep, $df), $room_stay_checkout); ?></span>
1965 </div>
1966 </div>
1967 <?php
1968 } elseif (!$row['split_stay'] && $room_stay_records && isset($room_stay_records[$ind]) && $room_stay_records[$ind]['idroom'] == $or['idroom']) {
1969 // print modified stay dates information for this room
1970 $room_stay_checkin = $room_stay_records[$ind]['checkin'];
1971 $room_stay_checkout = $room_stay_records[$ind]['checkout'];
1972 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
1973 if ($room_stay_checkin != $row['checkin'] || $room_stay_checkout != $row['checkout']) {
1974 ?>
1975 <div class="vbo-cal-splitstay-details vbo-bookdet-splitstay-details vbo-bookdet-roomdatesmod-details">
1976 <div class="vbo-cal-splitstay-dates">
1977 <span class="vbo-cal-splitstay-room-nights"><?php VikBookingIcons::e('moon'); ?> <?php echo $room_stay_nights . ' ' . ($room_stay_nights > 1 ? JText::translate('VBDAYS') : JText::translate('VBDAY')); ?></span>
1978 <span class="vbo-cal-splitstay-dates-in" title="<?php echo date('H:i', $room_stay_checkin); ?>"><?php VikBookingIcons::e('plane-arrival'); ?> <?php echo date(str_replace("/", $datesep, $df), $room_stay_checkin); ?></span>
1979 <span class="vbo-cal-splitstay-dates-out" title="<?php echo date('H:i', $room_stay_checkout); ?>"><?php VikBookingIcons::e('plane-departure'); ?> <?php echo date(str_replace("/", $datesep, $df), $room_stay_checkout); ?></span>
1980 </div>
1981 </div>
1982 <?php
1983 }
1984 }
1985 ?>
1986 </td>
1987 <td>
1988 <div class="vbo-bookingdet-summary-price">
1989 <?php
1990 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
1991 echo $currencyname.' '.VikBooking::numberFormat($or['cust_cost']);
1992 } elseif (!empty($tars[$num]) && !empty($tars[$num][0]['idprice'])) {
1993 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num][0]['cost'];
1994 echo $currencyname.' '.VikBooking::numberFormat(($after_tax ? VikBooking::sayCostPlusIva($display_rate, $tars[$num][0]['idprice']) : $display_rate));
1995 }
1996 ?>
1997 </div>
1998 </td>
1999 </tr>
2000 <?php
2001 //Options
2002 if (!empty($or['optionals'])) {
2003 $stepo = explode(";", $or['optionals']);
2004 $counter = 0;
2005 foreach ($stepo as $roptkey => $oo) {
2006 if (empty($oo)) {
2007 continue;
2008 }
2009 $stept = explode(":", $oo);
2010 $q = "SELECT * FROM `#__vikbooking_optionals` WHERE `id`=".(int)$stept[0].";";
2011 $dbo->setQuery($q);
2012 $actopt = $dbo->loadAssocList();
2013 if (!$actopt) {
2014 continue;
2015 }
2016
2017 // option params
2018 $opt_params = !empty($actopt[0]['oparams']) ? json_decode($actopt[0]['oparams'], true) : [];
2019 $opt_params = is_array($opt_params) ? $opt_params : [];
2020 if ($opt_params['damagedep'] ?? 0) {
2021 // turn flag on
2022 $booking_has_damage_dep = 1;
2023 }
2024
2025 $counter++;
2026 $chvar = '';
2027 if (!empty($actopt[0]['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
2028 $optagenames = VikBooking::getOptionIntervalsAges($actopt[0]['ageintervals']);
2029 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt[0]['ageintervals']);
2030 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt[0], $or['adults'], $or['children']);
2031 $child_num = VikBooking::getRoomOptionChildNumber($or['optionals'], $actopt[0]['id'], $roptkey, $or['children']);
2032 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt[0]['ageintervals']);
2033 $agestept = explode('-', $stept[1]);
2034 $stept[1] = $agestept[0];
2035 $chvar = $agestept[1];
2036 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
2037 //percentage value of the adults tariff
2038 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
2039 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2040 } else {
2041 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num][0]['cost'];
2042 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
2043 }
2044 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
2045 //VBO 1.10 - percentage value of room base cost
2046 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
2047 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2048 } else {
2049 $display_rate = isset($tars[$num][0]['room_base_cost']) ? $tars[$num][0]['room_base_cost'] : (!empty($or['room_cost']) ? $or['room_cost'] : $tars[$num][0]['cost']);
2050 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
2051 }
2052 }
2053 if (!isset($optagenames[($chvar - 1)])) {
2054 $optagenames[($chvar - 1)] = '';
2055 }
2056 if (!isset($optagecosts[($chvar - 1)])) {
2057 $optagecosts[($chvar - 1)] = 0;
2058 }
2059 $actopt[0]['chageintv'] = $chvar;
2060 $actopt[0]['name'] .= ' ('.$optagenames[($chvar - 1)].')';
2061 $realcost = (intval($actopt[0]['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $room_stay_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
2062 } elseif (is_numeric($stept[1])) {
2063 // VBO 1.11 - options percentage cost of the room total fee
2064 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
2065 $deftar_basecosts = $or['cust_cost'];
2066 } else {
2067 $use_def_tar = isset($tars[$num]) && isset($tars[$num][0]) ? $tars[$num][0]['cost'] : 0;
2068 $deftar_basecosts = !empty($or['room_cost']) ? $or['room_cost'] : $use_def_tar;
2069 }
2070 $actopt[0]['cost'] = (int)$actopt[0]['pcentroom'] ? ($deftar_basecosts * $actopt[0]['cost'] / 100) : $actopt[0]['cost'];
2071 //
2072 $realcost = (intval($actopt[0]['perday']) == 1 ? ($actopt[0]['cost'] * $room_stay_nights * $stept[1]) : ($actopt[0]['cost'] * $stept[1]));
2073 } else {
2074 $realcost = 0;
2075 }
2076 if ($actopt[0]['maxprice'] > 0 && $realcost > $actopt[0]['maxprice']) {
2077 $realcost = $actopt[0]['maxprice'];
2078 if (intval($actopt[0]['hmany']) == 1 && intval($stept[1]) > 1) {
2079 $realcost = $actopt[0]['maxprice'] * $stept[1];
2080 }
2081 }
2082 $realcost = $actopt[0]['perperson'] == 1 ? ($realcost * $arrpeople[$num]['adults']) : $realcost;
2083
2084 /**
2085 * Trigger event to allow third party plugins to apply a custom calculation for the option/extra fee or tax.
2086 *
2087 * @since 1.17.7 (J) - 1.7.7 (WP)
2088 */
2089 $custom_calculation = VBOFactory::getPlatform()->getDispatcher()->filter('onCalculateBookingOptionFeeCost', [$realcost, &$actopt[0], $row, $or]);
2090 if ($custom_calculation) {
2091 $realcost = (float) $custom_calculation[0];
2092 }
2093
2094 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt[0]['idiva']);
2095 ?>
2096 <tr class="vbo-bookingdet-summary-options">
2097 <td class="vbo-bookingdet-summary-options-title"><?php echo $counter == 1 ? JText::translate('VBEDITORDEREIGHT') : '&nbsp;'; ?></td>
2098 <td>
2099 <span class="vbo-bookingdet-summary-lbl"><?php echo ($stept[1] > 1 ? $stept[1]." " : "").$actopt[0]['name']; ?></span>
2100 </td>
2101 <td>
2102 <span class="vbo-bookingdet-summary-cost"><?php echo $currencyname." ".VikBooking::numberFormat(($after_tax ? $tmpopr : $realcost)); ?></span>
2103 </td>
2104 </tr>
2105 <?php
2106 }
2107 }
2108 //Custom extra costs
2109 if (!empty($or['extracosts'])) {
2110 $counter = 0;
2111 $cur_extra_costs = json_decode($or['extracosts'], true);
2112 foreach ($cur_extra_costs as $eck => $ecv) {
2113 $counter++;
2114 $ecv['idtax'] = isset($ecv['idtax']) ? $ecv['idtax'] : 0;
2115 ?>
2116 <tr class="vbo-bookingdet-summary-custcosts">
2117 <td class="vbo-bookingdet-summary-custcosts-title"><?php echo $counter == 1 ? JText::translate('VBPEDITBUSYEXTRACOSTS') : '&nbsp;'; ?></td>
2118 <td>
2119 <?php
2120 if (!empty($ecv['type'])) {
2121 ?>
2122 <span class="vbo-tooltip vbo-tooltip-top" data-tooltiptext="<?php echo JHtml::fetch('esc_attr', JText::translate('VBPSHOWSEASONSTHREE') . ': ' . $ecv['type']); ?>">
2123 <span class="vbo-bookingdet-summary-lbl"><?php echo $ecv['name']; ?></span>
2124 </span>
2125 <?php
2126 } else {
2127 ?>
2128 <span class="vbo-bookingdet-summary-lbl"><?php echo $ecv['name']; ?></span>
2129 <?php
2130 }
2131 ?>
2132 </td>
2133 <td>
2134 <span class="vbo-bookingdet-summary-cost"><?php echo $currencyname." ".VikBooking::numberFormat(($after_tax ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'])); ?></span>
2135 </td>
2136 </tr>
2137 <?php
2138 }
2139 }
2140 }
2141 //vikbooking 1.1 coupon
2142 if (strlen((string)$row['coupon']) > 0) {
2143 $expcoupon = explode(";", $row['coupon']);
2144 ?>
2145 <tr class="vbo-bookingdet-summary-coupon">
2146 <td><?php echo JText::translate('VBCOUPON'); ?></td>
2147 <td>
2148 <span class="vbo-bookingdet-summary-lbl"><?php echo $expcoupon[2]; ?></span>
2149 </td>
2150 <td>
2151 <span class="vbo-bookingdet-summary-cost">- <?php echo $currencyname; ?> <?php echo VikBooking::numberFormat($expcoupon[1]); ?></span>
2152 </td>
2153 </tr>
2154 <?php
2155 }
2156 if ($row['refund'] > 0) {
2157 ?>
2158 <tr class="vbo-bookingdet-summary-totpaid vbo-bookingdet-summary-totrefunded">
2159 <td>
2160 <strong><?php echo JText::translate('VBOBOOKHISTORYTRF'); ?></strong>
2161 </td>
2162 <td>
2163 <span class="vbo-amount-refunded-lbl"><?php echo JText::translate('VBO_AMOUNT_REFUNDED'); ?></span>
2164 </td>
2165 <td>
2166 <div id="vbo-amountrefunded-cont">
2167 <span id="vbo-amountrefunded-current"><?php echo $currencyname.' '.VikBooking::numberFormat($row['refund']); ?></span>
2168 <span id="vbo-amountrefunded-edit" style="margin-left: 5px; cursor: pointer;"><?php VikBookingIcons::e('edit'); ?></span>
2169 </div>
2170 <div id="vbo-amountrefunded-modcont" style="display: none;">
2171 <span id="vbo-amountrefunded-cancedit" style="margin-right: 5px; cursor: pointer;"><?php VikBookingIcons::e('times'); ?></span>
2172 <span id="vbo-amountrefunded-new"><input type="number" step="any" name="newamountrefunded" value="" min="0" style="margin: 0;" placeholder="<?php echo $row['refund']; ?>" disabled /></span>
2173 <span id="vbo-amountrefunded-save"><button type="submit" class="btn btn-success"><?php echo JText::translate('VBAPPLYDISCOUNTSAVE'); ?></button></span>
2174 </div>
2175 </td>
2176 </tr>
2177 <?php
2178 }
2179 //Reservation Total
2180 //Taxes Breakdown (only if tot_taxes is greater than 0)
2181 $tax_breakdown = array();
2182 $base_aliq = 0;
2183 if ($all_id_prices && $row['tot_taxes'] > 0) {
2184 //only last type of price assuming that the tax breakdown is equivalent in case of different rates
2185 $q = "SELECT `p`.`id`,`p`.`name`,`p`.`idiva`,`t`.`aliq`,`t`.`breakdown` FROM `#__vikbooking_prices` AS `p` LEFT JOIN `#__vikbooking_iva` `t` ON `p`.`idiva`=`t`.`id` WHERE `p`.`id`=".intval(array_pop($all_id_prices))." LIMIT 1;";
2186 $dbo->setQuery($q);
2187 $breakdown_info = $dbo->loadAssoc();
2188 if ($breakdown_info) {
2189 if (!empty($breakdown_info['breakdown']) && !empty($breakdown_info['aliq'])) {
2190 $tax_breakdown = json_decode($breakdown_info['breakdown'], true);
2191 $tax_breakdown = is_array($tax_breakdown) && $tax_breakdown ? $tax_breakdown : array();
2192 $base_aliq = $breakdown_info['aliq'];
2193 }
2194 }
2195 }
2196 //
2197 if ($printreceipt && $row['tot_taxes'] > 0) {
2198 // only when printing the receipt we display an additional row for the total amount of tax
2199 ?>
2200 <tr class="vbo-bookingdet-summary-total vbo-bookingdet-summary-totaltax">
2201 <td>
2202
2203 </td>
2204 <td>
2205 <span class="vbo-bookingdet-summary-lbl"><?php echo JText::translate('VBTOTALVAT'); ?></span>
2206 </td>
2207 <td>
2208 <span class="vbo-bookingdet-summary-cost"><?php echo $currencyname; ?> <?php echo VikBooking::numberFormat($row['tot_taxes']); ?></span>
2209 </td>
2210 </tr>
2211 <?php
2212 }
2213 ?>
2214 <tr class="vbo-bookingdet-summary-total">
2215 <td>
2216 <?php
2217 if (!$printreceipt) {
2218 ?>
2219 <span class="vbapplydiscsp" onclick="toggleDiscount(this);">
2220 <i class="<?php echo VikBookingIcons::i('chevron-down'); ?>" title="<?php echo htmlspecialchars(JText::translate('VBAPPLYDISCOUNT')); ?>"></i>
2221 </span>
2222 <?php
2223 }
2224 ?>
2225 </td>
2226 <td>
2227 <span class="vbo-bookingdet-summary-lbl"><?php echo JText::translate('VBEDITORDERNINE'); ?></span>
2228
2229 <div class="vbdiscenter" id="vbdiscenter" style="display: none;">
2230 <div class="vbdiscenter-entry">
2231 <span class="vbdiscenter-label"><?php echo JText::translate('VBTOTALVAT'); ?>:</span><span class="vbdiscenter-value"><?php echo $currencyname; ?> <input type="number" step="any" name="tot_taxes" value="<?php echo $row['tot_taxes']; ?>" size="4"/></span>
2232 </div>
2233 <?php
2234 if ($tax_breakdown) {
2235 foreach ($tax_breakdown as $tbkk => $tbkv) {
2236 $tax_break_cost = $row['tot_taxes'] * floatval($tbkv['aliq']) / $base_aliq;
2237 ?>
2238 <div class="vbdiscenter-entry vbdiscenter-entry-breakdown">
2239 <span class="vbdiscenter-label"><?php echo $tbkv['name']; ?>:</span><span class="vbdiscenter-value"><?php echo $currencyname; ?> <?php echo VikBooking::numberFormat($tax_break_cost); ?></span>
2240 </div>
2241 <?php
2242 }
2243 }
2244 ?>
2245 <div class="vbdiscenter-entry">
2246 <span class="vbdiscenter-label"><?php echo JText::translate('VBTOTALCITYTAX'); ?>:</span><span class="vbdiscenter-value"><?php echo $currencyname; ?> <input type="number" step="any" name="tot_city_taxes" value="<?php echo $row['tot_city_taxes']; ?>" size="4"/></span>
2247 </div>
2248 <div class="vbdiscenter-entry">
2249 <span class="vbdiscenter-label"><?php echo JText::translate('VBTOTALFEES'); ?>:</span><span class="vbdiscenter-value"><?php echo $currencyname; ?> <input type="number" step="any" name="tot_fees" value="<?php echo $row['tot_fees']; ?>" size="4"/></span>
2250 </div>
2251 <div class="vbdiscenter-entry">
2252 <span class="vbdiscenter-label hasTooltip"<?php echo !empty($otachannel_name) ? ' title="'.$otachannel_name.'"' : ''; ?>><?php echo JText::translate('VBTOTALCOMMISSIONS'); ?>:</span><span class="vbdiscenter-value"><?php echo $currencyname; ?> <input type="number" step="any" name="cmms" value="<?php echo $row['cmms']; ?>" size="4"/></span>
2253 </div>
2254 <?php
2255 if ($booking_has_damage_dep) {
2256 // allow to overwrite (or see) the amount of damage deposit
2257 ?>
2258 <div class="vbdiscenter-entry">
2259 <span class="vbdiscenter-label"><?php echo JText::translate('VBO_DAMAGE_DEPOSIT'); ?>:</span><span class="vbdiscenter-value"><?php echo $currencyname; ?> <input type="number" step="any" name="tot_damage_dep" value="<?php echo $row['tot_damage_dep']; ?>" min="0" size="4"/></span>
2260 </div>
2261 <?php
2262 }
2263 ?>
2264 <div class="vbdiscenter-entry">
2265 <span class="vbdiscenter-label"><?php echo JText::translate('VBAPPLYDISCOUNT'); ?>:</span><span class="vbdiscenter-value"><?php echo $currencyname; ?> <input type="number" step="any" name="admindisc" value="<?php echo isset($expcoupon) ? (float)$expcoupon[1] : ''; ?>" size="4"/></span>
2266 </div>
2267 <div class="vbdiscenter-entrycentered">
2268 <button type="submit" class="btn btn-success"><?php echo JText::translate('VBAPPLYDISCOUNTSAVE'); ?></button>
2269 </div>
2270 </div>
2271 </td>
2272 <td>
2273 <span class="vbo-bookingdet-summary-cost"><?php echo (!empty($otacurrency) && $otacurrency != $currencyname ? '('.$otacurrency.') ' . $currencyname : $currencyname); ?> <?php echo VikBooking::numberFormat($row['total']); ?></span>
2274 <?php
2275 /**
2276 * Display the information about the expected payout, if available and eligible.
2277 *
2278 * @since 1.18.4 (J) - 1.8.4 (WP)
2279 */
2280 if ($row['status'] == 'confirmed' && !empty($row['channel']) && !empty($row['idorderota']) && $row['checkout'] >= $current_ts && !empty($ota_type_data['expected_payout'])) {
2281 ?>
2282 <div class="vbo-bookingdet-exp-payout">
2283 <span class="vbo-bookingdet-exp-payout-lbl"><?php echo JText::translate('VBO_EXPECTED_PAYOUT'); ?></span>
2284 <span class="vbo-bookingdet-exp-payout-txt"><?php
2285 echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($ota_type_data['expected_payout']), (!empty($otacurrency) && $otacurrency != $currencyname ? $otacurrency : $currencysymb));
2286 ?></span>
2287 </div>
2288 <?php
2289 }
2290 ?>
2291 </td>
2292 </tr>
2293 <?php
2294 if ($row['total'] > 0 && !$row['closure']) {
2295 $has_paid = ($row['totpaid'] > 0);
2296 $diff_to_pay = $has_paid ? ($row['total'] - $row['totpaid']) : 0;
2297 if ($diff_to_pay && !empty($row['idorderota']) && !empty($row['channel']) && round($row['cmms'], 2) == round($diff_to_pay, 2)) {
2298 // the outstanding balance is equal to the OTA commissions amount
2299 $diff_to_pay = 0;
2300 }
2301 if ($has_paid || $row['status'] != 'standby') {
2302 ?>
2303 <tr class="vbo-bookingdet-summary-totpaid">
2304 <td>&nbsp;</td>
2305 <td><?php echo JText::translate('VBAMOUNTPAID'); ?></td>
2306 <td>
2307 <div id="vbo-amountpaid-cont">
2308 <span id="vbo-amountpaid-current"><?php echo $has_paid ? ($currencyname . ' ' . VikBooking::numberFormat($row['totpaid'])) : ''; ?></span>
2309 <span id="vbo-amountpaid-edit" style="margin-left: 5px; cursor: pointer;"><?php VikBookingIcons::e('edit'); ?></span>
2310 </div>
2311 <div id="vbo-amountpaid-modcont" style="display: none;">
2312 <span id="vbo-amountpaid-cancedit" style="margin-right: 5px; cursor: pointer;"><?php VikBookingIcons::e('times'); ?></span>
2313 <span id="vbo-amountpaid-new"><input type="number" step="any" name="newamountpaid" value="" min="0" style="margin: 0;" placeholder="<?php echo $has_paid ? $row['totpaid'] : ''; ?>" disabled /></span>
2314 <?php
2315 if ($payments) {
2316 ?>
2317 <span id="vbo-amountpaid-paymeth" style="margin: 0 5px; max-width: 160px;">
2318 <select name="newamountpaymeth" style="margin: 0;">
2319 <option value=""><?php echo JText::translate('VBPAYMENTMETHOD'); ?></option>
2320 <?php
2321 foreach ($payments as $pay) {
2322 ?>
2323 <option value="<?php echo JHtml::fetch('esc_attr', $pay['id'] . '_' . $pay['name']); ?>"><?php echo $pay['name']; ?></option>
2324 <?php
2325 }
2326 ?>
2327 </select>
2328 </span>
2329 <?php
2330 }
2331 ?>
2332 <span id="vbo-amountpaid-save"><button type="submit" class="btn btn-success"><?php echo JText::translate('VBAPPLYDISCOUNTSAVE'); ?></button></span>
2333 </div>
2334 </td>
2335 </tr>
2336 <?php
2337 }
2338 if ($diff_to_pay > 1 && $row['status'] != 'cancelled') {
2339 ?>
2340 <tr class="vbo-bookingdet-summary-totpaid vbo-bookingdet-summary-totremaining">
2341 <td>&nbsp;</td>
2342 <td>
2343 <div><?php echo JText::translate('VBTOTALREMAINING'); ?></div>
2344 <?php
2345 // enable second payment
2346 if (!$printreceipt && $row['status'] == 'confirmed' && !($row['paymcount'] > 0) && VikBooking::multiplePayments() && is_array($payment) && !empty($payment['id'])) {
2347 ?>
2348 <div style="margin-top: 5px;">
2349 <a href="index.php?option=com_vikbooking&amp;task=editorder&amp;makepay=1&amp;cid[]=<?php echo $row['id']; ?>" class="vbo-makepayable-link"><?php VikBookingIcons::e('credit-card'); ?> <?php echo JText::translate('VBMAKEORDERPAYABLE'); ?></a>
2350 </div>
2351 <?php
2352 }
2353 ?>
2354 </td>
2355 <td><?php echo $currencyname . ' ' . VikBooking::numberFormat($diff_to_pay); ?></td>
2356 </tr>
2357 <?php
2358 }
2359 }
2360 if (!$printreceipt && $row['status'] == 'confirmed' && VikBooking::multiplePayments() && is_array($payment) && !empty($payment['id']) && $row['checkout'] > strtotime('-10 days')) {
2361 /**
2362 * The amount payable can be modified by the admin.
2363 *
2364 * @since 1.14 (J) - 1.4.0 (WP)
2365 */
2366 ?>
2367 <tr class="vbo-bookingdet-summary-totpaid vbo-bookingdet-summary-totpayable">
2368 <td>&nbsp;</td>
2369 <td>
2370 <span class="vbo-amount-payable-lbl<?php echo $row['payable'] > 0 ? ' vbo-amount-payable-lbl-requested' : ''; ?>"><?php echo $row['payable'] > 0 ? JText::translate('VBO_AMOUNT_PAYABLE') : JText::translate('VBO_AMOUNT_PAYABLE_RQ'); ?></span>
2371 </td>
2372 <td>
2373 <div id="vbo-amountpayable-cont">
2374 <?php
2375 if ($row['payable'] > 0) {
2376 ?>
2377 <span id="vbo-amountpayable-current"><?php echo $currencyname . ' ' . VikBooking::numberFormat($row['payable']); ?></span>
2378 <?php
2379 }
2380 ?>
2381 <span id="vbo-amountpayable-edit" style="margin-left: 5px; cursor: pointer;"><?php VikBookingIcons::e('edit'); ?></span>
2382 </div>
2383 <div id="vbo-amountpayable-modcont" style="display: none;">
2384 <span id="vbo-amountpayable-cancedit" style="margin-right: 5px; cursor: pointer;"><?php VikBookingIcons::e('times'); ?></span>
2385 <span id="vbo-amountpayable-new"><input type="number" step="any" name="newamountpayable" value="" min="0" style="margin: 0;" placeholder="<?php echo $row['payable']; ?>" disabled /></span>
2386 <span id="vbo-amountpayable-save"><button type="submit" class="btn btn-success"><?php echo JText::translate('VBAPPLYDISCOUNTSAVE'); ?></button></span>
2387 </div>
2388 </td>
2389 </tr>
2390 <?php
2391 }
2392
2393 /**
2394 * Cancellation fee for cancelled bookings after the deadline.
2395 *
2396 * @since 1.16.0 (J) - 1.6.0 (WP)
2397 */
2398 if ($row['status'] == 'cancelled' && !$row['closure'] && $row['total'] > 0) {
2399 ?>
2400 <tr class="vbo-bookingdet-summary-cancfee">
2401 <td>&nbsp;</td>
2402 <td><?php echo JText::translate('VBO_CANC_FEE'); ?></td>
2403 <td>
2404 <div id="vbo-cancfee-cont">
2405 <span id="vbo-cancfee-current"><?php echo $currencyname.' '.VikBooking::numberFormat($row['canc_fee']); ?></span>
2406 <span id="vbo-cancfee-edit" style="margin-left: 5px; cursor: pointer;"><?php VikBookingIcons::e('edit'); ?></span>
2407 </div>
2408 <div id="vbo-cancfee-modcont" style="display: none;">
2409 <span id="vbo-cancfee-cancedit" style="margin-right: 5px; cursor: pointer;"><?php VikBookingIcons::e('times'); ?></span>
2410 <span id="vbo-cancfee-new"><input type="number" step="any" name="newcancfee" value="" min="0" style="margin: 0;" placeholder="<?php echo $row['canc_fee']; ?>" disabled /></span>
2411 <span id="vbo-cancfee-save"><button type="submit" class="btn btn-success"><?php echo JText::translate('VBAPPLYDISCOUNTSAVE'); ?></button></span>
2412 </div>
2413 </td>
2414 </tr>
2415 <?php
2416 }
2417 ?>
2418 </table>
2419 </div>
2420
2421 <!-- Define role to detect the supported hook -->
2422 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorder","type":"fieldset"} -->
2423
2424 <?php
2425 foreach ($bookingPanelForms as $legend => $form)
2426 {
2427 if (in_array($legend, ['buttons']))
2428 {
2429 // skip default forms
2430 continue;
2431 }
2432 ?>
2433 <div class="table-responsive">
2434 <h3><?php echo JText::translate($legend); ?></h3>
2435
2436 <?php echo $form; ?>
2437 </div>
2438 <?php
2439 }
2440 ?>
2441
2442 </div>
2443 </div>
2444 <?php
2445 if ($printreceipt) {
2446 $receipt_notes = VikBooking::getReceiptNotes();
2447 ?>
2448 <div class="vbo-receipt-notes-container">
2449 <div class="vbo-receipt-notes-inner">
2450 <div class="vbo-receipt-notes-val vbo-showin-print" id="vbo-receipt-notes-val"><?php echo $receipt_notes; ?></div>
2451 <div class="vbo-receipt-notes-tarea vbo-hidein-print">
2452 <textarea id="vbo-receipt-notes" placeholder="<?php echo JText::translate('VBORECEIPTNOTESDEF'); ?>"><?php echo htmlspecialchars($receipt_notes); ?></textarea>
2453 </div>
2454 </div>
2455 </div>
2456 <?php
2457 }
2458 ?>
2459 </div>
2460
2461 <div class="vbo-bookingdet-tab-cont" id="vbo-tab-admin" style="display: none;">
2462 <div class="vbo-bookingdet-innercontainer">
2463 <div class="vbo-bookingdet-admindata">
2464 <?php
2465 if (!$row['closure']) {
2466 ?>
2467 <div class="vbo-bookingdet-admin-entry">
2468 <label for="vbo-searchcust"><?php echo JText::translate($customer ? 'VBOASSIGNNEWCUST' : 'VBFILLCUSTFIELDS'); ?></label>
2469 <span style="display: block;"><?php echo JText::translate('VBOSEARCHEXISTCUST'); ?></span>
2470 <span class="vbo-eorder-assigncust" style="margin-bottom: 1px;">
2471 <input type="text" id="vbo-searchcust" autocomplete="off" value="" placeholder="<?php echo JText::translate('VBOSEARCHCUSTBY'); ?>" size="30" style="margin-bottom: 0;" />
2472 </span>
2473 <span id="vbo-searchcust-loading">
2474 <?php VikBookingIcons::e('hourglass-half'); ?>
2475 </span>
2476 <input type="hidden" name="newcustid" id="newcustid" value="" />
2477 <div id="vbo-searchcust-res" style="position: absolute; background-color: #fff;"></div>
2478 <span class="vbo-eorder-assignnewcust" style="display: block; margin-top: 10px;">
2479 <a class="vbo-assign-customer" href="index.php?option=com_vikbooking&task=newcustomer&bid=<?php echo $row['id']; ?>&goto=<?php echo base64_encode($gotouri.'#tab-admin'); ?>">
2480 <?php VikBookingIcons::e('user-circle'); ?>
2481 <span><?php echo JText::translate('VBOCREATENEWCUST'); ?></span>
2482 </a>
2483 </span>
2484
2485 <?php
2486 if (isset($adminSidebarForms['customer']))
2487 {
2488 echo $adminSidebarForms['customer'];
2489 }
2490 ?>
2491
2492 </div>
2493 <?php
2494 }
2495 ?>
2496 <div class="vbo-bookingdet-admin-entry">
2497 <label for="newpayment"><?php echo JText::translate('VBPAYMENTMETHOD'); ?></label>
2498 <?php
2499 if (is_array($payment)) {
2500 ?>
2501 <span><?php echo $payment['name']; ?></span>
2502 <?php
2503 }
2504 $chpayment = '';
2505 if ($payments) {
2506 $chpayment = '<div><select name="newpayment" id="newpayment" onchange="changePayment();"><option value="">- ' . JText::translate('VBCHANGEPAYLABEL') . ' -</option>';
2507 foreach ($payments as $pay) {
2508 $chpayment .= '<option value="' . $pay['id'] . '">' . (is_array($payment) && $payment['id'] == $pay['id'] ? '- ' : '') . $pay['name'] . '</option>';
2509 }
2510 $chpayment .= '</select></div>';
2511 }
2512 echo $chpayment;
2513 ?>
2514
2515 <!-- Define role to detect the supported hook -->
2516 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderAdministrationSidebar","key":"payment","type":"field"} -->
2517
2518 <?php
2519 if (isset($adminSidebarForms['payment']))
2520 {
2521 echo $adminSidebarForms['payment'];
2522 }
2523 ?>
2524
2525 </div>
2526 <?php
2527 $tn = VikBooking::getTranslator();
2528 $all_langs = $tn->getLanguagesList();
2529 if (count($all_langs) > 1) {
2530 ?>
2531 <div class="vbo-bookingdet-admin-entry">
2532 <label for="newlang"><?php echo JText::translate('VBOBOOKINGLANG'); ?></label>
2533 <select name="newlang" id="newlang" onchange="document.adminForm.submit();">
2534 <?php
2535 foreach ($all_langs as $lk => $lv) {
2536 ?>
2537 <option value="<?php echo $lk; ?>"<?php echo $row['lang'] == $lk ? ' selected="selected"' : ''; ?>><?php echo isset($lv['nativeName']) ? $lv['nativeName'] : $lv['name']; ?></option>
2538 <?php
2539 }
2540 ?>
2541 </select>
2542
2543 <!-- Define role to detect the supported hook -->
2544 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderAdministrationSidebar","key":"language","type":"field"} -->
2545
2546 <?php
2547 if (isset($adminSidebarForms['language']))
2548 {
2549 echo $adminSidebarForms['language'];
2550 }
2551 ?>
2552 </div>
2553 <?php
2554 }
2555 ?>
2556
2557 <!-- Define role to detect the supported hook -->
2558 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderAdministrationSidebar","type":"fieldset"} -->
2559
2560 <?php
2561 foreach ($adminSidebarForms as $legend => $form)
2562 {
2563 if (in_array($legend, ['customer', 'payment', 'language']))
2564 {
2565 // skip default forms
2566 continue;
2567 }
2568 ?>
2569 <div class="vbo-bookingdet-admin-entry">
2570 <h3><?php echo JText::translate($legend); ?></h3>
2571
2572 <?php echo $form; ?>
2573 </div>
2574 <?php
2575 }
2576 ?>
2577
2578 </div>
2579 <div class="vbo-bookingdet-noteslogs">
2580 <?php
2581 $history = $history_obj->loadHistory();
2582 ?>
2583 <div class="vbo-bookingdet-noteslogs-btns">
2584 <div class="vbo-bookingdet-noteslogs-btn vbo-bookingdet-noteslogs-btn-active" data-id="notes">
2585 <a href="javascript: void(0);" id="vbo-trig-notes" onclick="javascript: vbToggleNotes(this);">
2586 <?php VikBookingIcons::e('user-lock'); ?>
2587 <span class="vbo-bookingdet-admintab-lbl"><?php echo JText::translate('VBADMINNOTESTOGGLE'); ?></span>
2588 </a>
2589 </div>
2590 <?php
2591 /**
2592 * Initialize chat instance by getting the proper channel name
2593 *
2594 * @since 1.12
2595 */
2596 if (empty($row['channel'])) {
2597 // front-end reservation chat handler
2598 $chat_channel = 'vikbooking';
2599 } else {
2600 $channelparts = explode('_', $row['channel']);
2601 // check if this is a meta search channel
2602 $is_meta_search = false;
2603 if (preg_match("/(customer).*[0-9]$/", $channelparts[0]) || !strcasecmp($channelparts[0], 'googlehotel') || !strcasecmp($channelparts[0], 'googlevr') || !strcasecmp($channelparts[0], 'trivago')) {
2604 $is_meta_search = empty($row['idorderota']);
2605 }
2606 if ($is_meta_search) {
2607 // customer of type sales channel should use front-end reservation chat handler
2608 $chat_channel = 'vikbooking';
2609 } else {
2610 // let the getInstance method validate the channel chat handler
2611 $chat_channel = $row['channel'];
2612 }
2613 }
2614 $messaging = VikBooking::getVcmChatInstance($row['id'], $chat_channel);
2615 //
2616 if (!$printreceipt && !is_null($messaging)) {
2617 ?>
2618 <div class="vbo-bookingdet-noteslogs-btn" data-id="messaging">
2619 <a name="messaging" href="javascript: void(0);" id="vbo-trig-messaging" onclick="javascript: vbToggleMessaging(this);">
2620 <?php VikBookingIcons::e('comment-dots'); ?>
2621 <span class="vbo-bookingdet-admintab-lbl"><?php echo JText::translate('VBO_GUEST_MESSAGING'); ?></span>
2622 </a>
2623 </div>
2624 <?php
2625 }
2626
2627 /**
2628 * Build up a tab to summarize the "takings" for this sole booking in case of relevant events.
2629 *
2630 * @since 1.16.9 (J) - 1.6.9 (WP)
2631 */
2632 $takings = [];
2633 if ($history) {
2634 // payment related events
2635 $h_payment_group = $history_obj->getTypeGroups($group = 'GPM');
2636
2637 // merge default types with 'PU' for the manually set "new amount paid" and with 'RU' (refunded amount updated)
2638 $takings_events = array_unique(array_merge(($h_payment_group['types'] ?? []), ['PU', 'RU']));
2639
2640 // load the relevant events with data
2641 $takings = $history_obj->getEventsWithData($takings_events, null, false);
2642
2643 if ($takings) {
2644 ?>
2645 <div class="vbo-bookingdet-noteslogs-btn pro-feature" data-id="takings">
2646 <a href="javascript: void(0);" id="vbo-trig-bookhistory" onclick="javascript: vbToggleDynamicPanel(this, '#vboextrapanel-takings');">
2647 <?php VikBookingIcons::e('wallet'); ?>
2648 <span class="vbo-bookingdet-admintab-lbl"><?php echo JText::translate('VBO_TAKINGS'); ?></span>
2649 </a>
2650 </div>
2651 <?php
2652 }
2653 }
2654
2655 if ($history) {
2656 ?>
2657 <div class="vbo-bookingdet-noteslogs-btn" data-id="history">
2658 <a href="javascript: void(0);" id="vbo-trig-bookhistory" onclick="javascript: vbToggleHistory(this);">
2659 <?php VikBookingIcons::e('history'); ?>
2660 <span class="vbo-bookingdet-admintab-lbl"><?php echo JText::translate('VBOBOOKHISTORYTAB'); ?></span>
2661 </a>
2662 </div>
2663 <script type="text/javascript">
2664 if (window.location.hash == '#bookhistory') {
2665 setTimeout(function() {
2666 jQuery(".vbo-bookingdet-tab[data-vbotab='vbo-tab-admin']").trigger('click');
2667 vbToggleHistory(document.getElementById('vbo-trig-bookhistory'));
2668 }, 500);
2669 }
2670 </script>
2671 <?php
2672 }
2673 ?>
2674 <div class="vbo-bookingdet-noteslogs-btn pro-feature" data-id="invnotes">
2675 <a href="javascript: void(0);" class="hasTooltip" id="vbo-trig-invnotes" onclick="javascript: vbToggleInvNotes(this);" title="<?php echo addslashes(JText::translate('VBBOOKINGINVNOTESHELP')); ?>">
2676 <?php VikBookingIcons::e('file-invoice'); ?>
2677 <span class="vbo-bookingdet-admintab-lbl"><?php echo JText::translate('VBBOOKINGINVNOTES'); ?></span>
2678 </a>
2679 </div>
2680
2681 <!-- Define role to detect the supported hook -->
2682 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderAdministration","type":"fieldset"} -->
2683
2684 <?php
2685 foreach ($adminPanelForms as $legend => $form)
2686 {
2687 $legendId = preg_replace("/[^a-zA-Z0-9_\-]+/", '', $legend);
2688 ?>
2689 <div class="vbo-bookingdet-noteslogs-btn" data-id="<?php echo $legendId; ?>">
2690 <a href="javascript: void(0);" class="hasTooltip" id="vbo-trig-<?php echo $legendId; ?>" onclick="javascript: vbToggleDynamicPanel(this, '#vboextrapanel-<?php echo $legendId; ?>');">
2691 <?php VikBookingIcons::e(!empty($adminFormsSetup->icons[$legend]) ? $adminFormsSetup->icons[$legend] : 'plug'); ?>
2692 <span class="vbo-bookingdet-admintab-lbl"><?php echo JText::translate($legend); ?></span>
2693 </a>
2694 </div>
2695 <?php
2696 }
2697
2698 if (!empty($row['paymentlog'])) {
2699 $paylogs_lbl = JText::translate('VBPAYMENTLOGTOGGLE');
2700 if ($may_have_cc_details) {
2701 $paylogs_lbl = JText::translate('VBO_CREDIT_CARD');
2702 }
2703 ?>
2704 <div class="vbo-bookingdet-noteslogs-btn" data-id="paylogs">
2705 <a href="javascript: void(0);" id="vbo-trig-paylogs" onclick="javascript: vbToggleLog(this);">
2706 <?php VikBookingIcons::e('credit-card'); ?>
2707 <span class="vbo-bookingdet-admintab-lbl"><?php echo $paylogs_lbl; ?></span>
2708 </a>
2709 <a name="paymentlog" href="javascript: void(0);"></a>
2710 </div>
2711 <?php
2712 }
2713 ?>
2714 </div>
2715 <div class="vbo-bookingdet-noteslogs-cont">
2716 <div id="vbadminnotesdiv" class="vbo-extra-panel" style="display: block;">
2717 <textarea name="adminnotes" class="vbadminnotestarea"><?php echo JHtml::fetch('esc_textarea', (string) $row['adminnotes']); ?></textarea>
2718 <input type="submit" name="updadmnotes" value="<?php echo JText::translate('VBADMINNOTESUPD'); ?>" class="btn btn-success" />
2719 </div>
2720 <?php
2721 if ($takings) {
2722 ?>
2723 <div class="vbo-extra-panel" id="vboextrapanel-takings" style="display: none;">
2724 <div class="vbo-booking-takings-container table-responsive">
2725 <table class="table">
2726 <thead>
2727 <tr class="vbo-booking-takings-firstrow">
2728 <td class="vbo-booking-takings-td-totpaid"><?php echo JText::translate('VBO_TAKINGS'); ?></td>
2729 <td class="vbo-booking-takings-td-date"><?php echo JText::translate('VBOBOOKHISTORYLBLDATE'); ?></td>
2730 <td class="vbo-booking-takings-td-type"><?php echo JText::translate('VBOBOOKHISTORYLBLTYPE'); ?></td>
2731 <td class="vbo-booking-takings-td-fees"><?php echo JText::translate('VBO_PROCESSING_FEES'); ?></td>
2732 <td class="vbo-booking-takings-td-descr"><?php echo JText::translate('VBOBOOKHISTORYLBLDESC'); ?></td>
2733 </tr>
2734 </thead>
2735 <tbody>
2736 <?php
2737 $booking_total_taking = 0;
2738 $booking_total_prfees = 0;
2739 foreach (array_reverse($takings) as $hist) {
2740 // calculate amount paid and description
2741 $tn_amount_paid = 0;
2742 $tn_amount_fees = 0;
2743 $tn_description = strpos((string) $hist['descr'], '<') !== false ? $hist['descr'] : preg_replace("/\R/", ' - ', (string) $hist['descr']);
2744 if (is_object($hist['data'])) {
2745 // calculate amount paid or amount refunded
2746 if (($hist['data']->amount_paid ?? 0)) {
2747 $tn_amount_paid = $hist['data']->amount_paid;
2748 if (in_array($hist['type'], ['RF', 'RU'])) {
2749 // turn the amount paid to negative
2750 $tn_amount_paid = $tn_amount_paid < 0 ? $tn_amount_paid : ($tn_amount_paid - ($tn_amount_paid * 2));
2751 if ($hist['type'] === 'RU' && $hist['data']->amount_paid < 0) {
2752 // this indicates a lower amount refunded, so we double it to make it positive
2753 $tn_amount_paid = abs($hist['data']->amount_paid);
2754 }
2755 }
2756 }
2757
2758 // calculate processing fees, if set and if any
2759 if (($hist['data']->processing_fees ?? 0)) {
2760 $tn_amount_fees += $hist['data']->processing_fees;
2761 }
2762
2763 // build the event description
2764 if (($hist['data']->payment_method ?? '')) {
2765 $tn_description = ucwords($hist['data']->payment_method);
2766 } elseif (($hist['data']->driver ?? '')) {
2767 $tn_description = ucwords(str_replace('_', ' ', basename($hist['data']->driver, '.php')));
2768 }
2769 }
2770
2771 // increase (or decrease) booking total takings and processing fees amounts
2772 $booking_total_taking += $tn_amount_paid;
2773 $booking_total_prfees += $tn_amount_fees;
2774 ?>
2775 <tr class="vbo-booking-takings-row">
2776 <td>
2777 <?php
2778 echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($tn_amount_paid), $currencysymb);
2779 if (!strcasecmp($hist['type'], 'PU')) {
2780 /**
2781 * Allow to edit or delete the history record.
2782 *
2783 * @since 1.16.10 (J) - 1.6.10 (WP)
2784 */
2785 ?>
2786 <div class="vbo-booking-taking-cmds">
2787 <button type="button" class="btn btn-small btn-primary vbo-booking-taking-edit vbo-tooltip vbo-tooltip-top" data-tooltiptext="<?php echo $this->escape(JText::translate('VBMAINPAYMENTSEDIT')); ?>" data-historyid="<?php echo $hist['id']; ?>" data-amount="<?php echo $tn_amount_paid; ?>"><?php VikBookingIcons::e('edit'); ?></button>
2788 <button type="button" class="btn btn-small btn-danger vbo-booking-taking-delete vbo-tooltip vbo-tooltip-top" data-tooltiptext="<?php echo $this->escape(JText::translate('VBELIMINA')); ?>" data-historyid="<?php echo $hist['id']; ?>"><?php VikBookingIcons::e('times-circle'); ?></button>
2789 </div>
2790 <?php
2791 }
2792 ?>
2793 </td>
2794 <td><?php echo JHtml::fetch('date', $hist['dt'], 'Y-m-d H:i:s'); ?></td>
2795 <td><?php echo $history_obj->validType($hist['type'], true); ?></td>
2796 <td><?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($tn_amount_fees), $currencysymb); ?></td>
2797 <td><?php echo $tn_description; ?></td>
2798 </tr>
2799 <?php
2800 }
2801 ?>
2802 </tbody>
2803 <tfoot>
2804 <tr>
2805 <td colspan="2">
2806 <span><?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($booking_total_taking), $currencysymb); ?></span>
2807 </td>
2808 <td></td>
2809 <td>
2810 <span><?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($booking_total_prfees), $currencysymb); ?></span>
2811 </td>
2812 <td>
2813 <button type="button" class="btn btn-small btn-success vbo-takings-addnew"><?php VikBookingIcons::e('plus-circle'); ?> <?php echo JText::translate('VBO_REG_NEW_PAYMENT'); ?></button>
2814 </td>
2815 </tr>
2816 </tfoot>
2817 </table>
2818 </div>
2819
2820 <div class="vbo-eorder-newtaking-helper-wrap" style="display: none;">
2821 <div class="vbo-eorder-newtaking-helper-cont">
2822 <div class="vbo-admin-container vbo-admin-container-full vbo-admin-container-compact">
2823 <div class="vbo-params-wrap">
2824 <div class="vbo-params-container">
2825 <div class="vbo-params-block">
2826 <div class="vbo-param-container">
2827 <div class="vbo-param-label">
2828 <label for="new_taking_amount"><?php echo JText::translate('VBO_CC_AMOUNT'); ?></label>
2829 </div>
2830 <div class="vbo-param-setting">
2831 <div class="vbo-input-currency-wrap">
2832 <span><?php echo $currencysymb; ?></span>
2833 <input type="number" id="new_taking_amount" value="" min="0" max="<?php echo $row['total']; ?>" step="any" />
2834 </div>
2835 <span class="vbo-param-setting-comment">
2836 <?php echo JText::translate('VBOCUSTOMERCMMSONTOTAL') . ' ' . VikBooking::formatCurrencyNumber(VikBooking::numberFormat($row['total']), $currencysymb) . ' - ' . JText::translate('VBAMOUNTPAID') . ' ' . VikBooking::formatCurrencyNumber(VikBooking::numberFormat($row['totpaid']), $currencysymb); ?>
2837 </span>
2838 </div>
2839 </div>
2840 <div class="vbo-param-container">
2841 <div class="vbo-param-label">
2842 <label for="new_taking_descr"><?php echo JText::translate('VBLIBPAYNAME'); ?></label>
2843 </div>
2844 <div class="vbo-param-setting">
2845 <select id="new_taking_payid">
2846 <option value="">&nbsp;</option>
2847 <?php
2848 foreach ($this->payments as $paymeth) {
2849 ?>
2850 <option value="<?php echo $paymeth['id']; ?>"><?php echo $paymeth['name']; ?></option>
2851 <?php
2852 }
2853 ?>
2854 </select>
2855 </div>
2856 </div>
2857 <div class="vbo-param-container vbo-param-nested" id="vbo-new-taking-custom-wrap">
2858 <div class="vbo-param-label">&nbsp;</div>
2859 <div class="vbo-param-setting">
2860 <input id="new_taking_descr" type="text" value="" maxlength="200" placeholder="<?php echo $this->escape(JText::translate('VBPVIEWOPTIONALSTWO')); ?>" />
2861 </div>
2862 </div>
2863 </div>
2864 </div>
2865 </div>
2866 </div>
2867 </div>
2868 </div>
2869
2870 </div>
2871
2872 <script type="text/javascript">
2873 jQuery(function() {
2874
2875 jQuery('#new_taking_payid').on('change', function() {
2876 if (jQuery(this).val()) {
2877 jQuery('#vbo-new-taking-custom-wrap').hide();
2878 jQuery('#new_taking_descr').val('');
2879 } else {
2880 jQuery('#vbo-new-taking-custom-wrap').show();
2881 }
2882 });
2883
2884 jQuery('.vbo-takings-addnew').on('click', function() {
2885 // build modal buttons
2886 let footer_left = jQuery('<button></button>');
2887 footer_left.addClass('btn');
2888 footer_left.attr('type', 'button');
2889 footer_left.text(Joomla.JText._('VBANNULLA'));
2890 footer_left.on('click', function() {
2891 // dismiss the modal
2892 VBOCore.emitEvent('vbo-eorder-new-taking-dismiss');
2893 });
2894
2895 let footer_right = jQuery('<button></button>');
2896 footer_right.addClass('btn btn-success');
2897 footer_right.attr('type', 'button');
2898 footer_right.text(Joomla.JText._('VBSAVE'));
2899 footer_right.on('click', function() {
2900 // disable button to prevent double submissions
2901 let submit_btn = jQuery(this);
2902 submit_btn.prop('disabled', true);
2903 // make the request
2904 VBOCore.doAjax(
2905 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=bookings.add_taking'); ?>",
2906 {
2907 bid: '<?php echo $row['id']; ?>',
2908 amount: jQuery('#new_taking_amount').val(),
2909 payid: jQuery('#new_taking_payid').val(),
2910 descr: jQuery('#new_taking_descr').val(),
2911 },
2912 (success) => {
2913 // dismiss the modal
2914 VBOCore.emitEvent('vbo-eorder-new-taking-dismiss');
2915 // reload the page by following the response URL
2916 document.location.href = success.url;
2917 },
2918 (error) => {
2919 // re-enable submit button
2920 submit_btn.prop('disabled', false);
2921 // display error message
2922 alert(error.responseText);
2923 }
2924 );
2925 });
2926
2927 // display modal
2928 let modal_body = VBOCore.displayModal({
2929 suffix: 'vbo-new-taking',
2930 extra_class: 'vbo-modal-rounded vbo-modal-dialog',
2931 title: Joomla.JText._('VBO_REG_NEW_PAYMENT'),
2932 body: '',
2933 body_prepend: true,
2934 footer_left: footer_left,
2935 footer_right: footer_right,
2936 draggable: true,
2937 dismiss_event: 'vbo-eorder-new-taking-dismiss',
2938 onDismiss: () => {
2939 jQuery('.vbo-eorder-newtaking-helper-cont').appendTo(
2940 jQuery('.vbo-eorder-newtaking-helper-wrap')
2941 );
2942 },
2943 });
2944
2945 // reset helper input values
2946 jQuery('#new_taking_amount').val('');
2947 jQuery('#new_taking_payid').prop('disabled', false).val('').trigger('change');
2948 jQuery('#new_taking_descr').val('');
2949
2950 // append modal body
2951 jQuery('.vbo-eorder-newtaking-helper-cont').appendTo(modal_body);
2952 });
2953
2954 jQuery('.vbo-booking-taking-edit').on('click', function() {
2955 let edit_btn = jQuery(this);
2956 let history_id = edit_btn.attr('data-historyid');
2957 let curr_amount_paid = edit_btn.attr('data-amount');
2958 let curr_pay_descr = edit_btn.closest('tr.vbo-booking-takings-row').find('td').last().text();
2959
2960 // build modal buttons
2961 let footer_left = jQuery('<button></button>');
2962 footer_left.addClass('btn');
2963 footer_left.attr('type', 'button');
2964 footer_left.text(Joomla.JText._('VBANNULLA'));
2965 footer_left.on('click', function() {
2966 // dismiss the modal
2967 VBOCore.emitEvent('vbo-eorder-edit-taking-dismiss');
2968 });
2969
2970 let footer_right = jQuery('<button></button>');
2971 footer_right.addClass('btn btn-success');
2972 footer_right.attr('type', 'button');
2973 footer_right.text(Joomla.JText._('VBO_UPDATE_PAYMENT'));
2974 footer_right.on('click', function() {
2975 // disable button to prevent double submissions
2976 let submit_btn = jQuery(this);
2977 submit_btn.prop('disabled', true);
2978 // make the request
2979 VBOCore.doAjax(
2980 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=bookings.update_taking'); ?>",
2981 {
2982 bid: '<?php echo $row['id']; ?>',
2983 hid: history_id,
2984 amount: jQuery('#new_taking_amount').val(),
2985 descr: jQuery('#new_taking_descr').val(),
2986 htype: 'PU',
2987 },
2988 (success) => {
2989 // dismiss the modal
2990 VBOCore.emitEvent('vbo-eorder-edit-taking-dismiss');
2991 // reload the page by following the response URL
2992 document.location.href = success.url;
2993 },
2994 (error) => {
2995 // re-enable submit button
2996 submit_btn.prop('disabled', false);
2997 // display error message
2998 alert(error.responseText);
2999 }
3000 );
3001 });
3002
3003 // display modal
3004 let modal_body = VBOCore.displayModal({
3005 suffix: 'vbo-edit-taking',
3006 extra_class: 'vbo-modal-rounded vbo-modal-dialog',
3007 title: Joomla.JText._('VBO_UPDATE_PAYMENT'),
3008 body: '',
3009 body_prepend: true,
3010 footer_left: footer_left,
3011 footer_right: footer_right,
3012 draggable: true,
3013 dismiss_event: 'vbo-eorder-edit-taking-dismiss',
3014 onDismiss: () => {
3015 jQuery('.vbo-eorder-newtaking-helper-cont').appendTo(
3016 jQuery('.vbo-eorder-newtaking-helper-wrap')
3017 );
3018 },
3019 });
3020
3021 // populate helper input values
3022 jQuery('#new_taking_amount').val(curr_amount_paid);
3023 jQuery('#new_taking_payid').val('').trigger('change').prop('disabled', true);
3024 jQuery('#new_taking_descr').val(curr_pay_descr);
3025
3026 // append modal body
3027 jQuery('.vbo-eorder-newtaking-helper-cont').appendTo(modal_body);
3028 });
3029
3030 jQuery('.vbo-booking-taking-delete').on('click', function() {
3031 if (!confirm(Joomla.JText._('VBDELCONFIRM'))) {
3032 return false;
3033 }
3034 let del_btn = jQuery(this);
3035 del_btn.prop('disabled', true);
3036 let history_id = del_btn.attr('data-historyid');
3037 // make the request
3038 VBOCore.doAjax(
3039 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=bookings.delete_history_record'); ?>",
3040 {
3041 bid: '<?php echo $row['id']; ?>',
3042 hid: history_id,
3043 htype: 'PU',
3044 },
3045 (success) => {
3046 // reload the page by following the response URL
3047 document.location.href = success.url;
3048 },
3049 (error) => {
3050 // re-enable delete button
3051 del_btn.prop('disabled', false);
3052 // display error message
3053 alert(error.responseText);
3054 }
3055 );
3056 });
3057
3058 });
3059 </script>
3060 <?php
3061 }
3062 if ($history) {
3063 ?>
3064 <div id="vbhistorydiv" class="vbo-extra-panel" style="display: none;">
3065 <div class="vbo-booking-history-container table-responsive">
3066 <table class="table">
3067 <thead>
3068 <tr class="vbo-booking-history-firstrow">
3069 <td class="vbo-booking-history-td-type"><?php echo JText::translate('VBOBOOKHISTORYLBLTYPE'); ?></td>
3070 <td class="vbo-booking-history-td-date"><?php echo JText::translate('VBOBOOKHISTORYLBLDATE'); ?></td>
3071 <td class="vbo-booking-history-td-descr"><?php echo JText::translate('VBOBOOKHISTORYLBLDESC'); ?></td>
3072 <td class="vbo-booking-history-td-totpaid"><?php echo JText::translate('VBOBOOKHISTORYLBLTPAID'); ?></td>
3073 <td class="vbo-booking-history-td-tot"><?php echo JText::translate('VBOBOOKHISTORYLBLTOT'); ?></td>
3074 </tr>
3075 </thead>
3076 <tbody>
3077 <?php
3078 foreach ($history as $hist) {
3079 $hdescr = strpos((string) $hist['descr'], '<') !== false ? $hist['descr'] : nl2br((string) $hist['descr']);
3080 ?>
3081 <tr class="vbo-booking-history-row">
3082 <td><?php echo $history_obj->validType($hist['type'], true); ?></td>
3083 <td><?php echo JHtml::fetch('date', $hist['dt'], 'Y-m-d H:i:s'); ?></td>
3084 <td><?php echo $hdescr; ?></td>
3085 <td><?php echo $currencyname.' '.VikBooking::numberFormat($hist['totpaid']); ?></td>
3086 <td><?php echo $currencyname.' '.VikBooking::numberFormat($hist['total']); ?></td>
3087 </tr>
3088 <?php
3089 }
3090 ?>
3091 </tbody>
3092 </table>
3093 </div>
3094 </div>
3095 <?php
3096 }
3097 ?>
3098 <div id="vbinvnotesdiv" class="vbo-extra-panel" style="display: none;">
3099 <textarea name="invnotes" id="invnotes" class="vbadminnotestarea"><?php echo $row['inv_notes']; ?></textarea>
3100 <input type="submit" name="updinvnotes" value="<?php echo JText::translate('VBADMINNOTESUPD'); ?>" class="btn btn-success" />
3101 <button type="button" class="btn vbo-config-btn btn-secondary pull-right" onclick="document.getElementById('invnotes-hid').value=document.getElementById('invnotes').value;document.getElementById('vbo-gen-invoice').submit();"><?php VikBookingIcons::e('file-invoice'); ?> <?php echo JText::translate('VBOGENBOOKINGINVOICE'); ?></button>
3102 </div>
3103 <?php
3104 if (!empty($row['paymentlog'])) {
3105 ?>
3106 <div id="vbpaymentlogdiv" class="vbo-extra-panel" style="display: none;">
3107 <div class="vbo-eorder-paymentlog-buttons">
3108 <?php
3109 // PCI Data Retrieval
3110 $cc_acl_denied = false;
3111 if (!empty($row['idorderota']) && !empty($row['channel'])) {
3112 $channel_source = $row['channel'];
3113 if (strpos($row['channel'], '_') !== false) {
3114 $channelparts = explode('_', $row['channel']);
3115 $channel_source = $channelparts[0];
3116 }
3117 $checkout_info = getdate($row['checkout']);
3118
3119 // validate ACL for credit card details
3120 if (!$canDo->authorise('core.admin', 'com_vikchannelmanager')) {
3121 // permissions to access VCM are required
3122 $cc_acl_denied = true;
3123 ?>
3124 <p class="err"><?php echo JText::translate('JERROR_ALERTNOAUTHOR'); ?></p>
3125 <?php
3126 } else {
3127 /**
3128 * Limit for accessing the credit card details has been changed to check-out
3129 * day at 23:59:59 + 10 extra days. It used to be at 23:59:59 on check-out day.
3130 *
3131 * @since 1.13
3132 */
3133 $cardlimit = mktime(23, 59, 59, $checkout_info['mon'], ($checkout_info['mday'] + 10), $checkout_info['year']);
3134 if ($current_ts < $cardlimit && $may_have_cc_details) {
3135 // log contains credit card details
3136 // prepare modal (Credit Card Details)
3137 array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-vcm-pcid', JText::translate('GETFULLCARDDETAILS'), '', 'width: 80%; height: 60%; margin-left: -40%; top: 20% !important;'));
3138 ?>
3139 <div class="vcm-notif-pcidrq-container">
3140 <button type="button" class="btn vbo-config-btn vcm-pcid-launch" onclick="vboOpenJModal('vbo-vcm-pcid', 'index.php?option=com_vikchannelmanager&task=execpcid&channel_source=<?php echo $channel_source; ?>&otaid=<?php echo $row['idorderota']; ?>&tmpl=component');"><?php VikBookingIcons::e('credit-card'); ?> <?php echo JText::translate('GETFULLCARDDETAILS'); ?></button>
3141 </div>
3142 <?php
3143 /**
3144 * Check for automatic payment schedules support when an active CC/VCC is available.
3145 *
3146 * @since 1.16.10 (J) - 1.6.10 (WP)
3147 */
3148 $can_payschedule = false;
3149 $active_payschedules = [];
3150 try {
3151 $processor = VBOModelReservation::getInstance($row, true)->getPaymentProcessor();
3152 if (method_exists($processor, 'isDirectChargeSupported') && $processor->isDirectChargeSupported()) {
3153 // turn flag on
3154 $can_payschedule = true;
3155 // load current schedules
3156 $active_payschedules = VBOModelPayschedules::getInstance()->getItems([
3157 'idorder' => [
3158 'value' => $row['id'],
3159 ],
3160 ]);
3161 }
3162 } catch (Exception $e) {
3163 // do nothing
3164 }
3165
3166 if ($can_payschedule) {
3167 // calculate the total amount scheduled
3168 $tot_scheduled = 0;
3169 foreach ($active_payschedules as $active_payschedule) {
3170 if (!$active_payschedule->status) {
3171 $tot_scheduled += $active_payschedule->amount;
3172 }
3173 }
3174
3175 // display action buttons for payment schedules
3176 ?>
3177 <div class="vbo-eorder-payschedules-wrap">
3178 <button type="button" class="btn btn-<?php echo $active_payschedules || $automatic_payment_collection ? 'success' : 'primary'; ?> vbo-context-menu-btn vbo-context-menu-payschedules">
3179 <span class="vbo-context-menu-lbl"><?php echo JText::translate('VBO_AUTOPAY_SCHEDULED'); ?></span>
3180 <span class="vbo-context-menu-ico"><?php VikBookingIcons::e('sort-down'); ?></span>
3181 </button>
3182 </div>
3183
3184 <div class="vbo-eorder-newpayschedule-helper-wrap" style="display: none;">
3185 <div class="vbo-eorder-newpayschedule-helper-cont" data-auto-pay-schedules="<?php echo (int) $automatic_payment_collection; ?>">
3186 <p class="info" data-auto-pay-schedules="help" style="display: none;"><?php echo JText::translate('VBO_AUTO_PAY_COLLECT_HELP'); ?></p>
3187 <div class="vbo-admin-container vbo-admin-container-full vbo-admin-container-compact">
3188 <div class="vbo-params-wrap">
3189 <div class="vbo-params-container">
3190 <div class="vbo-params-block">
3191 <div class="vbo-param-container">
3192 <div class="vbo-param-label">
3193 <label for="new_payschedule_amount"><?php echo JText::translate('VBO_CC_AMOUNT'); ?></label>
3194 </div>
3195 <div class="vbo-param-setting">
3196 <div class="vbo-input-currency-wrap">
3197 <span><?php echo $currencysymb; ?></span>
3198 <input type="number" id="new_payschedule_amount" value="<?php echo $tot_scheduled < $row['total'] ? ($row['total'] - $tot_scheduled) : 0; ?>" min="0" step="any" />
3199 </div>
3200 <span class="vbo-param-setting-comment"><?php echo JText::translate('VBEDITORDERNINE') . ' ' . VikBooking::formatCurrencyNumber(VikBooking::numberFormat($row['total']), $currencysymb); ?></span>
3201 </div>
3202 </div>
3203 <div class="vbo-param-container">
3204 <div class="vbo-param-label">
3205 <label for="new_payschedule_fordt"><?php echo JText::translate('VBPVIEWORDERSONE'); ?></label>
3206 </div>
3207 <div class="vbo-param-setting">
3208 <?php echo $vbo_app->getCalendar(date($df, $row['checkin']), 'new_payschedule_fordt', 'new_payschedule_fordt', $nowdf, array('class'=>'', 'size'=>'10', 'maxlength'=>'19', 'todayBtn' => 'true')); ?>
3209 </div>
3210 </div>
3211 <div class="vbo-param-container">
3212 <div class="vbo-param-label">
3213 <label for="new_payschedule_fordtime"><?php echo JText::translate('VBO_REMINDER_TIME'); ?></label>
3214 </div>
3215 <div class="vbo-param-setting">
3216 <select id="new_payschedule_fordtime">
3217 <?php
3218 for ($h = 0; $h < 24; $h++) {
3219 $say_htime = ($h < 10 ? '0' : '') . $h;
3220 ?>
3221 <option value="<?php echo $say_htime; ?>:00"><?php echo $say_htime; ?>:00</option>
3222 <option value="<?php echo $say_htime; ?>:30"><?php echo $say_htime; ?>:30</option>
3223 <?php
3224 }
3225 ?>
3226 </select>
3227 </div>
3228 </div>
3229 </div>
3230 </div>
3231 </div>
3232 </div>
3233 </div>
3234 </div>
3235
3236 <script type="text/javascript">
3237
3238 // build base buttons list for context menu
3239 var vbo_payschedule_btns = [
3240 // toggle automatic payment collection scheduling for all bookings
3241 {
3242 activeState: <?php echo $automatic_payment_collection ? 'true' : 'false'; ?>,
3243 text: <?php echo json_encode(JText::translate('VBO_ENABLED_FOR_ALL_BOOKINGS')); ?>,
3244 separator: true,
3245 icon: function() {
3246 return this.activeState ? '<?php echo VikBookingIcons::i('toggle-on', 'vbo-enabled-icon'); ?>' : '<?php echo VikBookingIcons::i('toggle-off'); ?>';
3247 },
3248 action: function(root, event) {
3249 // create reference to button object
3250 let that = this;
3251
3252 // get new state
3253 let newState = !this.activeState;
3254
3255 // determine confirmation message
3256 let confirm_enable = <?php echo json_encode(JText::translate('VBO_AUTO_PAY_COLLECT_ENABLE_CONF')); ?>;
3257 let confirm_disable = <?php echo json_encode(JText::translate('VBO_AUTO_PAY_COLLECT_DISABLE_CONF')); ?>;
3258
3259 if ((newState && confirm(confirm_enable)) || (!newState && confirm(confirm_disable))) {
3260 // silently update configuration setting
3261 VBOCore.doAjax(
3262 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=configuration.update'); ?>",
3263 {
3264 settings: {
3265 auto_payment_collection: newState ? 1 : 0,
3266 }
3267 },
3268 (success) => {
3269 // toggle state
3270 that.activeState = newState;
3271 // update data attribute with the newly saved configuration value
3272 let statusEl = document.querySelector('.vbo-eorder-newpayschedule-helper-cont[data-auto-pay-schedules]');
3273 if (statusEl) {
3274 statusEl.setAttribute('data-auto-pay-schedules', (newState ? 1 : 0));
3275 }
3276 },
3277 (error) => {
3278 console.error(error);
3279 }
3280 );
3281 }
3282 },
3283 },
3284 // add new payment schedule button
3285 {
3286 icon: '<?php echo VikBookingIcons::i('plus-circle'); ?>',
3287 text: Joomla.JText._('VBO_NEW_PAYSCHEDULE'),
3288 separator: true,
3289 action: (root, config) => {
3290 // build modal buttons
3291 let footer_left = jQuery('<button></button>');
3292 footer_left.addClass('btn');
3293 footer_left.attr('type', 'button');
3294 footer_left.text(Joomla.JText._('VBANNULLA'));
3295 footer_left.on('click', function() {
3296 // dismiss the modal
3297 VBOCore.emitEvent('vbo-eorder-new-payschedule-dismiss');
3298 });
3299
3300 let footer_right = jQuery('<button></button>');
3301 footer_right.addClass('btn btn-success');
3302 footer_right.attr('type', 'button');
3303 footer_right.text(Joomla.JText._('VBSAVE'));
3304 footer_right.on('click', function() {
3305 // disable button to prevent double submissions
3306 let submit_btn = jQuery(this);
3307 submit_btn.prop('disabled', true);
3308 // make the request
3309 VBOCore.doAjax(
3310 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=payschedules.save'); ?>",
3311 {
3312 bid: '<?php echo $row['id']; ?>',
3313 amount: jQuery('#new_payschedule_amount').val(),
3314 dt: jQuery('#new_payschedule_fordt').val(),
3315 time: jQuery('#new_payschedule_fordtime').val(),
3316 },
3317 (new_pay_schedules) => {
3318 // re-enable submit button
3319 submit_btn.prop('disabled', false);
3320 // dismiss the modal
3321 VBOCore.emitEvent('vbo-eorder-new-payschedule-dismiss');
3322 // populate the new schedule buttons
3323 let new_pay_schedule_btns = [];
3324 // push button to toggle automatic payment collection scheduling for all bookings
3325 new_pay_schedule_btns.push(vbo_payschedule_btns[0]);
3326 // push button to add a new schedule
3327 new_pay_schedule_btns.push(vbo_payschedule_btns[1]);
3328 // push all active schedules
3329 new_pay_schedules.forEach((payschedule) => {
3330 new_pay_schedule_btns.push(
3331 vboBuildPayScheduleBtn(payschedule)
3332 );
3333 });
3334 // update trigger button class
3335 if (new_pay_schedules.length) {
3336 jQuery('.vbo-context-menu-payschedules').removeClass('btn-primary').addClass('btn-success');
3337 } else {
3338 jQuery('.vbo-context-menu-payschedules').removeClass('btn-success').addClass('btn-primary');
3339 }
3340 // set new buttons in context menu
3341 jQuery('.vbo-context-menu-payschedules').vboContextMenu('buttons', new_pay_schedule_btns);
3342 },
3343 (error) => {
3344 // re-enable submit button
3345 submit_btn.prop('disabled', false);
3346 // display error message
3347 alert(error.responseText);
3348 }
3349 );
3350 });
3351
3352 // display modal
3353 let modal_body = VBOCore.displayModal({
3354 suffix: 'vbo-new-pay-schedule',
3355 extra_class: 'vbo-modal-rounded vbo-modal-dialog',
3356 title: Joomla.JText._('VBO_NEW_PAYSCHEDULE'),
3357 body: '',
3358 body_prepend: true,
3359 footer_left: footer_left,
3360 footer_right: footer_right,
3361 draggable: true,
3362 dismiss_event: 'vbo-eorder-new-payschedule-dismiss',
3363 onDismiss: () => {
3364 jQuery('.vbo-eorder-newpayschedule-helper-cont').appendTo(
3365 jQuery('.vbo-eorder-newpayschedule-helper-wrap')
3366 );
3367 },
3368 });
3369
3370 // check current automatic payment schedules status
3371 let statusEl = document.querySelector('.vbo-eorder-newpayschedule-helper-cont[data-auto-pay-schedules]');
3372 if (statusEl) {
3373 let autoPayStatus = statusEl.getAttribute('data-auto-pay-schedules');
3374 if (autoPayStatus == 1) {
3375 // show help element
3376 statusEl.querySelector('[data-auto-pay-schedules="help"]').style.display = '';
3377 } else {
3378 // hide help element
3379 statusEl.querySelector('[data-auto-pay-schedules="help"]').style.display = 'none';
3380 }
3381 }
3382
3383 // append modal body
3384 jQuery('.vbo-eorder-newpayschedule-helper-cont').appendTo(modal_body);
3385 },
3386 }
3387 ];
3388
3389 /**
3390 * Builds a button object for the context menu from the given payment schedule object.
3391 */
3392 function vboBuildPayScheduleBtn(payschedule) {
3393 let icn_to_process = '<?php echo VikBookingIcons::i('clock'); ?>';
3394 let icn_processed = '<?php echo VikBookingIcons::i('check-circle'); ?>';
3395 let icn_error = '<?php echo VikBookingIcons::i('exclamation-triangle'); ?>';
3396 let dt_unit = (payschedule.dt_diff.days || payschedule.dt_diff.weeks || payschedule.dt_diff.months || payschedule.dt_diff.years || 0);
3397 let say_dt = !payschedule.dt_diff.past && dt_unit > 0 ? payschedule.dt_diff.relative : payschedule?.fordt;
3398 if (!payschedule.dt_diff.past && (payschedule.dt_diff.sameday || payschedule.dt_diff.today)) {
3399 say_dt = payschedule.dt_diff.relative + ' (' + payschedule.time_hm + ')';
3400 } else if (!payschedule.dt_diff.past && payschedule.dt_diff.tomorrow) {
3401 say_dt = payschedule.dt_diff.relative + ' (' + payschedule.time_hm + ')';
3402 }
3403
3404 return {
3405 icon: ((payschedule.status || 0) > 0 ? (payschedule.status == 1 ? icn_processed : icn_error) : icn_to_process),
3406 text: VBOCore.getCurrency().format(payschedule?.amount) + ' - ' + say_dt,
3407 class: ((payschedule.status || 0) == 1 ? 'vbo-context-menu-entry-success' : ((payschedule.status || 0) == 2 ? 'vbo-context-menu-entry-warning' : 'vbo-context-menu-entry-danger')),
3408 separator: false,
3409 action: (root, config) => {
3410 if (payschedule.status == 0 || !payschedule.logs) {
3411 // confirm deletion without displaying anything
3412 if (confirm(Joomla.JText._('VBDELCONFIRM'))) {
3413 // make the request
3414 VBOCore.doAjax(
3415 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=payschedules.delete'); ?>",
3416 {
3417 bid: payschedule.idorder,
3418 schedule_id: payschedule.id,
3419 },
3420 (new_pay_schedules) => {
3421 // populate the new schedule buttons
3422 let new_pay_schedule_btns = [];
3423 // push button to toggle automatic payment collection scheduling for all bookings
3424 new_pay_schedule_btns.push(vbo_payschedule_btns[0]);
3425 // push button to add a new schedule
3426 new_pay_schedule_btns.push(vbo_payschedule_btns[1]);
3427 // push all active schedules
3428 new_pay_schedules.forEach((payschedule) => {
3429 new_pay_schedule_btns.push(
3430 vboBuildPayScheduleBtn(payschedule)
3431 );
3432 });
3433 // update trigger button class
3434 if (new_pay_schedules.length) {
3435 jQuery('.vbo-context-menu-payschedules').removeClass('btn-primary').addClass('btn-success');
3436 } else {
3437 jQuery('.vbo-context-menu-payschedules').removeClass('btn-success').addClass('btn-primary');
3438 }
3439 // set new buttons in context menu
3440 jQuery('.vbo-context-menu-payschedules').vboContextMenu('buttons', new_pay_schedule_btns);
3441 },
3442 (error) => {
3443 // display error message
3444 alert(error.responseText);
3445 }
3446 );
3447 }
3448 } else {
3449 // display modal on click with the execution logs
3450
3451 // build modal buttons
3452 let footer_left = jQuery('<button></button>');
3453 footer_left.addClass('btn');
3454 footer_left.attr('type', 'button');
3455 footer_left.text(Joomla.JText._('VBANNULLA'));
3456 footer_left.on('click', function() {
3457 // dismiss the modal
3458 VBOCore.emitEvent('vbo-eorder-payschedule-logs-dismiss');
3459 });
3460
3461 let footer_right = jQuery('<button></button>');
3462 footer_right.addClass('btn btn-danger');
3463 footer_right.attr('type', 'button');
3464 footer_right.text(Joomla.JText._('VBELIMINA'));
3465 footer_right.on('click', function() {
3466 // confirm record deletion
3467 if (confirm(Joomla.JText._('VBDELCONFIRM'))) {
3468 // make the request
3469 VBOCore.doAjax(
3470 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=payschedules.delete'); ?>",
3471 {
3472 bid: payschedule.idorder,
3473 schedule_id: payschedule.id,
3474 },
3475 (new_pay_schedules) => {
3476 // dismiss the modal
3477 VBOCore.emitEvent('vbo-eorder-payschedule-logs-dismiss');
3478 // populate the new schedule buttons
3479 let new_pay_schedule_btns = [];
3480 // push button to toggle automatic payment collection scheduling for all bookings
3481 new_pay_schedule_btns.push(vbo_payschedule_btns[0]);
3482 // push button to add a new schedule
3483 new_pay_schedule_btns.push(vbo_payschedule_btns[1]);
3484 // push all active schedules
3485 new_pay_schedules.forEach((payschedule) => {
3486 new_pay_schedule_btns.push(
3487 vboBuildPayScheduleBtn(payschedule)
3488 );
3489 });
3490 // update trigger button class
3491 if (new_pay_schedules.length) {
3492 jQuery('.vbo-context-menu-payschedules').removeClass('btn-primary').addClass('btn-success');
3493 } else {
3494 jQuery('.vbo-context-menu-payschedules').removeClass('btn-success').addClass('btn-primary');
3495 }
3496 // set new buttons in context menu
3497 jQuery('.vbo-context-menu-payschedules').vboContextMenu('buttons', new_pay_schedule_btns);
3498 },
3499 (error) => {
3500 // display error message
3501 alert(error.responseText);
3502 }
3503 );
3504 }
3505 });
3506
3507 // display modal
3508 let modal_body = VBOCore.displayModal({
3509 suffix: 'vbo-pay-schedule-logs',
3510 extra_class: 'vbo-modal-rounded vbo-modal-dialog',
3511 title: payschedule.fordt,
3512 body: '<pre>' + payschedule.logs + '</pre>',
3513 footer_left: footer_left,
3514 footer_right: footer_right,
3515 draggable: true,
3516 dismiss_event: 'vbo-eorder-payschedule-logs-dismiss',
3517 });
3518 }
3519 },
3520 };
3521 }
3522
3523 // build context menu
3524 jQuery(function() {
3525
3526 // append active payment schedule buttons
3527 let active_payschedules = <?php echo json_encode($active_payschedules); ?>;
3528 active_payschedules.forEach((payschedule) => {
3529 vbo_payschedule_btns.push(
3530 vboBuildPayScheduleBtn(payschedule)
3531 );
3532 });
3533
3534 // render context menu
3535 jQuery('.vbo-context-menu-payschedules').vboContextMenu({
3536 placement: 'bottom-left',
3537 buttons: vbo_payschedule_btns,
3538 });
3539
3540 });
3541 </script>
3542 <?php
3543 }
3544 // end automatic payment schedules
3545 }
3546 }
3547 } elseif (empty($row['idorderota']) && !empty($row['paymentlog']) && $row['status'] == 'standby') {
3548 ?>
3549 <div class="vbo-eorder-emptyccdata">
3550 <a class="btn btn-warning" href="index.php?option=com_vikbooking&task=editorder&cid[]=<?php echo $row['id']; ?>&unset_cc=1" onclick="return confirm(Joomla.JText._('VBDELCONFIRM'));"><?php VikBookingIcons::e('broom'); ?> <?php echo JText::translate('VBO_EMPTY_DATA'); ?></a>
3551 </div>
3552 <?php
3553 }
3554
3555 /**
3556 * Attempt to display the reporting invalid credit card layout from VCM.
3557 *
3558 * @requires VCM >= 1.8.27
3559 *
3560 * @since 1.16.9 (J) - 1.6.9 (WP)
3561 */
3562 try {
3563 // prepare the layout data array
3564 $layout_data = [
3565 'caller' => 'vikbooking',
3566 'booking' => $row,
3567 ];
3568
3569 ?>
3570 <div class="vbo-eorder-vcm-reporting-invalidcc">
3571 <?php
3572 // render the reporting-invalidcc layout
3573 echo JLayoutHelper::render('reporting.invalidcc', $layout_data, null, [
3574 'component' => 'com_vikchannelmanager',
3575 'client' => 'admin',
3576 ]);
3577 ?>
3578 </div>
3579 <?php
3580 } catch(Throwable $e) {
3581 // do nothing
3582 }
3583
3584 ?>
3585 </div>
3586 <?php
3587
3588 if (!$cc_acl_denied) {
3589 ?>
3590 <pre><?php echo htmlspecialchars($row['paymentlog']); ?></pre>
3591 <?php
3592 }
3593 ?>
3594 </div>
3595
3596 <script type="text/javascript">
3597 if (window.location.hash == '#paymentlog') {
3598 setTimeout(function() {
3599 jQuery(".vbo-bookingdet-tab[data-vbotab='vbo-tab-admin']").trigger('click');
3600 vbToggleLog(document.getElementById('vbo-trig-paylogs'));
3601 }, 500);
3602 }
3603 </script>
3604 <?php
3605 }
3606 if (!$printreceipt && !is_null($messaging)) {
3607 ?>
3608 <div id="vbmessagingdiv" class="vbo-extra-panel" style="display: none;">
3609 <?php echo $messaging->renderChat(); ?>
3610 </div>
3611 <script type="text/javascript">
3612 jQuery(function() {
3613 if (window.location.hash == '#messaging') {
3614 setTimeout(function() {
3615 jQuery(".vbo-bookingdet-tab[data-vbotab='vbo-tab-admin']").trigger('click');
3616 vbToggleMessaging(document.getElementById('vbo-trig-messaging'));
3617 }, 100);
3618 }
3619 });
3620 </script>
3621 <?php
3622 }
3623
3624 foreach ($adminPanelForms as $legend => $form)
3625 {
3626 $legendId = preg_replace("/[^a-zA-Z0-9_\-]+/", '', $legend);
3627 ?>
3628 <div class="vbo-extra-panel" id="vboextrapanel-<?php echo $legendId; ?>" style="display: none;">
3629 <?php echo $form; ?>
3630 </div>
3631 <?php
3632 }
3633 ?>
3634 </div>
3635 </div>
3636 </div>
3637 </div>
3638
3639 <input type="hidden" name="task" value="editorder">
3640 <input type="hidden" name="vbo_active_tab" id="vbo_active_tab" value="">
3641 <input type="hidden" name="whereup" value="<?php echo $row['id']; ?>">
3642 <input type="hidden" name="cid[]" value="<?php echo $row['id']; ?>">
3643 <input type="hidden" name="option" value="com_vikbooking">
3644 <?php
3645 $tmpl = VikRequest::getVar('tmpl');
3646 if ($tmpl == 'component') {
3647 echo '<input type="hidden" name="tmpl" value="component" />';
3648 }
3649 $pgoto = VikRequest::getString('goto', '', 'request');
3650 if (in_array($pgoto, ['overv', 'ratesoverv'])) {
3651 echo '<input type="hidden" name="goto" value="' . $pgoto . '" />';
3652 }
3653 ?>
3654 </form>
3655 </div>
3656 <?php
3657 foreach ($vbo_modals_html as $modalhtml) {
3658 echo $modalhtml;
3659 }
3660 ?>
3661 <form action="index.php?option=com_vikbooking&amp;task=orders" method="post" id="vbo-gen-invoice">
3662 <input type="hidden" name="option" value="com_vikbooking" />
3663 <input type="hidden" name="task" value="orders" />
3664 <input type="hidden" name="cid[]" value="<?php echo $row['id']; ?>" />
3665 <input type="hidden" name="invnotes" id="invnotes-hid" value="" />
3666 </form>
3667
3668 <div class="vbo-editorder-sms-email-send-helper" style="display: none;">
3669
3670 <div class="vbo-editorder-sms-send-wrap">
3671 <form action="index.php?option=com_vikbooking" method="post" id="vbo-modal-form-sms">
3672 <div class="vbo-admin-container vbo-admin-container-full vbo-admin-container-compact">
3673 <div class="vbo-params-wrap">
3674 <div class="vbo-params-container">
3675
3676 <div class="vbo-param-container vbo-param-container-full">
3677 <div class="vbo-param-label">
3678 <label for="smscont"><?php echo JText::translate('VBSENDSMSCUSTCONT'); ?></label>
3679 </div>
3680 <div class="vbo-param-setting">
3681 <textarea name="smscont" id="smscont" style="width: 99%; min-width: 99%; max-width: 99%; height: 120px;"></textarea>
3682 </div>
3683 </div>
3684
3685 </div>
3686 </div>
3687 </div>
3688 <input type="hidden" name="phone" id="smstophone" value="<?php echo $row['phone']; ?>" />
3689 <input type="hidden" name="goto" value="<?php echo urlencode('index.php?option=com_vikbooking&task=editorder&cid[]='.$row['id']); ?>" />
3690 <input type="hidden" name="task" value="sendcustomsms" />
3691 </form>
3692 </div>
3693
3694 <div class="vbo-editorder-email-send-wrap">
3695 <form action="index.php?option=com_vikbooking" method="post" enctype="multipart/form-data" id="vbo-modal-form-email">
3696 <div class="vbo-admin-container vbo-admin-container-full vbo-admin-container-compact">
3697 <div class="vbo-params-wrap">
3698 <div class="vbo-params-container">
3699
3700 <?php
3701 $cur_emtpl = VBOFactory::getConfig()->getArray('customemailtpls', []);
3702 if ($cur_emtpl) {
3703 ?>
3704 <div class="vbo-param-container">
3705 <div class="vbo-param-setting">
3706 <select id="emtpl-customemail" onchange="vboLoadEmailTpl(this.value);">
3707 <option value=""><?php echo JText::translate('VBEMAILCUSTFROMTPL'); ?></option>
3708 <?php
3709 foreach ($cur_emtpl as $emk => $emv) {
3710 ?>
3711 <optgroup label="<?php echo $emv['emailsubj']; ?>">
3712 <option value="<?php echo $emk; ?>"><?php echo JText::translate('VBEMAILCUSTFROMTPLUSE'); ?></option>
3713 <option value="rm<?php echo $emk; ?>"><?php echo JText::translate('VBEMAILCUSTFROMTPLRM'); ?></option>
3714 </optgroup>
3715 <?php
3716 }
3717 ?>
3718 </select>
3719 </div>
3720 </div>
3721 <?php
3722 }
3723
3724 /**
3725 * Load all conditional text special tags.
3726 *
3727 * @since 1.14 (J) - 1.4.0 (WP)
3728 */
3729 $extra_btns = [];
3730 $condtext_tags = VikBooking::getConditionalRulesInstance()->getSpecialTags();
3731 if ($condtext_tags) {
3732 $condtext_tags = array_keys($condtext_tags);
3733 foreach ($condtext_tags as $tag) {
3734 array_push($extra_btns, '<button type="button" class="btn btn-secondary btn-small vbo-condtext-specialtag-btn" onclick="setSpecialTplTag(\'emailcont\', \'' . $tag . '\');">' . $tag . '</button>');
3735 }
3736 }
3737 ?>
3738 <div class="vbo-param-container vbo-param-container-full">
3739 <div class="vbo-param-label">
3740 <label for="emailsubj"><?php echo JText::translate('VBSENDEMAILCUSTSUBJ'); ?></label>
3741 </div>
3742 <div class="vbo-param-setting">
3743 <input type="text" name="emailsubj" id="emailsubj" value="" size="30" />
3744 </div>
3745 </div>
3746
3747 <div class="vbo-param-container vbo-param-container-full">
3748 <div class="vbo-param-label">
3749 <label for="emailcont"><?php echo JText::translate('VBSENDEMAILCUSTCONT'); ?></label>
3750 </div>
3751 <div class="vbo-param-setting">
3752 <?php
3753 $special_tags_base = [
3754 '{customer_name}',
3755 '{booking_id}',
3756 '{checkin_date}',
3757 '{checkout_date}',
3758 '{num_nights}',
3759 '{rooms_booked}',
3760 '{rooms_names}',
3761 '{tot_adults}',
3762 '{tot_children}',
3763 '{tot_guests}',
3764 '{total}',
3765 '{total_paid}',
3766 '{remaining_balance}',
3767 '{booking_link}',
3768 ];
3769
3770 $special_tags_base_html = '';
3771 foreach ($special_tags_base as $sp_tag) {
3772 $special_tags_base_html .= '<button type="button" class="btn btn-secondary btn-small" onclick="setSpecialTplTag(\'emailcont\', \'' . $sp_tag . '\');">' . $sp_tag . '</button>' . "\n";
3773 }
3774
3775 /**
3776 * Use the rich text editor (visual editor) to build custom email messages.
3777 *
3778 * @since 1.15.0 (J) - 1.5.0 (WP)
3779 */
3780 $tarea_attr = [
3781 'id' => 'emailcont',
3782 'rows' => '7',
3783 'cols' => '170',
3784 'style' => 'width: 99%; min-width: 99%; max-width: 99%; height: 120px; margin-bottom: 1px;',
3785 ];
3786 $editor_opts = [
3787 'modes' => [
3788 'visual',
3789 'text',
3790 ],
3791 'gen_ai' => [
3792 'booking' => $row,
3793 'customer' => $customer,
3794 'environment' => 'booking',
3795 ],
3796 ];
3797 $editor_btns = $special_tags_base;
3798 if ($condtext_tags) {
3799 $editor_btns = array_merge($editor_btns, $condtext_tags);
3800 }
3801
3802 /**
3803 * Trigger event to allow third-party plugins to add custom special tags.
3804 *
3805 * @since 1.16.10 (J) - 1.6.10 (WP)
3806 */
3807 $custom_btns = VBOFactory::getPlatform()->getDispatcher()->filter('onRenderCustomEmailSpecialTags', [$row, $editor_btns]);
3808 foreach ($custom_btns as $custom_btn) {
3809 // merge custom buttons
3810 $editor_btns = array_merge($editor_btns, (array) $custom_btn);
3811 }
3812
3813 // make sure to filter empty buttons
3814 $editor_btns = array_filter($editor_btns);
3815
3816 // render visual editor
3817 echo $vbo_app->renderVisualEditor('emailcont', '', $tarea_attr, $editor_opts, $editor_btns);
3818 ?>
3819 <div class="btn-group pull-left vbo-smstpl-bgroup vbo-custmail-bgroup vik-contentbuilder-textmode-sptags">
3820 <?php echo $special_tags_base_html . "\n" . implode("\n", $extra_btns); ?>
3821 </div>
3822 </div>
3823 </div>
3824
3825 <div class="vbo-param-container vbo-param-container-full">
3826 <div class="vbo-param-label">
3827 <label for="emailattch"><?php echo JText::translate('VBSENDEMAILCUSTATTCH'); ?></label>
3828 </div>
3829 <div class="vbo-param-setting">
3830 <input type="file" name="emailattch" id="emailattch" />
3831 </div>
3832 </div>
3833
3834 <div class="vbo-param-container vbo-param-container-full">
3835 <div class="vbo-param-label">
3836 <label for="emailfrom"><?php echo JText::translate('VBSENDEMAILCUSTFROM'); ?></label>
3837 </div>
3838 <div class="vbo-param-setting">
3839 <input type="text" name="emailfrom" id="emailfrom" value="<?php echo VikBooking::getSenderMail(); ?>" size="30" />
3840 </div>
3841 </div>
3842
3843 </div>
3844 </div>
3845 </div>
3846 <input type="hidden" name="bid" value="<?php echo $row['id']; ?>" />
3847 <input type="hidden" name="email" id="emailto" value="<?php echo $row['custmail']; ?>" />
3848 <input type="hidden" name="goto" value="<?php echo urlencode('index.php?option=com_vikbooking&task=editorder&cid[]='.$row['id']); ?>" />
3849 <input type="hidden" name="task" value="sendcustomemail" />
3850 </form>
3851 </div>
3852
3853 <div id="vbo-modal-footer-sms" style="display: none;">
3854 <button type="submit" class="btn vbo-config-btn" onclick="document.getElementById('vbo-modal-form-sms').submit();"><?php VikBookingIcons::e('comment'); ?> <?php echo JText::translate('VBSENDSMSACTION'); ?></button>
3855 </div>
3856 <div id="vbo-modal-footer-email" style="display: none;">
3857 <button type="submit" class="btn vbo-config-btn" onclick="document.getElementById('vbo-modal-form-email').submit();"><?php VikBookingIcons::e('envelope'); ?> <?php echo JText::translate('VBSENDEMAILACTION'); ?></button>
3858 </div>
3859 </div>
3860
3861 <div class="vbo-bookingdet-send-tplmessage-helper" style="display: none;">
3862 <div class="vbo-bookingdet-send-tplmessage-wrap">
3863 <div class="vbo-admin-container vbo-admin-container-full vbo-admin-container-compact">
3864 <div class="vbo-params-wrap">
3865 <div class="vbo-params-container">
3866 <div class="vbo-params-block">
3867 <?php
3868 echo VBOParamsRendering::getInstance(
3869 [
3870 'ma_identifier' => [
3871 'type' => 'elements',
3872 'label' => JText::translate('VBO_MESSAGE_TEMPLATE'),
3873 'asset_options' => [
3874 'placeholder' => JText::translate('VBO_MESSAGE_TEMPLATE'),
3875 'allowClear' => false,
3876 ],
3877 'inline' => false,
3878 'wrapdivcls' => 'vbo-singleselect-inline-elems-wrap vbo-singleselect-inline-small-icons',
3879 'style_selection' => true,
3880 'attributes' => [
3881 'data-element' => 'message-template',
3882 ],
3883 'elements' => array_map(function($maConfig) {
3884 if (!empty($maConfig['channel_logo'])) {
3885 $messTplName = sprintf('%s (%s)', $maConfig['name'], $maConfig['lang']);
3886 } else {
3887 $messTplName = sprintf('%s - %s (%s)', $maConfig['channel_name'], $maConfig['name'], $maConfig['lang']);
3888 }
3889 return array_filter([
3890 'id' => $maConfig['identifier'],
3891 'name' => $messTplName,
3892 'img_uri' => ($maConfig['channel_logo'] ?? '') ?: null,
3893 ]);
3894 }, $messagingAccountConfigurations),
3895 ],
3896 ],
3897 []
3898 )->setInputName('send_ma_tpl')->getHtml();
3899 ?>
3900 <div class="vbo-param-container">
3901 <div class="vbo-param-label"><?php echo JText::translate('VBOPREVIEW'); ?></div>
3902 <div class="vbo-param-setting">
3903 <div class="vbo-ma-send-tplmessage-preview"></div>
3904 </div>
3905 </div>
3906 </div>
3907 </div>
3908 </div>
3909 </div>
3910 </div>
3911 </div>
3912
3913 <script type="text/javascript">
3914 var vbo_print_only = false;
3915 if (typeof jQuery.fn.tooltip === 'function') {
3916 jQuery(".hasTooltip").tooltip();
3917 }
3918 function vboDisplaySendSMS() {
3919 var cur_phone = jQuery("#smstophone").val();
3920 var phone_set = jQuery("#custphone").trigger('vboupdatephonenumber').val();
3921 if (phone_set.length && phone_set != cur_phone) {
3922 jQuery("#smstophone").val(phone_set);
3923 }
3924
3925 // define the modal cancel button
3926 let cancel_btn = jQuery('<button></button>')
3927 .attr('type', 'button')
3928 .addClass('btn')
3929 .text(Joomla.JText._('VBANNULLA'))
3930 .on('click', function() {
3931 VBOCore.emitEvent('vbo-editorder-send-sms-dismiss');
3932 });
3933
3934 // display modal for email/sms contents
3935 let modal_body = VBOCore.displayModal({
3936 suffix: 'editorder-send-sms',
3937 extra_class: 'vbo-modal-large',
3938 lock_scroll: true,
3939 title: Joomla.JText._('VBSENDSMSACTION') + ': ' + (phone_set && phone_set != cur_phone ? phone_set : cur_phone),
3940 footer_left: cancel_btn,
3941 footer_right: jQuery('#vbo-modal-footer-sms').find('button').clone(),
3942 loading_event: 'vbo-editorder-send-sms-loading',
3943 dismiss_event: 'vbo-editorder-send-sms-dismiss',
3944 onDismiss: () => {
3945 jQuery('.vbo-editorder-sms-send-wrap').appendTo('.vbo-editorder-sms-email-send-helper');
3946 },
3947 });
3948
3949 jQuery('.vbo-editorder-sms-send-wrap').appendTo(modal_body);
3950 }
3951 function vboDisplaySendEmail() {
3952 var cur_email = jQuery("#emailto").val();
3953 var email_set = jQuery("#custmail").val();
3954 if (email_set.length && email_set != cur_email) {
3955 jQuery("#emailto").val(email_set);
3956 }
3957
3958 // define the modal cancel button
3959 let cancel_btn = jQuery('<button></button>')
3960 .attr('type', 'button')
3961 .addClass('btn')
3962 .text(Joomla.JText._('VBANNULLA'))
3963 .on('click', function() {
3964 VBOCore.emitEvent('vbo-editorder-send-email-dismiss');
3965 });
3966
3967 // display modal for email/sms contents
3968 let modal_body = VBOCore.displayModal({
3969 suffix: 'editorder-send-email',
3970 extra_class: 'vbo-modal-large',
3971 lock_scroll: true,
3972 title: Joomla.JText._('VBSENDEMAILACTION') + ': ' + (email_set && email_set != cur_email ? email_set : cur_email),
3973 footer_left: cancel_btn,
3974 footer_right: jQuery('#vbo-modal-footer-email').find('button').clone(),
3975 loading_event: 'vbo-editorder-send-email-loading',
3976 dismiss_event: 'vbo-editorder-send-email-dismiss',
3977 onDismiss: () => {
3978 jQuery('.vbo-editorder-email-send-wrap').appendTo('.vbo-editorder-sms-email-send-helper');
3979 },
3980 });
3981
3982 jQuery('.vbo-editorder-email-send-wrap').appendTo(modal_body);
3983 }
3984 function vboKeyupEmail(event) {
3985 if (event.key && event.key == 'Enter') {
3986 event.preventDefault();
3987 document.adminForm.submit();
3988 return;
3989 }
3990 jQuery('.vbo-bookingdet-save-email').show();
3991 }
3992 function setSpecialTplTag(taid, tpltag) {
3993 var tplobj = document.getElementById(taid);
3994 if (tplobj != null) {
3995 var start = tplobj.selectionStart;
3996 var end = tplobj.selectionEnd;
3997 tplobj.value = tplobj.value.substring(0, start) + tpltag + tplobj.value.substring(end);
3998 tplobj.selectionStart = tplobj.selectionEnd = start + tpltag.length;
3999 tplobj.focus();
4000 }
4001 }
4002 jQuery(function() {
4003 // register to the event emitted when a new payment is made through the virtual terminal widget
4004 document.addEventListener('vbo_new_payment_transaction', (e) => {
4005 if (!e || !e.detail || !e.detail.hasOwnProperty('tn') || !e.detail['tn']) {
4006 // do nothing
4007 return;
4008 }
4009 // reload the page to display the updated information
4010 location.reload();
4011 });
4012 // register to the event emitted when a booking is modified through an admin widget
4013 document.addEventListener('vbo_booking_modified', (e) => {
4014 if (!e || !e.detail || !e.detail.hasOwnProperty('bid') || !e.detail['bid']) {
4015 // do nothing
4016 return;
4017 }
4018 // reload the page to display the new information about the booking just modified
4019 location.reload();
4020 });
4021 // register click event for the button to see the quote details
4022 document.querySelector('.vbo-quote-details-btn')?.addEventListener('click', (e) => {
4023 VBOCore.handleDisplayWidgetNotification({widget_id: 'quotes'}, {bid: <?php echo $row['id']; ?>});
4024 });
4025 // remove overbooking flag
4026 jQuery('.vbo-label-overbooking').on('click', function() {
4027 if (confirm(Joomla.JText._('VBO_CONF_RM_OVERBOOKING_FLAG'))) {
4028 VBOCore.doAjax(
4029 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=bookings.delete_type_flag'); ?>",
4030 {
4031 bid: '<?php echo $row['id']; ?>',
4032 flag: 'overbooking',
4033 },
4034 (success) => {
4035 // remove "overbooking" label
4036 let parent_label = jQuery('.vbo-bookdet-container').find('.vbo-label-overbooking').parent('.label');
4037 jQuery('.vbo-bookdet-container').find('.vbo-label-overbooking').remove();
4038 parent_label.text(parent_label.text().replace(' / ', ''));
4039 },
4040 (error) => {
4041 alert(error.responseText);
4042 }
4043 );
4044 }
4045 });
4046 // sessionStorage for current tab
4047 if (typeof sessionStorage !== 'undefined' && !window.location.hash && <?php echo $printreceipt ? 'false' : 'true'; ?>) {
4048 var curtab = sessionStorage.getItem('vboEditOrderTab<?php echo $row['id']; ?>');
4049
4050 setTimeout(() => {
4051 let link = jQuery('.vbo-bookingdet-noteslogs-btn[data-id="' + curtab + '"] a');
4052
4053 if (link.length) {
4054 jQuery(".vbo-bookingdet-tab[data-vbotab='vbo-tab-admin']").trigger('click');
4055 link.trigger('click');
4056 }
4057 }, 128);
4058 }
4059 if (window.location.hash == '#tab-admin') {
4060 setTimeout(function() {
4061 jQuery(".vbo-bookingdet-tab[data-vbotab='vbo-tab-admin']").trigger('click');
4062 }, 100);
4063 }
4064 // Search customer - Start
4065 var vbocustsdelay = (function() {
4066 var timer = 0;
4067 return function(callback, ms) {
4068 clearTimeout(timer);
4069 timer = setTimeout(callback, ms);
4070 };
4071 })();
4072 function vboCustomerSearch(words) {
4073 jQuery("#vbo-searchcust-res").hide().html("");
4074 jQuery("#vbo-searchcust-loading").show();
4075 var jqxhr = jQuery.ajax({
4076 type: "POST",
4077 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=searchcustomer'); ?>",
4078 data: {
4079 kw: words,
4080 tmpl: "component"
4081 }
4082 }).done(function(cont) {
4083 if (cont) {
4084 var obj_res = typeof cont === 'string' ? JSON.parse(cont) : cont;
4085 customers_search_vals = obj_res[0];
4086 jQuery("#vbo-searchcust-res").html(obj_res[1]);
4087 } else {
4088 customers_search_vals = "";
4089 jQuery("#vbo-searchcust-res").html("----");
4090 }
4091 jQuery("#vbo-searchcust-res").show();
4092 jQuery("#vbo-searchcust-loading").hide();
4093 }).fail(function() {
4094 jQuery("#vbo-searchcust-loading").hide();
4095 alert("Error Searching.");
4096 });
4097 }
4098 jQuery("#vbo-searchcust").keyup(function(event) {
4099 vbocustsdelay(function() {
4100 var keywords = jQuery("#vbo-searchcust").val();
4101 var chars = keywords.length;
4102 if (chars > 1) {
4103 if ((event.which > 96 && event.which < 123) || (event.which > 64 && event.which < 91) || event.which == 13) {
4104 vboCustomerSearch(keywords);
4105 }
4106 } else {
4107 if (jQuery("#vbo-searchcust-res").is(":visible")) {
4108 jQuery("#vbo-searchcust-res").hide();
4109 }
4110 }
4111 }, 600);
4112 });
4113 jQuery("body").on("click", ".vbo-custsearchres-entry", function() {
4114 var custid = jQuery(this).attr("data-custid");
4115 if (confirm('<?php echo addslashes(JText::translate('VBOASSIGNNEWCUSTCONF')); ?>')) {
4116 jQuery('#newcustid').val(custid);
4117 document.adminForm.submit();
4118 return;
4119 }
4120 });
4121 // Search customer - End
4122 jQuery(".vbo-bookingdet-tab").click(function() {
4123 var newtabrel = jQuery(this).attr('data-vbotab');
4124 var oldtabrel = jQuery(".vbo-bookingdet-tab-active").attr('data-vbotab');
4125 if (newtabrel == oldtabrel) {
4126 return;
4127 }
4128 if (newtabrel == 'vbo-tab-details' && typeof sessionStorage !== 'undefined') {
4129 sessionStorage.setItem('vboEditOrderTab<?php echo $row['id']; ?>', 'details');
4130 }
4131 jQuery(".vbo-bookingdet-tab").removeClass("vbo-bookingdet-tab-active");
4132 jQuery(this).addClass("vbo-bookingdet-tab-active");
4133 jQuery("#"+oldtabrel).hide();
4134 jQuery("#"+newtabrel).fadeIn();
4135 jQuery("#vbo_active_tab").val(newtabrel);
4136 });
4137 jQuery(".vbo-bookingdet-tab[data-vbotab='<?php echo $pactive_tab; ?>']").trigger('click');
4138 // edit amount paid
4139 jQuery('#vbo-amountpaid-edit').click(function() {
4140 jQuery('#vbo-amountpaid-cont').hide();
4141 jQuery('#vbo-amountpaid-modcont').show();
4142 jQuery('input[name="newamountpaid"]').prop('disabled', false);
4143 if (jQuery('input[name="newamountrefunded"]').length) {
4144 jQuery('input[name="newamountrefunded"]').val('');
4145 }
4146 });
4147 jQuery('#vbo-amountpaid-cancedit').click(function() {
4148 jQuery('#vbo-amountpaid-modcont').hide();
4149 jQuery('#vbo-amountpaid-cont').show();
4150 });
4151 // edit amount refunded
4152 jQuery('#vbo-amountrefunded-edit').click(function() {
4153 jQuery('#vbo-amountrefunded-cont').hide();
4154 jQuery('#vbo-amountrefunded-modcont').show();
4155 jQuery('input[name="newamountrefunded"]').prop('disabled', false);
4156 if (jQuery('input[name="newamountpaid"]').length) {
4157 jQuery('input[name="newamountpaid"]').val('');
4158 }
4159 });
4160 jQuery('#vbo-amountrefunded-cancedit').click(function() {
4161 jQuery('#vbo-amountrefunded-modcont').hide();
4162 jQuery('#vbo-amountrefunded-cont').show();
4163 });
4164 // edit amount payable
4165 jQuery('#vbo-amountpayable-edit').click(function() {
4166 jQuery('#vbo-amountpayable-cont').hide();
4167 jQuery('#vbo-amountpayable-modcont').show();
4168 jQuery('input[name="newamountpayable"]').prop('disabled', false);
4169 });
4170 jQuery('#vbo-amountpayable-cancedit').click(function() {
4171 jQuery('#vbo-amountpayable-modcont').hide();
4172 jQuery('#vbo-amountpayable-cont').show();
4173 });
4174 // edit cancellation fee
4175 jQuery('#vbo-cancfee-edit').click(function() {
4176 jQuery('#vbo-cancfee-cont').hide();
4177 jQuery('#vbo-cancfee-modcont').show();
4178 jQuery('input[name="newcancfee"]').prop('disabled', false);
4179 });
4180 jQuery('#vbo-cancfee-cancedit').click(function() {
4181 jQuery('#vbo-cancfee-modcont').hide();
4182 jQuery('#vbo-cancfee-cont').show();
4183 });
4184 // chat listener
4185 if (typeof VCMChat !== 'undefined') {
4186 jQuery(window).on('chatsync', function(e) {
4187 if (!jQuery("#vcm-chat-audio-notification").length) {
4188 jQuery("body").append("<audio id=\"vcm-audio-notification\" preload=\"auto\"><source type=\"audio/mp3\" src=\"<?php echo VCM_ADMIN_URI; ?>assets/css/audio/new_chat_message.mp3\"></source></audio>");
4189 }
4190 try {
4191 var promise = document.getElementById('vcm-audio-notification').play();
4192 console.log(promise);
4193 } catch (err) {
4194 console.warn('Could not play sound', err);
4195 }
4196 });
4197 }
4198
4199 // zoom-able avatars
4200 jQuery('.vbo-customer-info-box-avatar').each(function() {
4201 var img = jQuery(this).find('img');
4202 if (!img.length) {
4203 return;
4204 }
4205 // register click listener
4206 img.on('click', function(e) {
4207 // stop events propagation
4208 e.preventDefault();
4209 e.stopPropagation();
4210
4211 // check for caption
4212 var caption = jQuery(this).attr('data-caption');
4213
4214 // build modal content
4215 var zoom_modal = jQuery('<div></div>').addClass('vbo-modal-overlay-block vbo-modal-overlay-zoom-image').css('display', 'block');
4216 var zoom_dismiss = jQuery('<a></a>').addClass('vbo-modal-overlay-close');
4217 zoom_dismiss.on('click', function() {
4218 jQuery('.vbo-modal-overlay-zoom-image').fadeOut();
4219 });
4220 zoom_modal.append(zoom_dismiss);
4221 var zoom_content = jQuery('<div></div>').addClass('vbo-modal-overlay-content vbo-modal-overlay-content-zoom-image');
4222 var zoom_head = jQuery('<div></div>').addClass('vbo-modal-overlay-content-head');
4223 var zoom_head_title = jQuery('<span></span>');
4224 if (caption) {
4225 zoom_head_title.text(caption);
4226 }
4227 var zoom_head_close = jQuery('<span></span>').addClass('vbo-modal-overlay-close-times').html('&times;');
4228 zoom_head_close.on('click', function() {
4229 jQuery('.vbo-modal-overlay-zoom-image').fadeOut();
4230 });
4231 zoom_head.append(zoom_head_title).append(zoom_head_close);
4232 var zoom_body = jQuery('<div></div>').addClass('vbo-modal-overlay-content-body vbo-modal-overlay-content-body-scroll');
4233 var zoom_image = jQuery('<div></div>').addClass('vbo-modal-zoom-image-wrap');
4234 zoom_image.append(jQuery(this).clone());
4235 zoom_body.append(zoom_image);
4236 zoom_content.append(zoom_head).append(zoom_body);
4237 zoom_modal.append(zoom_content);
4238 // append modal to body
4239 if (jQuery('.vbo-modal-overlay-zoom-image').length) {
4240 jQuery('.vbo-modal-overlay-zoom-image').remove();
4241 }
4242 jQuery('body').append(zoom_modal);
4243 });
4244 });
4245
4246 // emit the event to read all notifications in the current context
4247 VBOCore.emitEvent('vbo-nc-read-notifications', {
4248 criteria: {
4249 group: '<?php echo !empty($row['idorderota']) && !empty($row['channel']) ? 'otas' : 'website'; ?>',
4250 idorder: '<?php echo $row['id']; ?>',
4251 }
4252 });
4253
4254 // register click event on the booking task(s)
4255 document.querySelectorAll('.vbo-bookingdet-task-details[data-task-id]').forEach((task) => {
4256 const taskId = task.getAttribute('data-task-id');
4257 task.addEventListener('click', (e) => {
4258 e.stopPropagation();
4259 // define the modal cancel button
4260 let cancel_btn = jQuery('<button></button>')
4261 .attr('type', 'button')
4262 .addClass('btn')
4263 .text(Joomla.JText._('VBOCLOSE'))
4264 .on('click', () => {
4265 VBOCore.emitEvent('vbo-tm-edittask-dismiss');
4266 });
4267
4268 // define the modal save button
4269 let save_btn = jQuery('<button></button>')
4270 .attr('type', 'button')
4271 .addClass('btn btn-success')
4272 .text(Joomla.JText._('VBSAVE'))
4273 .on('click', function() {
4274 // disable button to prevent double submissions
4275 let submit_btn = jQuery(this);
4276 submit_btn.prop('disabled', true);
4277
4278 // start loading animation
4279 VBOCore.emitEvent('vbo-tm-edittask-loading');
4280
4281 // get form data
4282 const taskForm = new FormData(document.querySelector('#vbo-tm-task-manage-form'));
4283
4284 // build query parameters for the request
4285 let qpRequest = new URLSearchParams(taskForm);
4286
4287 // make sure the request always includes the assignees query parameter, even if the list is empty
4288 if (!qpRequest.has('data[assignees][]')) {
4289 qpRequest.append('data[assignees][]', []);
4290 }
4291
4292 // make sure the request always includes the tags query parameter, even if the list is empty
4293 if (!qpRequest.has('data[tags][]')) {
4294 qpRequest.append('data[tags][]', []);
4295 }
4296
4297 // make the request
4298 VBOCore.doAjax(
4299 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=taskmanager.updateTask'); ?>",
4300 qpRequest.toString(),
4301 (resp) => {
4302 // dismiss the modal on success
4303 VBOCore.emitEvent('vbo-tm-edittask-dismiss');
4304
4305 // reload the page
4306 location.reload();
4307 },
4308 (error) => {
4309 // display error message
4310 alert(error.responseText);
4311
4312 // re-enable submit button
4313 submit_btn.prop('disabled', false);
4314
4315 // stop loading
4316 VBOCore.emitEvent('vbo-tm-edittask-loading');
4317 }
4318 );
4319 });
4320
4321 // display modal
4322 let modalBody = VBOCore.displayModal({
4323 suffix: 'tm_edittask_modal',
4324 title: <?php echo json_encode(JText::translate('VBO_TASK')); ?> + ' #' + taskId,
4325 extra_class: 'vbo-modal-rounded vbo-modal-taller vbo-modal-large',
4326 body_prepend: true,
4327 lock_scroll: true,
4328 escape_dismiss: false,
4329 footer_left: cancel_btn,
4330 footer_right: save_btn,
4331 loading_event: 'vbo-tm-edittask-loading',
4332 dismiss_event: 'vbo-tm-edittask-dismiss',
4333 });
4334
4335 // start loading animation
4336 VBOCore.emitEvent('vbo-tm-edittask-loading');
4337
4338 // make the request
4339 VBOCore.doAjax(
4340 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=taskmanager.renderLayout'); ?>",
4341 {
4342 type: 'tasks.managetask',
4343 data: {
4344 task_id: taskId,
4345 form_id: 'vbo-tm-task-manage-form',
4346 },
4347 },
4348 (resp) => {
4349 // stop loading
4350 VBOCore.emitEvent('vbo-tm-edittask-loading');
4351
4352 try {
4353 // decode the response (if needed), and append the content to the modal body
4354 let obj_res = typeof resp === 'string' ? JSON.parse(resp) : resp;
4355 modalBody.append(obj_res['html']);
4356 } catch (err) {
4357 console.error('Error decoding the response', err, resp);
4358 }
4359 },
4360 (error) => {
4361 // display error message
4362 alert(error.responseText);
4363
4364 // stop loading
4365 VBOCore.emitEvent('vbo-tm-edittask-loading');
4366 }
4367 );
4368 });
4369 });
4370
4371 // register click event to copy the OTA booking ID
4372 const otaBidEl = document.querySelector('.vbo-reservation-copy-otabid');
4373 if (otaBidEl) {
4374 otaBidEl.addEventListener('click', () => {
4375 let copyEl = document.querySelector('textarea.vbo-textarea-copyable[data-copy="otabid"]');
4376 VBOCore.copyToClipboard(copyEl).then((success) => {
4377 otaBidEl.setAttribute('data-tooltiptext', <?php echo json_encode(JText::translate('VBO_COPIED') . '!'); ?>);
4378 }).catch((err) => {
4379 // do nothing
4380 });
4381 });
4382 }
4383
4384 // register events for sending a message template through a messaging account configuration
4385 const messagingAccountsData = <?php echo json_encode($messagingAccountConfigurations); ?>;
4386 const sendTplMessBtn = document.querySelector('.vbo-bookingdet-send-tplmessage-btn');
4387 const sendTplMessContWrap = document.querySelector('.vbo-bookingdet-send-tplmessage-wrap');
4388 jQuery(sendTplMessContWrap).find('select[data-element="message-template"]').on('change', function() {
4389 let maIdentifier = this.value;
4390 let previewEl = sendTplMessContWrap.querySelector('.vbo-ma-send-tplmessage-preview');
4391 previewEl.innerHTML = '';
4392 if (maIdentifier) {
4393 messagingAccountsData.forEach((maData) => {
4394 if (maData?.identifier == maIdentifier) {
4395 // update preview content
4396 previewEl.innerHTML = maData?.preview_html || '';
4397 }
4398 });
4399 }
4400 });
4401 if (sendTplMessBtn) {
4402 sendTplMessBtn.addEventListener('click', () => {
4403 let cancelBtn = document.createElement('button');
4404 cancelBtn.setAttribute('type', 'button');
4405 cancelBtn.classList.add('btn');
4406 cancelBtn.textContent = <?php echo json_encode(JText::translate('VBANNULLA')); ?>;
4407 cancelBtn.addEventListener('click', () => {
4408 VBOCore.emitEvent('vbo-send-tplmessage-dismiss');
4409 });
4410
4411 let confirmBtn = document.createElement('button');
4412 confirmBtn.setAttribute('type', 'button');
4413 confirmBtn.classList.add('btn', 'btn-primary');
4414 confirmBtn.innerHTML = '<?php VikBookingIcons::e('paper-plane'); ?> ' + <?php echo json_encode(JText::translate('VBO_SEND_MESSAGE')); ?>;
4415 confirmBtn.addEventListener('click', () => {
4416 // get message template identifier data
4417 let tplIdentifier = sendTplMessContWrap.querySelector('select[data-element="message-template"]')?.value;
4418 if (!tplIdentifier) {
4419 alert('Invalid message template');
4420 return;
4421 }
4422
4423 // obtain selected template details
4424 let tplIdentifierParts = tplIdentifier.split(':');
4425
4426 // start loading
4427 VBOCore.emitEvent('vbo-send-tplmessage-loading');
4428 confirmBtn.disabled = true;
4429
4430 // make the request
4431 VBOCore.doAjax(
4432 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=messaging.sendMessageTemplate'); ?>",
4433 {
4434 account_id: tplIdentifierParts[0],
4435 phone_id: tplIdentifierParts[1],
4436 config_id: tplIdentifierParts[2],
4437 booking_id: <?php echo $this->row['id']; ?>,
4438 },
4439 (resp) => {
4440 // dismiss modal on success
4441 VBOCore.emitEvent('vbo-send-tplmessage-dismiss');
4442
4443 // display success message
4444 VBOToast.enqueue(new VBOToastMessage({
4445 body: <?php echo json_encode(JText::translate('VBSENDEMAILOK')); ?>,
4446 icon: '<?php echo VikBookingIcons::i('check-circle'); ?>',
4447 status: VBOToast.SUCCESS_STATUS,
4448 action: () => {
4449 VBOToast.dispose(true);
4450 },
4451 }));
4452
4453 // reload the page (just for the new history event)
4454 location.reload();
4455 },
4456 (error) => {
4457 // display error message
4458 alert(error.responseText);
4459
4460 // stop loading
4461 VBOCore.emitEvent('vbo-send-tplmessage-loading');
4462 confirmBtn.disabled = false;
4463 }
4464 );
4465 });
4466
4467 let modalBody = VBOCore.displayModal({
4468 suffix: 'vbo-send-tplmessage',
4469 extra_class: 'vbo-modal-rounded',
4470 title: <?php echo json_encode(JText::translate('VBO_SEND_MESSAGE')); ?>,
4471 footer_left: cancelBtn,
4472 footer_right: confirmBtn,
4473 draggable: true,
4474 lock_scroll: true,
4475 dismiss_event: 'vbo-send-tplmessage-dismiss',
4476 loading_event: 'vbo-send-tplmessage-loading',
4477 onDismiss: () => {
4478 document.querySelector('.vbo-bookingdet-send-tplmessage-helper').append(
4479 sendTplMessContWrap
4480 );
4481 },
4482 });
4483
4484 (modalBody[0] || modalBody).append(sendTplMessContWrap);
4485 });
4486 }
4487
4488 });
4489 var cur_emtpl = <?php echo json_encode($cur_emtpl); ?>;
4490 function vboLoadEmailTpl(tplind) {
4491 if (!(tplind.length > 0)) {
4492 jQuery('#emailsubj').val('');
4493 jQuery('#emailcont').val('').trigger('change');
4494 return true;
4495 }
4496 if (tplind.substr(0, 2) == 'rm') {
4497 if (confirm(Joomla.JText._('VBDELCONFIRM'))) {
4498 document.location.href = 'index.php?option=com_vikbooking&task=rmcustomemailtpl&cid[]=<?php echo $row['id']; ?>&tplind='+tplind.substr(2);
4499 }
4500 return false;
4501 }
4502 if (!cur_emtpl.hasOwnProperty(tplind)) {
4503 jQuery('#emailsubj').val('');
4504 jQuery('#emailcont').val('').trigger('change');
4505 return true;
4506 }
4507 jQuery('#emailsubj').val(cur_emtpl[tplind]['emailsubj']);
4508 jQuery('#emailcont').val(cur_emtpl[tplind]['emailcont']).trigger('change');
4509 jQuery('#emailfrom').val(cur_emtpl[tplind]['emailfrom']);
4510 return true;
4511 }
4512 <?php
4513 $pcustomemail = VikRequest::getInt('customemail', '', 'request');
4514 if ($pcustomemail > 0) {
4515 ?>
4516 vboDisplaySendEmail();
4517 <?php
4518 }
4519 if ($printreceipt) {
4520 ?>
4521 jQuery(function() {
4522 jQuery('button, .vbo-bookingdet-innertop').hide();
4523 jQuery('body').find('a').each(function(k, v) {
4524 jQuery(this).replaceWith(jQuery(this).html());
4525 });
4526 jQuery('body').find("input[type='text']").each(function(k, v) {
4527 jQuery(this).replaceWith(jQuery(this).val());
4528 });
4529 });
4530 function vboMakePrintOnly() {
4531 vbo_print_only = true;
4532 jQuery(".vbo-receipt-numdate-block").remove();
4533 jQuery("#vbo-receipt-print-btn-name").text("<?php echo addslashes(JText::translate('VBOPRINT')); ?>");
4534 }
4535 function vboLaunchPrintReceipt() {
4536 var rcnotes = jQuery('#vbo-receipt-notes').val();
4537 var rnewnum = jQuery('#vbo-receipt-num-inp').val();
4538 if (rcnotes.length) {
4539 if (rcnotes.indexOf('<') < 0) {
4540 rcnotes = rcnotes.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1<br />$2');
4541 }
4542 jQuery('#vbo-receipt-notes-val').html(rcnotes);
4543 } else {
4544 jQuery('.vbo-receipt-notes-container').remove();
4545 }
4546 if (vbo_print_only === true) {
4547 window.print();
4548 return;
4549 }
4550 jQuery.ajax({
4551 type: "POST",
4552 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=updatereceiptnum'); ?>",
4553 data: {
4554 newnum: rnewnum,
4555 newnotes: rcnotes,
4556 oid: "<?php echo $row['id']; ?>"
4557 }
4558 }).done(function(res) {
4559 window.print();
4560 }).fail(function() {
4561 alert('Could not update the next receipt number.')
4562 window.print();
4563 });
4564 }
4565 <?php
4566 }
4567 ?>
4568 </script>
4569