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

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

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