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
← All changes | admin/views/editorder/tmpl/default.php +2168 -518 1.6.4 → 1.8.16 View file →
@@ -15,10 +15,11 @@
15 15 $busy = $this->busy;
16 16 $customer = $this->customer;
17 17 $payments = $this->payments;
18 18
19 -$history_obj = VikBooking::getBookingHistoryInstance();
20 -$history_obj->setBid($row['id']);
19 +// load registry and history
20 +$registry = VBOBookingRegistry::getInstance($this->row, $this->rooms);
21 +$history_obj = VikBooking::getBookingHistoryInstance($row['id']);
21 22
22 23 // availability helper
23 24 $av_helper = VikBooking::getAvailabilityInstance();
24 25
@@ -31,14 +32,30 @@
31 32 JText::script('VBO_CONV_RES_OTA_CURRENCY_APPLY');
32 33 JText::script('VBDELCONFIRM');
33 34 JText::script('VBSENDCANCORDEMAIL');
34 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');
35 48
36 49 $dbo = JFactory::getDbo();
37 50
38 51 $vbo_app = VikBooking::getVboApplication();
39 52 $vbo_app->loadVisualEditorAssets();
53 +$vbo_app->prepareJavaScriptCurrency();
40 54
55 +// preload chat assets
56 +VBOFactory::getChatMediator()->useAssets();
57 +
41 58 /**
42 59 * This View can render within a modal the "bookingcheckin" View, and with WP
43 60 * this is loaded via AJAX. In order to not interfere or reset the contextual menu,
44 61 * we load the assets from the parent View. Context menu may also be used in this View.
@@ -53,9 +70,16 @@
53 70
54 71 $canDo = JFactory::getUser();
55 72 $vbo_auth_bookings = $canDo->authorise('core.vbo.bookings', 'com_vikbooking');
56 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)) : [];
57 80 $currencyname = VikBooking::getCurrencyName();
81 +$currencysymb = VikBooking::getCurrencySymb();
58 82 $after_tax = VikBooking::ivaInclusa();
59 83 $nowdf = VikBooking::getDateFormat(true);
60 84 if ($nowdf == "%d/%m/%Y") {
61 85 $df = 'd/m/Y';
@@ -103,10 +127,9 @@
103 127 continue;
104 128 }
105 129 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `id`=".(int)$or['idtar'].";";
106 130 $dbo->setQuery($q);
107 - $dbo->execute();
108 - $tar = $dbo->getNumRows() ? $dbo->loadAssocList() : array();
131 + $tar = $dbo->loadAssocList();
109 132 $tar = VikBooking::applySeasonsRoom($tar, $row['checkin'], $row['checkout']);
110 133
111 134 // apply OBP rules
112 135 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
@@ -134,8 +157,9 @@
134 157 $daysdiff = ceil($daysdiff);
135 158 }
136 159 }
137 160 }
161 +
138 162 $otachannel = '';
139 163 $otachannel_name = '';
140 164 $otachannel_bid = '';
141 165 $otacurrency = '';
@@ -147,12 +171,31 @@
147 171 if (strstr($otachannel, '.') !== false) {
148 172 $otaccparts = explode('.', $otachannel);
149 173 $otachannel = $otaccparts[0];
150 174 }
151 - $otacurrency = strlen($row['chcurrency']) > 0 ? $row['chcurrency'] : '';
175 + $otacurrency = strlen((string) $row['chcurrency']) > 0 ? $row['chcurrency'] : '';
152 176 }
153 177
154 -$status_type = !empty($row['type']) ? JText::translate('VBO_BTYPE_' . strtoupper($row['type'])) . ' / ' : '';
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 +}
155 198 $extra_status = $row['refund'] > 0 ? ' / ' . JText::translate('VBO_STATUS_REFUNDED') : '';
156 199 if ($row['status'] == "confirmed") {
157 200 $saystaus = '<span class="label label-success">' . $status_type . JText::translate('VBCONFIRMED') . $extra_status . '</span>';
158 201 } elseif ($row['status'] == "standby") {
@@ -157,9 +200,9 @@
157 200 $saystaus = '<span class="label label-success">' . $status_type . JText::translate('VBCONFIRMED') . $extra_status . '</span>';
158 201 } elseif ($row['status'] == "standby") {
159 202 $saystaus = '<span class="label label-warning">' . $status_type . JText::translate('VBSTANDBY') . $extra_status . '</span>';
160 203 } else {
161 - $saystaus = '<span class="label label-error" style="background-color: #d9534f;">' . $status_type . JText::translate('VBCANCELLED') . $extra_status . '</span>';
204 + $saystaus = '<span class="label label-error">' . $status_type . JText::translate('VBCANCELLED') . $extra_status . '</span>';
162 205 }
163 206
164 207 // extend booking details main panel
165 208 $bookingPanelForms = $this->onDisplayView();
@@ -174,8 +217,24 @@
174 217
175 218 // extend administration sidebar
176 219 $adminSidebarForms = $this->onDisplayView('AdministrationSidebar');
177 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 +
178 237 //Prepare modal (used for the Registration and for reconstructing the credit card details through the channel manager)
179 238 echo $vbo_app->getJmodalScript();
180 239 //end Prepare modal
181 240 ?>
@@ -305,9 +364,9 @@
305 364 <span><?php echo date(str_replace("/", $datesep, $df).' H:i', $row['ts']); ?></span>
306 365 </div>
307 366 </div>
308 367 <?php
309 - if (!$printreceipt && count($customer)) {
368 + if (!$printreceipt && $customer) {
310 369 ?>
311 370 <div class="vbo-bookdet-wrap">
312 371 <div class="vbo-bookdet-head">
313 372 <span><?php echo JText::translate('VBCUSTOMERNOMINATIVE'); ?></span>
@@ -410,9 +469,9 @@
410 469 $checked_btn = 'btn-warning';
411 470 break;
412 471 default:
413 472 $checked_status = JText::translate('VBOCHECKEDSTATUSZERO');
414 - if (count($customer) && isset($customer['pax_data']) && !empty($customer['pax_data'])) {
473 + if ($customer && isset($customer['pax_data']) && !empty($customer['pax_data'])) {
415 474 // pre check-in performed via front-end
416 475 $checked_status = JText::translate('VBOCHECKEDSTATUSPRECHECKIN');
417 476 }
418 477 break;
@@ -434,23 +493,48 @@
434 493 //end Prepare modal
435 494 }
436 495
437 496 /**
438 - * Check whether the booking can be refunded.
497 + * Check whether the booking can be refunded or charged through an off-session capturing.
439 498 *
440 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.
441 501 */
442 502
443 - // refundable up to 3 days after check-out day
444 - $max_refund_ts = mktime(23, 59, 59, $checkout_info['mon'], ($checkout_info['mday'] + 3), $checkout_info['year']);
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 +
445 506 // current payment driver must be set
446 507 $tn_driver = is_array($payment) ? $payment['file'] : null;
508 +
447 509 // transaction data validation callback
448 510 $tn_data_callback = function($data) use ($tn_driver) {
449 511 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
450 512 };
451 513 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
452 - $refundable = ($row['status'] != 'standby' && $max_refund_ts >= time() && is_array($prev_tn_data) && count($prev_tn_data));
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 +
453 537 if ($refundable) {
454 538 // prepare modal (refundtn) with a custom function to trigger the opening
455 539 array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-refund-tn', JText::translate('VBO_ISSUE_REFUND')));
456 540 echo $vbo_app->getJmodalScript('Refund', 'vboDetectRefundChanges();');
@@ -471,9 +555,9 @@
471 555 <div class="vbo-bookdet-head">
472 556 <span><?php echo JText::translate('VBO_ISSUE_REFUND'); ?></span>
473 557 </div>
474 558 <div class="vbo-bookdet-foot">
475 - <button type="button" class="btn btn-small btn-danger vbo-dorefund-btn"<?php echo count($refunds) ? ' data-totrefunds="' . count($refunds) . '"' : ''; ?> onclick="vboOpenJModalRefund('vbo-refund-tn', 'index.php?option=com_vikbooking&task=refundtn&cid[]=<?php echo $row['id']; ?>&tmpl=component');">
559 + <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');">
476 560 <?php echo JText::translate('VBO_REFUND'); ?>
477 561 </button>
478 562 </div>
479 563 </div>
@@ -478,9 +562,8 @@
478 562 </div>
479 563 </div>
480 564 <?php
481 565 }
482 - //
483 566
484 567 if (!$printreceipt && !empty($row['channel'])) {
485 568 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
486 569 if ($ota_logo_img === false) {
@@ -579,9 +662,9 @@
579 662 </div>
580 663 </div>
581 664 <?php
582 665 }
583 - if (!empty($row['channel']) && stripos($row['channel'], 'booking.com') !== false && $row['checkin'] <= time() && strtotime('+ 7 days', $row['checkout']) >= time()) {
666 + if (!empty($row['channel']) && stripos($row['channel'], 'booking.com') !== false && $row['checkin'] <= $current_ts && strtotime('+ 7 days', $row['checkout']) >= $current_ts) {
584 667 /**
585 668 * Guest misconduct reporting API for Booking.com.
586 669 * Only after reservation check-in date and no later than 7 days after check-out date.
587 670 *
@@ -608,309 +691,314 @@
608 691 }
609 692 ?>
610 693 <a id="vbo-gm-reloadlink" style="display: none;" href="index.php?option=com_vikbooking&task=editorder&cid[]=<?php echo $row['id']; ?>"></a>
611 694 </div>
612 - </div>
613 695
614 - <div class="vbo-modal-overlay-block vbo-modal-overlay-block-guestmisconduct">
615 - <a class="vbo-modal-overlay-close" href="javascript: void(0);"></a>
616 - <div class="vbo-modal-overlay-content vbo-modal-overlay-content-guestmisconduct">
617 - <div class="vbo-modal-overlay-content-head vbo-modal-overlay-content-head-guestmisconduct">
618 - <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>
619 - </div>
620 - <div class="vbo-modal-overlay-content-body">
621 - <div class="vbo-modal-guestmisconduct-addnew" data-bid="<?php echo $row['id']; ?>" data-otabid="<?php echo $row['idorderota']; ?>">
622 - <div class="vbo-modal-guestmisconduct-report-elems"></div>
623 - <div class="vbo-modal-guestmisconduct-addnew-save">
624 - <button type="button" id="vbo-guest-misconduct-submit-btn" class="btn btn-success" onclick="vboSubmitGuestMisconduct();" style="display: none;"><?php echo JText::translate('VBCHANNELMANAGERSENDRQ'); ?></button>
625 - <button type="button" class="btn btn-danger" onclick="hideVboDialogGuestMisconduct();"><?php echo JText::translate('VBOCLOSE'); ?></button>
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>
626 709 </div>
627 710 </div>
628 711 </div>
629 712 </div>
630 - </div>
631 713
632 - <script type="text/javascript">
633 - var vbodialogguestmisconduct_on = false;
634 - var vbo_guest_misconduct_fields = new Array;
714 + <script type="text/javascript">
715 + var vbodialogguestmisconduct_on = false;
716 + var vbo_guest_misconduct_fields = new Array;
635 717
636 - function vboShowGuestMisconductReported() {
637 - // this is like simulating the navigation to the booking history tab
638 - jQuery(".vbo-bookingdet-tab[data-vbotab='vbo-tab-admin']").trigger('click');
639 - vbToggleHistory(document.getElementById('vbo-trig-bookhistory'));
640 - }
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 + }
641 723
642 - function vboRenderGuestMisconduct() {
643 - // empty content
644 - jQuery('.vbo-modal-guestmisconduct-report-elems').html('<?php echo $this->escape(JText::translate('VIKLOADING') . '...'); ?>');
645 - vbo_guest_misconduct_fields = new Array;
646 - // display modal
647 - jQuery('.vbo-modal-overlay-block-guestmisconduct').fadeIn();
648 - vbodialogguestmisconduct_on = true;
649 - // make AJAX request to VCM to always reload the form fields
650 - var jqxhr = jQuery.ajax({
651 - type: "POST",
652 - url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikchannelmanager&task=get_bcom_misconduct_categories'); ?>",
653 - data: { tmpl: "component" }
654 - }).done(function(res) {
655 - // parse the JSON response that contains the categories object with all fields for the reporting
656 - try {
657 - var misconduct_fields_rs = JSON.parse(res);
658 - console.log(misconduct_fields_rs);
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;
659 728
660 - // make sure the request was successful
661 - if (!misconduct_fields_rs.status) {
662 - alert(misconduct_fields_rs.error);
663 - hideVboDialogGuestMisconduct();
664 - return false;
665 - }
729 + // display modal
730 + jQuery('.vbo-modal-overlay-block-guestmisconduct').fadeIn();
731 + vbodialogguestmisconduct_on = true;
666 732
667 - // render form from response obtained
668 - var misconduct_html = '';
669 - var misconduct_fields = misconduct_fields_rs.data;
670 - if (!misconduct_fields.hasOwnProperty('categories') || !misconduct_fields.hasOwnProperty('fields')) {
671 - alert('Unexptected response. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
672 - hideVboDialogGuestMisconduct();
673 - return false;
674 - }
675 -
676 - // main category of misconduct
677 - misconduct_html += '<div class="vbo-modal-form-addnew-elem vbo-modal-guestmisconduct-addnew-elem">' + "\n";
678 - misconduct_html += '<label for="vbo-gm-category">' + misconduct_fields['labels']['category'] + '</label>';
679 - misconduct_html += '<select id="vbo-gm-category" data-gmname="category_id" onchange="vboGuestMisconductChangeCategory(this.value);">' + "\n";
680 - for (var category in misconduct_fields['categories']) {
681 - if (!misconduct_fields['categories'].hasOwnProperty(category)) {
682 - continue;
683 - }
684 - misconduct_html += '<option value="' + misconduct_fields['categories'][category]['id'] + '">' + misconduct_fields['categories'][category]['title'] + '</option>' + "\n";
685 - }
686 - misconduct_html += '</select>' + "\n";
687 - misconduct_html += '</div>' + "\n";
688 - // push category field in fields list for later submit
689 - vbo_guest_misconduct_fields.push('vbo-gm-category');
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;
690 743
691 - // sub-categories or additional fields of misconduct categories
692 - for (var category in misconduct_fields['categories']) {
693 - if (!misconduct_fields['categories'].hasOwnProperty(category)) {
694 - continue;
695 - }
696 - if (!misconduct_fields['categories'][category].hasOwnProperty('subcategories') && !misconduct_fields['categories'][category].hasOwnProperty('additional_fields')) {
697 - // at least one of these two properties must be set
698 - continue;
699 - }
700 - if (misconduct_fields['categories'][category].hasOwnProperty('subcategories') && misconduct_fields['categories'][category]['subcategories'].length) {
701 - // sub-categories in drop down
702 - var subcat_field_id = 'vbo-gm-subcategory' + misconduct_fields['categories'][category]['id'];
703 - 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";
704 - misconduct_html += '<label for="' + subcat_field_id + '">' + misconduct_fields['labels']['subcategory'] + '</label>';
705 - misconduct_html += '<select id="' + subcat_field_id + '" data-gmname="subcategory_id">' + "\n";
706 - for (var subcategory in misconduct_fields['categories'][category]['subcategories']) {
707 - if (!misconduct_fields['categories'][category]['subcategories'].hasOwnProperty(subcategory)) {
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)) {
708 766 continue;
709 767 }
710 - misconduct_html += '<option value="' + misconduct_fields['categories'][category]['subcategories'][subcategory]['id'] + '">' + misconduct_fields['categories'][category]['subcategories'][subcategory]['title'] + '</option>' + "\n";
768 + misconduct_html += '<option value="' + misconduct_fields['categories'][category]['id'] + '">' + misconduct_fields['categories'][category]['title'] + '</option>' + "\n";
711 769 }
712 770 misconduct_html += '</select>' + "\n";
713 771 misconduct_html += '</div>' + "\n";
714 - // push sub-category field in fields list for later submit
715 - if (vbo_guest_misconduct_fields.indexOf(subcat_field_id) < 0) {
716 - vbo_guest_misconduct_fields.push(subcat_field_id);
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 + }
717 836 }
718 - } else if (misconduct_fields['categories'][category].hasOwnProperty('additional_fields') && misconduct_fields['categories'][category]['additional_fields'].length) {
719 - // additional fields
720 - for (var extra_field in misconduct_fields['categories'][category]['additional_fields']) {
721 - if (!misconduct_fields['categories'][category]['additional_fields'].hasOwnProperty(extra_field)) {
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)) {
722 841 continue;
723 842 }
724 - var field_id = 'vbo-gm-extrafield-' + misconduct_fields['categories'][category]['additional_fields'][extra_field]['name'];
725 - var field_name = misconduct_fields['categories'][category]['additional_fields'][extra_field]['name'];
726 - 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";
727 - misconduct_html += '<label for="' + field_id + '">' + misconduct_fields['categories'][category]['additional_fields'][extra_field]['label'] + '</label>';
728 - if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'number') {
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') {
729 848 misconduct_html += '<input data-gmname="' + field_name + '" type="number" id="' + field_id + '" value="" step="any" min="0" />';
730 - } else if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'text') {
849 + } else if (misconduct_fields['fields'][mandfield]['type'] == 'text') {
731 850 misconduct_html += '<input data-gmname="' + field_name + '" type="text" id="' + field_id + '" value="" />';
732 - } else if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'text') {
851 + } else if (misconduct_fields['fields'][mandfield]['type'] == 'text') {
733 852 misconduct_html += '<input data-gmname="' + field_name + '" type="text" id="' + field_id + '" value="" />';
734 - } else if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'textarea') {
853 + } else if (misconduct_fields['fields'][mandfield]['type'] == 'textarea') {
735 854 misconduct_html += '<textarea data-gmname="' + field_name + '" id="' + field_id + '" rows="5" cols="50" maxlength="240"></textarea>';
736 - } else if (misconduct_fields['categories'][category]['additional_fields'][extra_field]['type'] == 'select') {
855 + } else if (misconduct_fields['fields'][mandfield]['type'] == 'select') {
737 856 misconduct_html += '<select data-gmname="' + field_name + '" id="' + field_id + '">';
738 - for (var choicekey in misconduct_fields['categories'][category]['additional_fields'][extra_field]['choices']) {
739 - // 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
740 - if (!misconduct_fields['categories'][category]['additional_fields'][extra_field]['choices'].hasOwnProperty(choicekey)) {
857 + for (var choicekey in misconduct_fields['fields'][mandfield]['choices']) {
858 + if (!misconduct_fields['fields'][mandfield]['choices'].hasOwnProperty(choicekey)) {
741 859 continue;
742 860 }
743 - misconduct_html += '<option value="' + choicekey + '">' + misconduct_fields['categories'][category]['additional_fields'][extra_field]['choices'][choicekey] + '</option>';
861 + misconduct_html += '<option value="' + choicekey + '">' + misconduct_fields['fields'][mandfield]['choices'][choicekey] + '</option>';
744 862 }
745 863 misconduct_html += '</select>';
746 864 }
747 865 misconduct_html += '</div>' + "\n";
748 - // push additional field in fields list for later submit
866 + // push mandatory field in fields list for later submit
749 867 vbo_guest_misconduct_fields.push(field_id);
750 868 }
751 - }
752 - }
753 869
754 - // mandatory fields for all categories of guest misconduct reporting
755 - for (var mandfield in misconduct_fields['fields']) {
756 - if (!misconduct_fields['fields'].hasOwnProperty(mandfield)) {
757 - continue;
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;
758 880 }
759 - var field_id = 'vbo-gm-mandfield-' + misconduct_fields['fields'][mandfield]['name'];
760 - var field_name = misconduct_fields['fields'][mandfield]['name'];
761 - misconduct_html += '<div class="vbo-modal-form-addnew-elem vbo-modal-guestmisconduct-addnew-elem">' + "\n";
762 - misconduct_html += '<label for="' + field_id + '">' + misconduct_fields['fields'][mandfield]['label'] + '</label>';
763 - if (misconduct_fields['fields'][mandfield]['type'] == 'number') {
764 - misconduct_html += '<input data-gmname="' + field_name + '" type="number" id="' + field_id + '" value="" step="any" min="0" />';
765 - } else if (misconduct_fields['fields'][mandfield]['type'] == 'text') {
766 - misconduct_html += '<input data-gmname="' + field_name + '" type="text" id="' + field_id + '" value="" />';
767 - } else if (misconduct_fields['fields'][mandfield]['type'] == 'text') {
768 - misconduct_html += '<input data-gmname="' + field_name + '" type="text" id="' + field_id + '" value="" />';
769 - } else if (misconduct_fields['fields'][mandfield]['type'] == 'textarea') {
770 - misconduct_html += '<textarea data-gmname="' + field_name + '" id="' + field_id + '" rows="5" cols="50" maxlength="240"></textarea>';
771 - } else if (misconduct_fields['fields'][mandfield]['type'] == 'select') {
772 - misconduct_html += '<select data-gmname="' + field_name + '" id="' + field_id + '">';
773 - for (var choicekey in misconduct_fields['fields'][mandfield]['choices']) {
774 - if (!misconduct_fields['fields'][mandfield]['choices'].hasOwnProperty(choicekey)) {
775 - continue;
776 - }
777 - misconduct_html += '<option value="' + choicekey + '">' + misconduct_fields['fields'][mandfield]['choices'][choicekey] + '</option>';
778 - }
779 - misconduct_html += '</select>';
780 - }
781 - misconduct_html += '</div>' + "\n";
782 - // push mandatory field in fields list for later submit
783 - vbo_guest_misconduct_fields.push(field_id);
881 + },
882 + (err) => {
883 + hideVboDialogGuestMisconduct();
884 + alert('Request failed. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
784 885 }
886 + );
887 + }
785 888
786 - // display HTML content and submit button
787 - jQuery('.vbo-modal-guestmisconduct-report-elems').html(misconduct_html);
788 - jQuery('#vbo-guest-misconduct-submit-btn').show();
789 - // trigger change of main category drop down
790 - jQuery('#vbo-gm-category').trigger('change');
791 - } catch (e) {
792 - console.log(res);
793 - alert('Invalid response. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
794 - hideVboDialogGuestMisconduct();
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.');
795 892 return false;
796 893 }
797 - }).fail(function() {
798 - alert('Request failed. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
799 - hideVboDialogGuestMisconduct();
800 - });
801 - }
894 +
895 + // prevent double submissions
896 + vboGuestMisconductDisableSubmit();
897 + //
802 898
803 - function vboSubmitGuestMisconduct() {
804 - if (!vbo_guest_misconduct_fields.length) {
805 - alert('Empty data to submit. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
806 - return false;
807 - }
808 -
809 - // prevent double submissions
810 - vboGuestMisconductDisableSubmit();
811 - //
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 + }
812 921
813 - var submit_fields = {
814 - tmpl: "component",
815 - bid: jQuery('.vbo-modal-guestmisconduct-addnew').attr('data-bid'),
816 - otabid: jQuery('.vbo-modal-guestmisconduct-addnew').attr('data-otabid'),
817 - bcom_keys: new Array
818 - };
819 - for (var elemid in vbo_guest_misconduct_fields) {
820 - if (!vbo_guest_misconduct_fields.hasOwnProperty(elemid)) {
821 - continue;
822 - }
823 - if (!jQuery('#' + vbo_guest_misconduct_fields[elemid]).length || !jQuery('#' + vbo_guest_misconduct_fields[elemid]).closest('.vbo-modal-guestmisconduct-addnew-elem').length) {
824 - // form element not found, or parent container not found
825 - continue;
826 - }
827 - if (jQuery('#' + vbo_guest_misconduct_fields[elemid]).closest('.vbo-modal-guestmisconduct-addnew-elem').is(':visible')) {
828 - // we include this value in the AJAX request
829 - var field_name = jQuery('#' + vbo_guest_misconduct_fields[elemid]).attr('data-gmname');
830 - var submit_key = 'bcom_' + field_name;
831 - submit_fields[submit_key] = jQuery('#' + vbo_guest_misconduct_fields[elemid]).val();
832 - submit_fields['bcom_keys'].push(submit_key);
833 - }
834 - }
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);
835 931
836 - // make the AJAX request to VCM
837 - var jqxhr = jQuery.ajax({
838 - type: "POST",
839 - url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikchannelmanager&task=submit_bcom_guestmisconduct'); ?>",
840 - data: submit_fields
841 - }).done(function(res) {
842 - try {
843 - var misconduct_rs = JSON.parse(res);
844 - console.log(submit_fields, misconduct_rs);
932 + // make sure the request was successful
933 + if (!misconduct_rs.status) {
934 + alert(misconduct_rs.error);
935 + vboGuestMisconductEnableSubmit();
936 + return false;
937 + }
845 938
846 - // make sure the request was successful
847 - if (!misconduct_rs.status) {
848 - alert(misconduct_rs.error);
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.');
849 960 vboGuestMisconductEnableSubmit();
961 + hideVboDialogGuestMisconduct();
850 962 return false;
851 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 + }
852 970
853 - // make another AJAX request (now on VBO) to update the booking history
854 - var event_descr = jQuery('#vbo-gm-mandfield-details_text').length ? jQuery('#vbo-gm-mandfield-details_text').val() : '';
855 - jQuery.ajax({
856 - type: "POST",
857 - url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=store_booking_history_event'); ?>",
858 - data: {
859 - tmpl: "component",
860 - bid: jQuery('.vbo-modal-guestmisconduct-addnew').attr('data-bid'),
861 - event: 'GM',
862 - descr: event_descr
863 - }
864 - }).done(function(res) {
865 - // just reload the page in case of success
866 - document.location.href = jQuery('#vbo-gm-reloadlink').attr('href');
867 - }).fail(function() {
868 - // we reload the page even in case of failure
869 - document.location.href = jQuery('#vbo-gm-reloadlink').attr('href');
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();
870 975 });
871 - } catch (e) {
872 - console.log(res);
873 - alert('Invalid update response. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
874 - vboGuestMisconductEnableSubmit();
875 - hideVboDialogGuestMisconduct();
876 - return false;
976 + // turn flag off
977 + vbodialogguestmisconduct_on = false;
877 978 }
878 - }).fail(function() {
879 - alert('Update Request failed. Vik Channel Manager needs to be installed, configured and updated to the latest version.');
880 - vboGuestMisconductEnableSubmit();
881 - return false;
882 - });
883 - }
979 + }
884 980
885 - function hideVboDialogGuestMisconduct() {
886 - if (vbodialogguestmisconduct_on === true) {
887 - jQuery(".vbo-modal-overlay-block-guestmisconduct").fadeOut(400, function () {
888 - jQuery(".vbo-modal-overlay-content-guestmisconduct").show();
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 + }
889 988 });
890 - // turn flag off
891 - vbodialogguestmisconduct_on = false;
892 989 }
893 - }
894 990
895 - function vboGuestMisconductChangeCategory(gmcid) {
896 - jQuery('.vbo-modal-guestmisconduct-addnew-cond').each(function() {
897 - if (jQuery(this).attr('data-gmcid') == gmcid) {
898 - jQuery(this).show();
899 - } else {
900 - jQuery(this).hide();
901 - }
902 - });
903 - }
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 + }
904 994
905 - function vboGuestMisconductDisableSubmit() {
906 - jQuery('#vbo-guest-misconduct-submit-btn').prepend('<i class="<?php echo VikBookingIcons::i('refresh', 'fa-spin fa-fw'); ?>"></i> ').prop('disabled', true);
907 - }
995 + function vboGuestMisconductEnableSubmit() {
996 + jQuery('#vbo-guest-misconduct-submit-btn').prop('disabled', false).find('i').remove();
997 + }
998 + </script>
908 999
909 - function vboGuestMisconductEnableSubmit() {
910 - jQuery('#vbo-guest-misconduct-submit-btn').prop('disabled', false).find('i').remove();
911 - }
912 - </script>
1000 + </div>
913 1001 <?php
914 1002 }
915 1003 if ($this->vcm_host_to_guest_review) {
916 1004 ?>
@@ -962,15 +1050,15 @@
962 1050 </div>
963 1051 <?php
964 1052 }
965 1053
966 - if (!$printreceipt && $row['status'] == "standby" && empty($row['idorderota']) && !strcasecmp($row['type'], 'Inquiry')) {
1054 + if (!$printreceipt && $row['status'] == "standby" && empty($row['idorderota']) && !strcasecmp((string)$row['type'], 'Inquiry')) {
967 1055 // website pending reservation inquiry
968 1056 $ir_data_callback = function($data) {
969 1057 return (is_object($data) && !empty($data->av_type));
970 1058 };
971 1059 $prev_ir_data = $history_obj->getEventsWithData('IR', $ir_data_callback, true);
972 - if (is_array($prev_ir_data) && count($prev_ir_data)) {
1060 + if (is_array($prev_ir_data) && $prev_ir_data) {
973 1061 // display a message about the availability type at the time of creation of the inquiry reservation
974 1062
975 1063 // parse original stay dates into DateTime objects
976 1064 $orig_checkin_dt_obj = new JDate($prev_ir_data[0]->checkin_date);
@@ -977,9 +1065,9 @@
977 1065 $orig_checkout_dt_obj = new JDate($prev_ir_data[0]->checkout_date);
978 1066 ?>
979 1067 <div class="vbo-bookdet-container vbo-bookdet-inquiry-alert">
980 1068 <div class="vbo-bookdet-inquiry-alert-dismiss">
981 - <button type="button" class="btn btn-warning" onclick="jQuery('.vbo-bookdet-inquiry-alert').remove();"><?php VikBookingIcons::e('times-circle'); ?> <?php echo JText::translate('VBOBTNKEEPREMIND'); ?></button>
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>
982 1070 </div>
983 1071 <div class="vbo-bookdet-inquiry-alert-message">
984 1072 <div class="vbo-bookdet-inquiry-alert-top">
985 1073 <span><?php echo JText::translate('VBO_WEB_INQUIRY_ALERT'); ?></span>
@@ -1013,8 +1101,43 @@
1013 1101 </div>
1014 1102 <div class="vbo-bookdet-inquiry-alert-bottom">
1015 1103 <span><?php echo JText::translate('VBO_WEB_INQUIRY_SUGG'); ?></span>
1016 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 + ?>
1017 1140 </div>
1018 1141 </div>
1019 1142 <?php
1020 1143 }
@@ -1030,16 +1153,23 @@
1030 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>
1031 1154 </div>
1032 1155 <?php
1033 1156 }
1034 - if ((array_key_exists(1, $tars) && count($tars[1]) > 0) || ($is_package || $is_cust_cost)) {
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)) {
1035 1165
1036 1166 if (VBOPlatformDetection::isWordPress()) {
1037 1167 /**
1038 1168 * @wponly display warning message if no valid Shortcodes found
1039 1169 */
1040 - $model = JModel::getInstance('vikbooking', 'shortcodes');
1041 - $itemid = $model->best('booking');
1170 + $model = JModel::getInstance('vikbooking', 'shortcodes');
1171 + $itemid = $model->best('booking');
1042 1172 if (!$itemid) {
1043 1173 VikError::raiseWarning('', 'No Shortcodes found, or no Shortcodes being used in Pages/Posts.');
1044 1174 }
1045 1175 }
@@ -1049,9 +1179,9 @@
1049 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>
1050 1180 </div>
1051 1181 <?php
1052 1182 }
1053 - if (($row['status'] == "confirmed" || ($row['status'] == "standby" && !empty($row['custmail']))) && ((array_key_exists(1, $tars) && count($tars[1]) > 0) || ($is_package || $is_cust_cost))) {
1183 + if (($row['status'] == "confirmed" || ($row['status'] == "standby" && !empty($row['custmail']))) && ((array_key_exists(1, $tars) && $tars[1]) || ($is_package || $is_cust_cost))) {
1054 1184 ?>
1055 1185 <div class="vbo-bookingdet-command">
1056 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>
1057 1187 </div>
@@ -1076,9 +1206,9 @@
1076 1206 </div>
1077 1207 <?php
1078 1208 }
1079 1209 }
1080 - if ($row['status'] == "standby" || ($row['status'] == "cancelled" && $row['checkout'] >= time())) {
1210 + if ($row['status'] == "standby" || ($row['status'] == "cancelled" && $row['checkout'] >= $current_ts)) {
1081 1211 ?>
1082 1212 <div class="vbo-bookingdet-command">
1083 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>
1084 1214 </div>
@@ -1087,9 +1217,9 @@
1087 1217 if ($row['status'] == "cancelled" && !$row['closure']) {
1088 1218 ?>
1089 1219 <div class="vbo-bookingdet-command">
1090 1220 <button type="button" class="btn btn-warning vbo-context-menu-btn vbo-context-menu-actionscanc">
1091 - <span class="vbo-context-menu-lbl"><?php echo JText::translate('VBCRONACTIONS'); ?> &#8230;</span>
1221 + <span class="vbo-context-menu-lbl"><?php echo JText::translate('VBCRONACTIONS'); ?></span>
1092 1222 <span class="vbo-context-menu-ico"><?php VikBookingIcons::e('sort-down'); ?></span>
1093 1223 </button>
1094 1224 </div>
1095 1225
@@ -1118,9 +1248,9 @@
1118 1248 text: Joomla.JText._('VBO_SET_STANDBY'),
1119 1249 class: 'vbo-context-menu-entry-warning',
1120 1250 separator: false,
1121 1251 action: (root, config) => {
1122 - document.location.href = 'index.php?option=com_vikbooking&task=bookings.set_to_pending&bid=<?php echo $row['id']; ?>';
1252 + document.location.href = '<?php echo VBOFactory::getPlatform()->getUri()->addCSRF('index.php?option=com_vikbooking&task=bookings.set_to_pending&bid=' . $row['id']); ?>';
1123 1253 },
1124 1254 },
1125 1255 ],
1126 1256 });
@@ -1190,11 +1320,84 @@
1190 1320 <div class="vbo-bookingdet-tab" data-vbotab="vbo-tab-admin"><?php echo JText::translate('VBOBOOKDETTABADMIN'); ?></div>
1191 1321 </div>
1192 1322 </div>
1193 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 +
1194 1341 <div class="vbo-bookingdet-tab-cont" id="vbo-tab-details" style="display: block;">
1195 1342 <div class="vbo-bookingdet-innercontainer">
1196 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 + ?>
1197 1400 <div class="vbo-bookingdet-detcont<?php echo $row['closure'] > 0 ? ' vbo-bookingdet-closure' : ''; ?>">
1198 1401 <?php
1199 1402 $custdata_parts = explode("\n", $row['custdata']);
1200 1403 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
@@ -1218,11 +1421,11 @@
1218 1421 }
1219 1422 unset($custdet_parts[0]);
1220 1423 if ((!strcasecmp(trim($custdet_parts[1]), 'http') || !strcasecmp(trim($custdet_parts[1]), 'https')) && !empty($custdet_parts[2]) && strpos($custdet_parts[2], '//') !== false) {
1221 1424 // this is a URI
1222 - $custd_val = '<a href="' . trim(implode(':', $custdet_parts)) . '" target="_blank"><i class="' . VikBookingIcons::i('external-link') . '"></i></a>';
1425 + $custd_val = '<a href="' . htmlspecialchars(trim(implode(':', $custdet_parts))) . '" target="_blank"><i class="' . VikBookingIcons::i('external-link') . '"></i></a>';
1223 1426 } else {
1224 - $custd_val = trim(implode(':', $custdet_parts));
1427 + $custd_val = htmlspecialchars(trim(implode(':', $custdet_parts)));
1225 1428 }
1226 1429 }
1227 1430 ?>
1228 1431 <div class="vbo-bookingdet-userdetail">
@@ -1280,24 +1483,77 @@
1280 1483
1281 1484 </div>
1282 1485
1283 1486 <?php
1284 - $invoiced = file_exists(VBO_SITE_PATH.DS.'helpers'.DS.'invoices'.DS.'generated'.DS.$row['id'].'_'.$row['sid'].'.pdf');
1285 - if (!$printreceipt && ((!empty($row['channel']) && !empty($row['idorderota'])) || strlen($row['confirmnumber']) > 0 || $invoiced)) {
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)) {
1286 1526 ?>
1287 1527 <div class="vbo-bookingdet-detcont vbo-bookingdet-detcont-labels-wrap vbo-hidein-print">
1288 1528 <?php
1289 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'];
1290 1536 ?>
1291 - <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-idorderota">
1537 + <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-idorderota <?php echo strtolower(preg_replace('/[^a-z0-9]/i', '', $channelparts[0])); ?>">
1292 1538 <span class="label label-info">
1293 - <span><?php echo $otachannel_name . ' ID'; ?></span>
1294 - <span class="badge"><?php echo !strcasecmp($row['type'], 'Inquiry') && $row['status'] == 'standby' ? '-----' : $row['idorderota']; ?></span>
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>
1295 1550 </span>
1551 + <textarea class="vbo-textarea-copyable" data-copy="otabid"><?php echo htmlentities($displayOtaBid); ?></textarea>
1296 1552 </div>
1297 1553 <?php
1298 1554 }
1299 - if (strlen($row['confirmnumber']) > 0) {
1555 + if (strlen((string)$row['confirmnumber'])) {
1300 1556 ?>
1301 1557 <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-confirmnumber">
1302 1558 <span class="label label-success">
1303 1559 <span><?php echo JText::translate('VBCONFIRMNUMB'); ?></span>
@@ -1305,26 +1561,138 @@
1305 1561 </span>
1306 1562 </div>
1307 1563 <?php
1308 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 +
1309 1660 if ($invoiced) {
1310 - ?>
1661 + foreach ($invoice_details as $invoice_detail) {
1662 + ?>
1311 1663 <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-invoice">
1312 1664 <span class="label label-success">
1313 - <span><?php echo JText::translate('VBOCOLORTAGRULEINVONE'); ?></span>
1314 - <span class="badge"><a href="<?php echo VBO_SITE_URI; ?>helpers/invoices/generated/<?php echo $row['id'].'_'.$row['sid']; ?>.pdf" target="_blank"><?php VikBookingIcons::e('download'); ?> <?php echo JText::translate('VBOINVDOWNLOAD'); ?></a></span>
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>
1315 1667 </span>
1316 1668 </div>
1317 - <?php
1669 + <?php
1670 + }
1318 1671 }
1319 - if (count($this->vcm_review)) {
1672 + if ($this->vcm_review) {
1320 1673 ?>
1321 1674 <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-review">
1322 - <span class="label label-warning">
1323 - <a href="index.php?option=com_vikchannelmanager&task=reviews&revid=<?php echo $this->vcm_review['id']; ?>" target="_blank" style="color: #fff;"><i class="vboicn-star-full"></i> <?php echo JText::translate('VBOSEEGUESTREVIEW'); ?></a>
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>
1324 1677 </span>
1325 1678 </div>
1326 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 + }
1327 1695 }
1328 1696 ?>
1329 1697
1330 1698 <!-- Define role to detect the supported hook -->
@@ -1330,10 +1698,9 @@
1330 1698 <!-- Define role to detect the supported hook -->
1331 1699 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"invoice","type":"field"} -->
1332 1700
1333 1701 <?php
1334 - if (isset($bookingSidebarForms['invoice']))
1335 - {
1702 + if (isset($bookingSidebarForms['invoice'])) {
1336 1703 echo $bookingSidebarForms['invoice'];
1337 1704 }
1338 1705 ?>
1339 1706
@@ -1348,15 +1715,15 @@
1348 1715 </div>
1349 1716 <div class="vbo-bookingdet-inpwrap">
1350 1717 <div class="vbo-bookingdet-inpcont">
1351 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>
1352 1722 </div>
1353 - <div class="vbo-bookingdet-btncont vbo-bookingdet-save-email" style="display: none;">
1354 - <button type="button" class="btn btn-success" onclick="document.adminForm.submit();"><?php VikBookingIcons::e('save'); ?> <?php echo JText::translate('VBSAVE'); ?></button>
1355 - </div>
1356 1723 <?php if (!empty($row['custmail'])) : ?>
1357 1724 <div class="vbo-bookingdet-btncont">
1358 - <button type="button" class="btn vbo-config-btn" onclick="vboToggleSendEmail();" style="vertical-align: top;"><?php VikBookingIcons::e('envelope'); ?> <?php echo JText::translate('VBSENDEMAILACTION'); ?></button>
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>
1359 1726 </div>
1360 1727 <?php endif; ?>
1361 1728 </div>
1362 1729
@@ -1363,10 +1730,9 @@
1363 1730 <!-- Define role to detect the supported hook -->
1364 1731 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"email","type":"field"} -->
1365 1732
1366 1733 <?php
1367 - if (isset($bookingSidebarForms['email']))
1368 - {
1734 + if (isset($bookingSidebarForms['email'])) {
1369 1735 echo $bookingSidebarForms['email'];
1370 1736 }
1371 1737 ?>
1372 1738
@@ -1378,13 +1744,27 @@
1378 1744 <div class="vbo-bookingdet-inpwrap">
1379 1745 <div class="vbo-bookingdet-inpcont">
1380 1746 <?php echo $vbo_app->printPhoneInputField(array('name' => 'custphone', 'id' => 'custphone', 'value' => $this->escape($row['phone'])), array('nationalMode' => false, 'fullNumberOnBlur' => true)); ?>
1381 1747 </div>
1382 - <?php if (!empty($row['phone'])) : ?>
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 + ?>
1383 1753 <div class="vbo-bookingdet-btncont">
1384 - <button type="button" class="btn vbo-config-btn" onclick="vboToggleSendSMS();" style="vertical-align: top;"><?php VikBookingIcons::e('comment-dots'); ?> <?php echo JText::translate('VBSENDSMSACTION'); ?></button>
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>
1385 1755 </div>
1386 - <?php endif; ?>
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 + ?>
1387 1767 </div>
1388 1768
1389 1769 <!-- Define role to detect the supported hook -->
1390 1770 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"phone","type":"field"} -->
@@ -1389,24 +1769,48 @@
1389 1769 <!-- Define role to detect the supported hook -->
1390 1770 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"phone","type":"field"} -->
1391 1771
1392 1772 <?php
1393 - if (isset($bookingSidebarForms['phone']))
1394 - {
1773 + if (isset($bookingSidebarForms['phone'])) {
1395 1774 echo $bookingSidebarForms['phone'];
1396 1775 }
1397 1776 ?>
1398 1777
1399 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>
1400 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 +
1401 1807 <!-- Define role to detect the supported hook -->
1402 1808 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","type":"fieldset"} -->
1403 1809
1404 1810 <?php
1405 - foreach ($bookingSidebarForms as $legend => $form)
1406 - {
1407 - if (in_array($legend, ['userdetails', 'invoice', 'email', 'phone']))
1408 - {
1811 + foreach ($bookingSidebarForms as $legend => $form) {
1812 + if (in_array($legend, ['userdetails', 'invoice', 'email', 'phone'])) {
1409 1813 // skip default forms
1410 1814 continue;
1411 1815 }
1412 1816 ?>
@@ -1456,10 +1860,10 @@
1456 1860 <td class="vbo-bookingdet-summary-room-firstcell">
1457 1861 <div class="vbo-bookingdet-summary-room-wrap">
1458 1862 <div class="vbo-bookingdet-summary-roomnum"><?php VikBookingIcons::e($room_icon); ?> <?php echo JText::translate('VBEDITORDERTHREE').' '.$num; ?></div>
1459 1863 <?php
1460 - //Room Specific Unit
1461 - if (!$row['closure'] && $row['status'] == "confirmed" && !empty($or['params'])) {
1864 + // Room Specific Unit
1865 + if ((!$row['closure'] || ($row['closure'] && count($rooms) === 1) && !empty($or['roomindex'])) && $row['status'] == "confirmed" && !empty($or['params'])) {
1462 1866 $room_params = json_decode($or['params'], true);
1463 1867 $arr_features = array();
1464 1868 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
1465 1869 if (is_array($room_params) && array_key_exists('features', $room_params) && !empty($room_params['features'])) {
@@ -1474,9 +1878,9 @@
1474 1878 }
1475 1879 }
1476 1880 }
1477 1881 }
1478 - if (count($arr_features)) {
1882 + if ($arr_features) {
1479 1883 // $or['id'] equals to the ID of each matching record in _ordersrooms
1480 1884 ?>
1481 1885 <div class="vbo-bookingdet-summary-roomnum-chunit">
1482 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']] : ''); ?>
@@ -1502,9 +1906,9 @@
1502 1906 if ($arrpeople[$num]['children'] > 0) {
1503 1907 $age_str = '';
1504 1908 if (!empty($arrpeople[$num]['children_age'])) {
1505 1909 $json_child = json_decode($arrpeople[$num]['children_age'], true);
1506 - if (is_array($json_child) && isset($json_child['age']) && is_array($json_child['age']) && count($json_child['age'])) {
1910 + if (is_array($json_child) && isset($json_child['age']) && is_array($json_child['age']) && $json_child['age']) {
1507 1911 $age_str = ' '.JText::sprintf('VBORDERCHILDAGES', implode(', ', $json_child['age']));
1508 1912 }
1509 1913 }
1510 1914 ?>
@@ -1548,9 +1952,9 @@
1548 1952 } else {
1549 1953 echo JText::translate('VBOROOMCUSTRATEPLAN');
1550 1954 }
1551 1955 }
1552 - } elseif (array_key_exists($num, $tars) && !empty($tars[$num][0]['idprice'])) {
1956 + } elseif (!empty($tars[$num]) && !empty($tars[$num][0]['idprice'])) {
1553 1957 $active_rplan_id = $tars[$num][0]['idprice'];
1554 1958 $all_id_prices[] = $tars[$num][0]['idprice'];
1555 1959 echo VikBooking::getPriceName($tars[$num][0]['idprice']);
1556 1960 if (!empty($tars[$num][0]['attrdata'])) {
@@ -1593,9 +1997,9 @@
1593 1997 </div>
1594 1998 <?php
1595 1999 }
1596 2000
1597 - if ($row['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
2001 + if ($row['split_stay'] && $room_stay_dates && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
1598 2002 // print split stay information for this room
1599 2003 $room_stay_checkin = !empty($room_stay_dates[$ind]['checkin_ts']) ? $room_stay_dates[$ind]['checkin_ts'] : $room_stay_dates[$ind]['checkin'];
1600 2004 $room_stay_checkout = !empty($room_stay_dates[$ind]['checkout_ts']) ? $room_stay_dates[$ind]['checkout_ts'] : $room_stay_dates[$ind]['checkout'];
1601 2005 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
@@ -1607,9 +2011,9 @@
1607 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>
1608 2012 </div>
1609 2013 </div>
1610 2014 <?php
1611 - } elseif (!$row['split_stay'] && count($room_stay_records) && isset($room_stay_records[$ind]) && $room_stay_records[$ind]['idroom'] == $or['idroom']) {
2015 + } elseif (!$row['split_stay'] && $room_stay_records && isset($room_stay_records[$ind]) && $room_stay_records[$ind]['idroom'] == $or['idroom']) {
1612 2016 // print modified stay dates information for this room
1613 2017 $room_stay_checkin = $room_stay_records[$ind]['checkin'];
1614 2018 $room_stay_checkout = $room_stay_records[$ind]['checkout'];
1615 2019 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
@@ -1631,9 +2035,9 @@
1631 2035 <div class="vbo-bookingdet-summary-price">
1632 2036 <?php
1633 2037 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
1634 2038 echo $currencyname.' '.VikBooking::numberFormat($or['cust_cost']);
1635 - } elseif (array_key_exists($num, $tars) && !empty($tars[$num][0]['idprice'])) {
2039 + } elseif (!empty($tars[$num]) && !empty($tars[$num][0]['idprice'])) {
1636 2040 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num][0]['cost'];
1637 2041 echo $currencyname.' '.VikBooking::numberFormat(($after_tax ? VikBooking::sayCostPlusIva($display_rate, $tars[$num][0]['idprice']) : $display_rate));
1638 2042 }
1639 2043 ?>
@@ -1651,14 +2055,22 @@
1651 2055 }
1652 2056 $stept = explode(":", $oo);
1653 2057 $q = "SELECT * FROM `#__vikbooking_optionals` WHERE `id`=".(int)$stept[0].";";
1654 2058 $dbo->setQuery($q);
1655 - $dbo->execute();
1656 - if ($dbo->getNumRows() != 1) {
2059 + $actopt = $dbo->loadAssocList();
2060 + if (!$actopt) {
1657 2061 continue;
1658 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 +
1659 2072 $counter++;
1660 - $actopt = $dbo->loadAssocList();
1661 2073 $chvar = '';
1662 2074 if (!empty($actopt[0]['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
1663 2075 $optagenames = VikBooking::getOptionIntervalsAges($actopt[0]['ageintervals']);
1664 2076 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt[0]['ageintervals']);
@@ -1693,9 +2105,9 @@
1693 2105 }
1694 2106 $actopt[0]['chageintv'] = $chvar;
1695 2107 $actopt[0]['name'] .= ' ('.$optagenames[($chvar - 1)].')';
1696 2108 $realcost = (intval($actopt[0]['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $room_stay_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
1697 - } else {
2109 + } elseif (is_numeric($stept[1])) {
1698 2110 // VBO 1.11 - options percentage cost of the room total fee
1699 2111 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
1700 2112 $deftar_basecosts = $or['cust_cost'];
1701 2113 } else {
@@ -1704,8 +2116,10 @@
1704 2116 }
1705 2117 $actopt[0]['cost'] = (int)$actopt[0]['pcentroom'] ? ($deftar_basecosts * $actopt[0]['cost'] / 100) : $actopt[0]['cost'];
1706 2118 //
1707 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;
1708 2122 }
1709 2123 if ($actopt[0]['maxprice'] > 0 && $realcost > $actopt[0]['maxprice']) {
1710 2124 $realcost = $actopt[0]['maxprice'];
1711 2125 if (intval($actopt[0]['hmany']) == 1 && intval($stept[1]) > 1) {
@@ -1712,8 +2126,19 @@
1712 2126 $realcost = $actopt[0]['maxprice'] * $stept[1];
1713 2127 }
1714 2128 }
1715 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 +
1716 2141 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt[0]['idiva']);
1717 2142 ?>
1718 2143 <tr class="vbo-bookingdet-summary-options">
1719 2144 <td class="vbo-bookingdet-summary-options-title"><?php echo $counter == 1 ? JText::translate('VBEDITORDEREIGHT') : '&nbsp;'; ?></td>
@@ -1737,9 +2162,21 @@
1737 2162 ?>
1738 2163 <tr class="vbo-bookingdet-summary-custcosts">
1739 2164 <td class="vbo-bookingdet-summary-custcosts-title"><?php echo $counter == 1 ? JText::translate('VBPEDITBUSYEXTRACOSTS') : '&nbsp;'; ?></td>
1740 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 + ?>
1741 2175 <span class="vbo-bookingdet-summary-lbl"><?php echo $ecv['name']; ?></span>
2176 + <?php
2177 + }
2178 + ?>
1742 2179 </td>
1743 2180 <td>
1744 2181 <span class="vbo-bookingdet-summary-cost"><?php echo $currencyname." ".VikBooking::numberFormat(($after_tax ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'])); ?></span>
1745 2182 </td>
@@ -1789,18 +2226,17 @@
1789 2226 //Reservation Total
1790 2227 //Taxes Breakdown (only if tot_taxes is greater than 0)
1791 2228 $tax_breakdown = array();
1792 2229 $base_aliq = 0;
1793 - if (count($all_id_prices) > 0 && $row['tot_taxes'] > 0) {
2230 + if ($all_id_prices && $row['tot_taxes'] > 0) {
1794 2231 //only last type of price assuming that the tax breakdown is equivalent in case of different rates
1795 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;";
1796 2233 $dbo->setQuery($q);
1797 - $dbo->execute();
1798 - if ($dbo->getNumRows() > 0) {
1799 - $breakdown_info = $dbo->loadAssoc();
2234 + $breakdown_info = $dbo->loadAssoc();
2235 + if ($breakdown_info) {
1800 2236 if (!empty($breakdown_info['breakdown']) && !empty($breakdown_info['aliq'])) {
1801 2237 $tax_breakdown = json_decode($breakdown_info['breakdown'], true);
1802 - $tax_breakdown = is_array($tax_breakdown) && count($tax_breakdown) > 0 ? $tax_breakdown : array();
2238 + $tax_breakdown = is_array($tax_breakdown) && $tax_breakdown ? $tax_breakdown : array();
1803 2239 $base_aliq = $breakdown_info['aliq'];
1804 2240 }
1805 2241 }
1806 2242 }
@@ -1841,9 +2277,9 @@
1841 2277 <div class="vbdiscenter-entry">
1842 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>
1843 2279 </div>
1844 2280 <?php
1845 - if (count($tax_breakdown)) {
2281 + if ($tax_breakdown) {
1846 2282 foreach ($tax_breakdown as $tbkk => $tbkv) {
1847 2283 $tax_break_cost = $row['tot_taxes'] * floatval($tbkv['aliq']) / $base_aliq;
1848 2284 ?>
1849 2285 <div class="vbdiscenter-entry vbdiscenter-entry-breakdown">
@@ -1861,9 +2297,19 @@
1861 2297 </div>
1862 2298 <div class="vbdiscenter-entry">
1863 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>
1864 2300 </div>
2301 + <?php
2302 + if ($booking_has_damage_dep) {
2303 + // allow to overwrite (or see) the amount of damage deposit
2304 + ?>
1865 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">
1866 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>
1867 2313 </div>
1868 2314 <div class="vbdiscenter-entrycentered">
1869 2315 <button type="submit" class="btn btn-success"><?php echo JText::translate('VBAPPLYDISCOUNTSAVE'); ?></button>
@@ -1870,9 +2316,26 @@
1870 2316 </div>
1871 2317 </div>
1872 2318 </td>
1873 2319 <td>
1874 - <span class="vbo-bookingdet-summary-cost"><?php echo (strlen($otacurrency) > 0 ? '('.$otacurrency.') '.$currencyname : $currencyname); ?> <?php echo VikBooking::numberFormat($row['total']); ?></span>
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 + ?>
1875 2338 </td>
1876 2339 </tr>
1877 2340 <?php
1878 2341 if ($row['total'] > 0 && !$row['closure']) {
@@ -1877,8 +2340,12 @@
1877 2340 <?php
1878 2341 if ($row['total'] > 0 && !$row['closure']) {
1879 2342 $has_paid = ($row['totpaid'] > 0);
1880 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 + }
1881 2348 if ($has_paid || $row['status'] != 'standby') {
1882 2349 ?>
1883 2350 <tr class="vbo-bookingdet-summary-totpaid">
1884 2351 <td>&nbsp;</td>
@@ -1891,9 +2358,9 @@
1891 2358 <div id="vbo-amountpaid-modcont" style="display: none;">
1892 2359 <span id="vbo-amountpaid-cancedit" style="margin-right: 5px; cursor: pointer;"><?php VikBookingIcons::e('times'); ?></span>
1893 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>
1894 2361 <?php
1895 - if (is_array($payments)) {
2362 + if ($payments) {
1896 2363 ?>
1897 2364 <span id="vbo-amountpaid-paymeth" style="margin: 0 5px; max-width: 160px;">
1898 2365 <select name="newamountpaymeth" style="margin: 0;">
1899 2366 <option value=""><?php echo JText::translate('VBPAYMENTMETHOD'); ?></option>
@@ -1936,9 +2403,9 @@
1936 2403 </tr>
1937 2404 <?php
1938 2405 }
1939 2406 }
1940 - if (!$printreceipt && $row['status'] == 'confirmed' && VikBooking::multiplePayments() && is_array($payment) && !empty($payment['id']) && $row['checkout'] > time()) {
2407 + if (!$printreceipt && $row['status'] == 'confirmed' && VikBooking::multiplePayments() && is_array($payment) && !empty($payment['id']) && $row['checkout'] > strtotime('-10 days')) {
1941 2408 /**
1942 2409 * The amount payable can be modified by the admin.
1943 2410 *
1944 2411 * @since 1.14 (J) - 1.4.0 (WP)
@@ -2044,9 +2511,9 @@
2044 2511 <?php
2045 2512 if (!$row['closure']) {
2046 2513 ?>
2047 2514 <div class="vbo-bookingdet-admin-entry">
2048 - <label for="vbo-searchcust"><?php echo JText::translate(count($customer) ? 'VBOASSIGNNEWCUST' : 'VBFILLCUSTFIELDS'); ?></label>
2515 + <label for="vbo-searchcust"><?php echo JText::translate($customer ? 'VBOASSIGNNEWCUST' : 'VBFILLCUSTFIELDS'); ?></label>
2049 2516 <span style="display: block;"><?php echo JText::translate('VBOSEARCHEXISTCUST'); ?></span>
2050 2517 <span class="vbo-eorder-assigncust" style="margin-bottom: 1px;">
2051 2518 <input type="text" id="vbo-searchcust" autocomplete="off" value="" placeholder="<?php echo JText::translate('VBOSEARCHCUSTBY'); ?>" size="30" style="margin-bottom: 0;" />
2052 2519 </span>
@@ -2081,12 +2548,12 @@
2081 2548 <span><?php echo $payment['name']; ?></span>
2082 2549 <?php
2083 2550 }
2084 2551 $chpayment = '';
2085 - if (is_array($payments)) {
2086 - $chpayment = '<div><select name="newpayment" id="newpayment" onchange="changePayment();"><option value="">'.JText::translate('VBCHANGEPAYLABEL').'</option>';
2087 - foreach($payments as $pay) {
2088 - $chpayment .= '<option value="'.$pay['id'].'">'.(is_array($payment) && $payment['id'] == $pay['id'] ? ' ::' : '').$pay['name'].'</option>';
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>';
2089 2556 }
2090 2557 $chpayment .= '</select></div>';
2091 2558 }
2092 2559 echo $chpayment;
@@ -2161,9 +2628,12 @@
2161 2628 $history = $history_obj->loadHistory();
2162 2629 ?>
2163 2630 <div class="vbo-bookingdet-noteslogs-btns">
2164 2631 <div class="vbo-bookingdet-noteslogs-btn vbo-bookingdet-noteslogs-btn-active" data-id="notes">
2165 - <a href="javascript: void(0);" id="vbo-trig-notes" onclick="javascript: vbToggleNotes(this);"><?php VikBookingIcons::e('user-lock'); ?> <?php echo JText::translate('VBADMINNOTESTOGGLE'); ?></a>
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>
2166 2636 </div>
2167 2637 <?php
2168 2638 /**
2169 2639 * Initialize chat instance by getting the proper channel name
@@ -2176,9 +2646,9 @@
2176 2646 } else {
2177 2647 $channelparts = explode('_', $row['channel']);
2178 2648 // check if this is a meta search channel
2179 2649 $is_meta_search = false;
2180 - if (preg_match("/(customer).*[0-9]$/", $channelparts[0]) || !strcasecmp($channelparts[0], 'googlehotel') || !strcasecmp($channelparts[0], 'trivago')) {
2650 + if (preg_match("/(customer).*[0-9]$/", $channelparts[0]) || !strcasecmp($channelparts[0], 'googlehotel') || !strcasecmp($channelparts[0], 'googlevr') || !strcasecmp($channelparts[0], 'trivago')) {
2181 2651 $is_meta_search = empty($row['idorderota']);
2182 2652 }
2183 2653 if ($is_meta_search) {
2184 2654 // customer of type sales channel should use front-end reservation chat handler
@@ -2192,24 +2662,51 @@
2192 2662 //
2193 2663 if (!$printreceipt && !is_null($messaging)) {
2194 2664 ?>
2195 2665 <div class="vbo-bookingdet-noteslogs-btn" data-id="messaging">
2196 - <a name="messaging" href="javascript: void(0);" id="vbo-trig-messaging" onclick="javascript: vbToggleMessaging(this);"><?php VikBookingIcons::e('comment-dots'); ?> <?php echo JText::translate('VBO_GUEST_MESSAGING'); ?></a>
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>
2197 2670 </div>
2198 2671 <?php
2199 2672 }
2200 - if (!empty($row['paymentlog'])) {
2201 - ?>
2202 - <div class="vbo-bookingdet-noteslogs-btn" data-id="paylogs">
2203 - <a href="javascript: void(0);" id="vbo-trig-paylogs" onclick="javascript: vbToggleLog(this);"><?php VikBookingIcons::e('credit-card'); ?> <?php echo JText::translate('VBPAYMENTLOGTOGGLE'); ?></a>
2204 - <a name="paymentlog" href="javascript: void(0);"></a>
2205 - </div>
2206 - <?php
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 + }
2207 2700 }
2208 - if (count($history)) {
2701 +
2702 + if ($history) {
2209 2703 ?>
2210 2704 <div class="vbo-bookingdet-noteslogs-btn" data-id="history">
2211 - <a href="javascript: void(0);" id="vbo-trig-bookhistory" onclick="javascript: vbToggleHistory(this);"><?php VikBookingIcons::e('history'); ?> <?php echo JText::translate('VBOBOOKHISTORYTAB'); ?></a>
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>
2212 2709 </div>
2213 2710 <script type="text/javascript">
2214 2711 if (window.location.hash == '#bookhistory') {
2215 2712 setTimeout(function() {
@@ -2221,9 +2718,12 @@
2221 2718 <?php
2222 2719 }
2223 2720 ?>
2224 2721 <div class="vbo-bookingdet-noteslogs-btn pro-feature" data-id="invnotes">
2225 - <a href="javascript: void(0);" class="hasTooltip" id="vbo-trig-invnotes" onclick="javascript: vbToggleInvNotes(this);" title="<?php echo addslashes(JText::translate('VBBOOKINGINVNOTESHELP')); ?>"><?php VikBookingIcons::e('file-invoice'); ?> <?php echo JText::translate('VBBOOKINGINVNOTES'); ?></a>
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>
2226 2726 </div>
2227 2727
2228 2728 <!-- Define role to detect the supported hook -->
2229 2729 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderAdministration","type":"fieldset"} -->
@@ -2232,28 +2732,383 @@
2232 2732 foreach ($adminPanelForms as $legend => $form)
2233 2733 {
2234 2734 $legendId = preg_replace("/[^a-zA-Z0-9_\-]+/", '', $legend);
2235 2735 ?>
2236 - <div class="vbo-bookingdet-noteslogs-btn" data-id="<?php echo $legendId; ?>">
2237 - <a href="javascript: void(0);" class="hasTooltip" id="vbo-trig-<?php echo $legendId; ?>" onclick="javascript: vbToggleDynamicPanel(this, '#vboextrapanel-<?php echo $legendId; ?>');">
2238 - <?php
2239 - VikBookingIcons::e(!empty($adminFormsSetup->icons[$legend]) ? $adminFormsSetup->icons[$legend] : 'plug');
2240 - echo JText::translate($legend);
2241 - ?>
2242 - </a>
2243 - </div>
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>
2244 2742 <?php
2245 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 + }
2246 2760 ?>
2247 2761 </div>
2248 2762 <div class="vbo-bookingdet-noteslogs-cont">
2249 2763 <div id="vbadminnotesdiv" class="vbo-extra-panel" style="display: block;">
2250 - <textarea name="adminnotes" class="vbadminnotestarea"><?php echo strip_tags((string)$row['adminnotes']); ?></textarea>
2764 + <textarea name="adminnotes" class="vbadminnotestarea"><?php echo JHtml::fetch('esc_textarea', (string) $row['adminnotes']); ?></textarea>
2251 2765 <input type="submit" name="updadmnotes" value="<?php echo JText::translate('VBADMINNOTESUPD'); ?>" class="btn btn-success" />
2252 2766 </div>
2253 2767 <?php
2254 - if (count($history)) {
2768 + if ($takings) {
2255 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 + ?>
2256 3111 <div id="vbhistorydiv" class="vbo-extra-panel" style="display: none;">
2257 3112 <div class="vbo-booking-history-container table-responsive">
2258 3113 <table class="table">
2259 3114 <thead>
@@ -2267,9 +3122,9 @@
2267 3122 </thead>
2268 3123 <tbody>
2269 3124 <?php
2270 3125 foreach ($history as $hist) {
2271 - $hdescr = strpos($hist['descr'], '<') !== false ? $hist['descr'] : nl2br($hist['descr']);
3126 + $hdescr = strpos((string) $hist['descr'], '<') !== false ? $hist['descr'] : nl2br((string) $hist['descr']);
2272 3127 ?>
2273 3128 <tr class="vbo-booking-history-row">
2274 3129 <td><?php echo $history_obj->validType($hist['type'], true); ?></td>
2275 3130 <td><?php echo JHtml::fetch('date', $hist['dt'], 'Y-m-d H:i:s'); ?></td>
@@ -2295,8 +3150,9 @@
2295 3150 <?php
2296 3151 if (!empty($row['paymentlog'])) {
2297 3152 ?>
2298 3153 <div id="vbpaymentlogdiv" class="vbo-extra-panel" style="display: none;">
3154 + <div class="vbo-eorder-paymentlog-buttons">
2299 3155 <?php
2300 3156 // PCI Data Retrieval
2301 3157 $cc_acl_denied = false;
2302 3158 if (!empty($row['idorderota']) && !empty($row['channel'])) {
@@ -2311,9 +3167,9 @@
2311 3167 if (!$canDo->authorise('core.admin', 'com_vikchannelmanager')) {
2312 3168 // permissions to access VCM are required
2313 3169 $cc_acl_denied = true;
2314 3170 ?>
2315 - <p class="err"><?php echo JText::translate('JERROR_ALERTNOAUTHOR'); ?></p>
3171 + <p class="err"><?php echo JText::translate('JERROR_ALERTNOAUTHOR'); ?></p>
2316 3172 <?php
2317 3173 } else {
2318 3174 /**
2319 3175 * Limit for accessing the credit card details has been changed to check-out
@@ -2321,34 +3177,465 @@
2321 3177 *
2322 3178 * @since 1.13
2323 3179 */
2324 3180 $cardlimit = mktime(23, 59, 59, $checkout_info['mon'], ($checkout_info['mday'] + 10), $checkout_info['year']);
2325 - if (time() < $cardlimit) {
2326 - $plain_log = htmlspecialchars($row['paymentlog']);
2327 - if (stripos($plain_log, 'card number') !== false && strpos($plain_log, '****') !== false) {
2328 - // log contains credit card details
2329 - // Prepare modal (Credit Card Details)
2330 - array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-vcm-pcid', JText::translate('GETFULLCARDDETAILS'), '', 'width: 80%; height: 60%; margin-left: -40%; top: 20% !important;'));
2331 - // end Prepare modal
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;'));
2332 3185 ?>
2333 - <div class="vcm-notif-pcidrq-container">
2334 - <a class="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');" href="javascript: void(0);"><?php echo JText::translate('GETFULLCARDDETAILS'); ?></a>
2335 - </div>
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>
2336 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
2337 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
2338 3592 }
2339 3593 }
2340 3594 } elseif (empty($row['idorderota']) && !empty($row['paymentlog']) && $row['status'] == 'standby') {
2341 3595 ?>
2342 - <div class="vbo-eorder-emptyccdata">
2343 - <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>
2344 - </div>
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>
2345 3599 <?php
2346 3600 }
2347 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 +
2348 3635 if (!$cc_acl_denied) {
2349 3636 ?>
2350 - <pre style="min-height: 100%;"><?php echo htmlspecialchars($row['paymentlog']); ?></pre>
3637 + <pre><?php echo htmlspecialchars($row['paymentlog']); ?></pre>
2351 3638 <?php
2352 3639 }
2353 3640 ?>
2354 3641 </div>
@@ -2424,92 +3711,94 @@
2424 3711 <input type="hidden" name="cid[]" value="<?php echo $row['id']; ?>" />
2425 3712 <input type="hidden" name="invnotes" id="invnotes-hid" value="" />
2426 3713 </form>
2427 3714
2428 -<div class="vbo-modal-overlay-block vbo-modal-overlay-block-sms-email">
2429 - <a class="vbo-modal-overlay-close" href="javascript: void(0);"></a>
2430 - <div class="vbo-modal-overlay-content vbo-modal-overlay-content-large vbo-modal-overlay-content-sms-email">
3715 +<div class="vbo-editorder-sms-email-send-helper" style="display: none;">
2431 3716
2432 - <div class="vbo-modal-overlay-content-head vbo-modal-overlay-content-sms-email-head">
2433 - <h3>
2434 - <span></span>
2435 - <span class="vbo-modal-overlay-close-times" onclick="vboToggleSendEmail();">&times;</span>
2436 - </h3>
2437 - </div>
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">
2438 3722
2439 - <div class="vbo-modal-overlay-content-body vbo-modal-overlay-content-body-scroll">
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>
2440 3731
2441 - <div id="vbo-overlay-sms-cont" style="display: none;">
2442 - <h4 style="display: none;"><?php echo JText::translate('VBSENDSMSACTION'); ?>: <span id="smstophone-lbl"><?php echo $row['phone']; ?></span></h4>
2443 - <form action="index.php?option=com_vikbooking" method="post" id="vbo-modal-form-sms">
2444 - <div class="vbo-calendar-cfield-entry">
2445 - <label for="smscont"><?php echo JText::translate('VBSENDSMSCUSTCONT'); ?></label>
2446 - <span><textarea name="smscont" id="smscont" style="width: 99%; min-width: 99%;max-width: 99%; height: 120px;"></textarea></span>
2447 3732 </div>
2448 - <input type="hidden" name="phone" id="smstophone" value="<?php echo $row['phone']; ?>" />
2449 - <input type="hidden" name="goto" value="<?php echo urlencode('index.php?option=com_vikbooking&task=editorder&cid[]='.$row['id']); ?>" />
2450 - <input type="hidden" name="task" value="sendcustomsms" />
2451 - </form>
3733 + </div>
2452 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>
2453 3740
2454 - <div id="vbo-overlay-email-cont" style="display: none;">
2455 - <h4 style="display: none;"><?php echo JText::translate('VBSENDEMAILACTION'); ?>: <span id="emailto-lbl"><?php echo $row['custmail']; ?></span></h4>
2456 - <form action="index.php?option=com_vikbooking" method="post" enctype="multipart/form-data" id="vbo-modal-form-email">
2457 - <input type="hidden" name="bid" value="<?php echo $row['id']; ?>" />
2458 - <?php
2459 - $cur_emtpl = array();
2460 - $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
2461 - $dbo->setQuery($q);
2462 - $dbo->execute();
2463 - if ($dbo->getNumRows() > 0) {
2464 - $cur_emtpl = $dbo->loadResult();
2465 - $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
2466 - $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
2467 - }
2468 - if (count($cur_emtpl) > 0) {
2469 - ?>
2470 - <div class="vbo-calendar-custmail-tpls-wrap">
2471 - <select id="emtpl-customemail" onchange="vboLoadEmailTpl(this.value);">
2472 - <option value=""><?php echo JText::translate('VBEMAILCUSTFROMTPL'); ?></option>
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>
2473 3768 <?php
2474 - foreach ($cur_emtpl as $emk => $emv) {
2475 - ?>
2476 - <optgroup label="<?php echo $emv['emailsubj']; ?>">
2477 - <option value="<?php echo $emk; ?>"><?php echo JText::translate('VBEMAILCUSTFROMTPLUSE'); ?></option>
2478 - <option value="rm<?php echo $emk; ?>"><?php echo JText::translate('VBEMAILCUSTFROMTPLRM'); ?></option>
2479 - </optgroup>
2480 - <?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>');
2481 3782 }
2482 - ?>
2483 - </select>
2484 - </div>
2485 - <?php
2486 - }
2487 -
2488 - /**
2489 - * Load all conditional text special tags.
2490 - *
2491 - * @since 1.14 (J) - 1.4.0 (WP)
2492 - */
2493 - $extra_btns = array();
2494 - $condtext_tags = VikBooking::getConditionalRulesInstance()->getSpecialTags();
2495 - if (count($condtext_tags)) {
2496 - $condtext_tags = array_keys($condtext_tags);
2497 - foreach ($condtext_tags as $tag) {
2498 - array_push($extra_btns, '<button type="button" class="btn btn-secondary btn-small vbo-condtext-specialtag-btn" onclick="setSpecialTplTag(\'emailcont\', \'' . $tag . '\');">' . $tag . '</button>');
2499 3783 }
2500 - }
2501 - //
2502 - ?>
2503 - <div class="vbo-calendar-cfields-wrap">
2504 - <div class="vbo-calendar-cfield-entry">
2505 - <label for="emailsubj"><?php echo JText::translate('VBSENDEMAILCUSTSUBJ'); ?></label>
2506 - <span><input type="text" name="emailsubj" id="emailsubj" value="" size="30" /></span>
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>
2507 3792 </div>
2508 - <div class="vbo-calendar-cfield-entry">
2509 - <label for="emailcont"><?php echo JText::translate('VBSENDEMAILCUSTCONT'); ?></label>
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">
2510 3799 <?php
2511 - $special_tags_base = array(
3800 + $special_tags_base = [
2512 3801 '{customer_name}',
2513 3802 '{booking_id}',
2514 3803 '{checkin_date}',
2515 3804 '{checkout_date}',
@@ -2522,9 +3811,9 @@
2522 3811 '{total}',
2523 3812 '{total_paid}',
2524 3813 '{remaining_balance}',
2525 3814 '{booking_link}',
2526 - );
3815 + ];
2527 3816
2528 3817 $special_tags_base_html = '';
2529 3818 foreach ($special_tags_base as $sp_tag) {
2530 3819 $special_tags_base_html .= '<button type="button" class="btn btn-secondary btn-small" onclick="setSpecialTplTag(\'emailcont\', \'' . $sp_tag . '\');">' . $sp_tag . '</button>' . "\n";
@@ -2534,110 +3823,211 @@
2534 3823 * Use the rich text editor (visual editor) to build custom email messages.
2535 3824 *
2536 3825 * @since 1.15.0 (J) - 1.5.0 (WP)
2537 3826 */
2538 - $tarea_attr = array(
3827 + $tarea_attr = [
2539 3828 'id' => 'emailcont',
2540 3829 'rows' => '7',
2541 3830 'cols' => '170',
2542 3831 'style' => 'width: 99%; min-width: 99%; max-width: 99%; height: 120px; margin-bottom: 1px;',
2543 - );
2544 - $editor_opts = array(
2545 - 'modes' => array(
3832 + ];
3833 + $editor_opts = [
3834 + 'modes' => [
3835 + 'visual',
2546 3836 'text',
2547 - 'visual',
2548 - ),
2549 - );
3837 + ],
3838 + 'gen_ai' => [
3839 + 'booking' => $row,
3840 + 'customer' => $customer,
3841 + 'environment' => 'booking',
3842 + ],
3843 + ];
2550 3844 $editor_btns = $special_tags_base;
2551 - if (count($condtext_tags)) {
3845 + if ($condtext_tags) {
2552 3846 $editor_btns = array_merge($editor_btns, $condtext_tags);
2553 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
2554 3864 echo $vbo_app->renderVisualEditor('emailcont', '', $tarea_attr, $editor_opts, $editor_btns);
2555 3865 ?>
2556 - <div class="btn-group pull-left vbo-smstpl-bgroup vbo-custmail-bgroup vik-contentbuilder-textmode-sptags">
2557 - <?php echo $special_tags_base_html . "\n" . implode("\n", $extra_btns); ?>
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>
2558 3869 </div>
2559 3870 </div>
2560 - <div class="vbo-calendar-cfield-entry">
2561 - <label for="emailattch"><?php echo JText::translate('VBSENDEMAILCUSTATTCH'); ?></label>
2562 - <span><input type="file" name="emailattch" id="emailattch" /></span>
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>
2563 3879 </div>
2564 - <div class="vbo-calendar-cfield-entry">
2565 - <label for="emailfrom"><?php echo JText::translate('VBSENDEMAILCUSTFROM'); ?></label>
2566 - <span><input type="text" name="emailfrom" id="emailfrom" value="<?php echo VikBooking::getSenderMail(); ?>" size="30" /></span>
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>
2567 3888 </div>
3889 +
2568 3890 </div>
2569 - <input type="hidden" name="email" id="emailto" value="<?php echo $row['custmail']; ?>" />
2570 - <input type="hidden" name="goto" value="<?php echo urlencode('index.php?option=com_vikbooking&task=editorder&cid[]='.$row['id']); ?>" />
2571 - <input type="hidden" name="task" value="sendcustomemail" />
2572 - </form>
3891 + </div>
2573 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>
2574 3899
2575 - </div>
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>
2576 3907
2577 - <div class="vbo-modal-overlay-content-footer">
2578 - <div class="vbo-modal-overlay-content-footer-right">
2579 - <div id="vbo-modal-footer-sms" style="display: none;">
2580 - <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>
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>
2581 3954 </div>
2582 - <div id="vbo-modal-footer-email" style="display: none;">
2583 - <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>
2584 - </div>
2585 3955 </div>
2586 3956 </div>
2587 -
2588 3957 </div>
2589 3958 </div>
2590 3959
2591 3960 <script type="text/javascript">
2592 -var vbo_overlay_on = false;
2593 3961 var vbo_print_only = false;
2594 -if (jQuery.isFunction(jQuery.fn.tooltip)) {
3962 +if (typeof jQuery.fn.tooltip === 'function') {
2595 3963 jQuery(".hasTooltip").tooltip();
2596 3964 }
2597 -function vboToggleSendSMS() {
3965 +function vboDisplaySendSMS() {
2598 3966 var cur_phone = jQuery("#smstophone").val();
2599 3967 var phone_set = jQuery("#custphone").trigger('vboupdatephonenumber').val();
2600 3968 if (phone_set.length && phone_set != cur_phone) {
2601 3969 jQuery("#smstophone").val(phone_set);
2602 - jQuery("#smstophone-lbl").text(phone_set);
2603 3970 }
2604 3971
2605 - // toggle email/sms contents
2606 - jQuery("#vbo-overlay-email-cont, #vbo-modal-footer-email").hide();
2607 - jQuery("#vbo-overlay-sms-cont, #vbo-modal-footer-sms").show();
2608 - var use_modal_title = jQuery("#vbo-overlay-sms-cont").find('h4').first().html();
2609 - jQuery('.vbo-modal-overlay-content-sms-email-head').find('h3').find('span').first().html(use_modal_title);
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 + });
2610 3980
2611 - jQuery(".vbo-modal-overlay-block-sms-email").fadeToggle(400, function() {
2612 - if (jQuery(".vbo-modal-overlay-block-sms-email").is(":visible")) {
2613 - vbo_overlay_on = true;
2614 - } else {
2615 - vbo_overlay_on = false;
2616 - }
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 + },
2617 3994 });
3995 +
3996 + jQuery('.vbo-editorder-sms-send-wrap').appendTo(modal_body);
2618 3997 }
2619 -function vboToggleSendEmail() {
3998 +function vboDisplaySendEmail() {
2620 3999 var cur_email = jQuery("#emailto").val();
2621 4000 var email_set = jQuery("#custmail").val();
2622 4001 if (email_set.length && email_set != cur_email) {
2623 4002 jQuery("#emailto").val(email_set);
2624 - jQuery("#emailto-lbl").text(email_set);
2625 4003 }
2626 4004
2627 - // toggle email/sms contents
2628 - jQuery("#vbo-overlay-sms-cont, #vbo-modal-footer-sms").hide();
2629 - jQuery("#vbo-overlay-email-cont, #vbo-modal-footer-email").show();
2630 - var use_modal_title = jQuery("#vbo-overlay-email-cont").find('h4').first().html();
2631 - jQuery('.vbo-modal-overlay-content-sms-email-head').find('h3').find('span').first().html(use_modal_title);
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 + });
2632 4013
2633 - jQuery(".vbo-modal-overlay-block-sms-email").fadeToggle(400, function() {
2634 - if (jQuery(".vbo-modal-overlay-block-sms-email").is(":visible")) {
2635 - vbo_overlay_on = true;
2636 - } else {
2637 - vbo_overlay_on = false;
2638 - }
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 + },
2639 4027 });
4028 +
4029 + jQuery('.vbo-editorder-email-send-wrap').appendTo(modal_body);
2640 4030 }
2641 4031 function vboKeyupEmail(event) {
2642 4032 if (event.key && event.key == 'Enter') {
2643 4033 event.preventDefault();
@@ -2665,8 +4055,42 @@
2665 4055 }
2666 4056 // reload the page to display the updated information
2667 4057 location.reload();
2668 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 + });
2669 4093 // sessionStorage for current tab
2670 4094 if (typeof sessionStorage !== 'undefined' && !window.location.hash && <?php echo $printreceipt ? 'false' : 'true'; ?>) {
2671 4095 var curtab = sessionStorage.getItem('vboEditOrderTab<?php echo $row['id']; ?>');
2672 4096
@@ -2741,24 +4165,8 @@
2741 4165 return;
2742 4166 }
2743 4167 });
2744 4168 // Search customer - End
2745 - jQuery(document).mouseup(function(e) {
2746 - if (!vbo_overlay_on) {
2747 - return false;
2748 - }
2749 - var vbo_overlay_cont = jQuery(".vbo-modal-overlay-content-sms-email");
2750 - if (!vbo_overlay_cont.is(e.target) && vbo_overlay_cont.has(e.target).length === 0 && !jQuery(e.target).is('svg')) {
2751 - jQuery(".vbo-modal-overlay-block-sms-email").fadeOut();
2752 - vbo_overlay_on = false;
2753 - }
2754 - });
2755 - jQuery(document).keyup(function(e) {
2756 - if (e.keyCode == 27 && vbo_overlay_on) {
2757 - jQuery(".vbo-modal-overlay-block-sms-email").fadeOut();
2758 - vbo_overlay_on = false;
2759 - }
2760 - });
2761 4169 jQuery(".vbo-bookingdet-tab").click(function() {
2762 4170 var newtabrel = jQuery(this).attr('data-vbotab');
2763 4171 var oldtabrel = jQuery(".vbo-bookingdet-tab-active").attr('data-vbotab');
2764 4172 if (newtabrel == oldtabrel) {
@@ -2881,8 +4289,250 @@
2881 4289 jQuery('body').append(zoom_modal);
2882 4290 });
2883 4291 });
2884 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 +
2885 4535 });
2886 4536 var cur_emtpl = <?php echo json_encode($cur_emtpl); ?>;
2887 4537 function vboLoadEmailTpl(tplind) {
2888 4538 if (!(tplind.length > 0)) {
@@ -2909,9 +4559,9 @@
2909 4559 <?php
2910 4560 $pcustomemail = VikRequest::getInt('customemail', '', 'request');
2911 4561 if ($pcustomemail > 0) {
2912 4562 ?>
2913 - vboToggleSendEmail();
4563 + vboDisplaySendEmail();
2914 4564 <?php
2915 4565 }
2916 4566 if ($printreceipt) {
2917 4567 ?>