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 +860 -212 1.7.1 → 1.8.16 View file →
@@ -15,8 +15,10 @@
15 15 $busy = $this->busy;
16 16 $customer = $this->customer;
17 17 $payments = $this->payments;
18 18
19 +// load registry and history
20 +$registry = VBOBookingRegistry::getInstance($this->row, $this->rooms);
19 21 $history_obj = VikBooking::getBookingHistoryInstance($row['id']);
20 22
21 23 // availability helper
22 24 $av_helper = VikBooking::getAvailabilityInstance();
@@ -33,12 +35,15 @@
33 35 JText::script('VBO_SET_STANDBY');
34 36 JText::script('VBO_CONF_RM_OVERBOOKING_FLAG');
35 37 JText::script('VBO_NEW_PAYSCHEDULE');
36 38 JText::script('VBANNULLA');
39 +JText::script('VBOCLOSE');
37 40 JText::script('VBSAVE');
38 41 JText::script('VBELIMINA');
39 42 JText::script('VBO_REG_NEW_PAYMENT');
40 43 JText::script('VBO_UPDATE_PAYMENT');
44 +JText::script('VBSENDSMSACTION');
45 +JText::script('VBSENDEMAILACTION');
41 46 JText::script('VBO_AI_AUTO_GUEST_REV_EXCLUDE');
42 47 JText::script('VBO_AI_AUTO_GUEST_REV_INCLUDE');
43 48
44 49 $dbo = JFactory::getDbo();
@@ -44,9 +49,13 @@
44 49 $dbo = JFactory::getDbo();
45 50
46 51 $vbo_app = VikBooking::getVboApplication();
47 52 $vbo_app->loadVisualEditorAssets();
53 +$vbo_app->prepareJavaScriptCurrency();
48 54
55 +// preload chat assets
56 +VBOFactory::getChatMediator()->useAssets();
57 +
49 58 /**
50 59 * This View can render within a modal the "bookingcheckin" View, and with WP
51 60 * this is loaded via AJAX. In order to not interfere or reset the contextual menu,
52 61 * we load the assets from the parent View. Context menu may also be used in this View.
@@ -61,8 +70,14 @@
61 70
62 71 $canDo = JFactory::getUser();
63 72 $vbo_auth_bookings = $canDo->authorise('core.vbo.bookings', 'com_vikbooking');
64 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)) : [];
65 80 $currencyname = VikBooking::getCurrencyName();
66 81 $currencysymb = VikBooking::getCurrencySymb();
67 82 $after_tax = VikBooking::ivaInclusa();
68 83 $nowdf = VikBooking::getDateFormat(true);
@@ -142,8 +157,9 @@
142 157 $daysdiff = ceil($daysdiff);
143 158 }
144 159 }
145 160 }
161 +
146 162 $otachannel = '';
147 163 $otachannel_name = '';
148 164 $otachannel_bid = '';
149 165 $otacurrency = '';
@@ -155,11 +171,23 @@
155 171 if (strstr($otachannel, '.') !== false) {
156 172 $otaccparts = explode('.', $otachannel);
157 173 $otachannel = $otaccparts[0];
158 174 }
159 - $otacurrency = strlen($row['chcurrency']) > 0 ? $row['chcurrency'] : '';
175 + $otacurrency = strlen((string) $row['chcurrency']) > 0 ? $row['chcurrency'] : '';
160 176 }
161 177
178 +/**
179 + * Tell whether the current reservation has or may have a CC/VCC available.
180 + */
181 +$may_have_cc_details = false;
182 +if (!empty($row['paymentlog']) && stripos($row['paymentlog'], 'card number') !== false && strpos($row['paymentlog'], '****') !== false) {
183 + // turn flag on for partial card details available
184 + $may_have_cc_details = true;
185 +} elseif (!empty($row['channel']) && !strcasecmp($otachannel_name, 'Booking.com')) {
186 + // the CM may be able to retrieve the CC details via API
187 + $may_have_cc_details = true;
188 +}
189 +
162 190 $status_type = '';
163 191 if (!empty($row['type'])) {
164 192 $status_type = JText::translate('VBO_BTYPE_' . strtoupper($row['type']));
165 193 if (!strcasecmp($row['type'], 'overbooking')) {
@@ -189,8 +217,24 @@
189 217
190 218 // extend administration sidebar
191 219 $adminSidebarForms = $this->onDisplayView('AdministrationSidebar');
192 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 +
193 237 //Prepare modal (used for the Registration and for reconstructing the credit card details through the channel manager)
194 238 echo $vbo_app->getJmodalScript();
195 239 //end Prepare modal
196 240 ?>
@@ -320,9 +364,9 @@
320 364 <span><?php echo date(str_replace("/", $datesep, $df).' H:i', $row['ts']); ?></span>
321 365 </div>
322 366 </div>
323 367 <?php
324 - if (!$printreceipt && count($customer)) {
368 + if (!$printreceipt && $customer) {
325 369 ?>
326 370 <div class="vbo-bookdet-wrap">
327 371 <div class="vbo-bookdet-head">
328 372 <span><?php echo JText::translate('VBCUSTOMERNOMINATIVE'); ?></span>
@@ -425,9 +469,9 @@
425 469 $checked_btn = 'btn-warning';
426 470 break;
427 471 default:
428 472 $checked_status = JText::translate('VBOCHECKEDSTATUSZERO');
429 - if (count($customer) && isset($customer['pax_data']) && !empty($customer['pax_data'])) {
473 + if ($customer && isset($customer['pax_data']) && !empty($customer['pax_data'])) {
430 474 // pre check-in performed via front-end
431 475 $checked_status = JText::translate('VBOCHECKEDSTATUSPRECHECKIN');
432 476 }
433 477 break;
@@ -449,23 +493,48 @@
449 493 //end Prepare modal
450 494 }
451 495
452 496 /**
453 - * Check whether the booking can be refunded.
497 + * Check whether the booking can be refunded or charged through an off-session capturing.
454 498 *
455 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.
456 501 */
457 502
458 - // refundable up to 7 days after check-out day
503 + // refundable/capturable up to 7 days after check-out day
459 504 $max_refund_ts = mktime(23, 59, 59, $checkout_info['mon'], ($checkout_info['mday'] + 7), $checkout_info['year']);
505 +
460 506 // current payment driver must be set
461 507 $tn_driver = is_array($payment) ? $payment['file'] : null;
508 +
462 509 // transaction data validation callback
463 510 $tn_data_callback = function($data) use ($tn_driver) {
464 511 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
465 512 };
466 513 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
467 - $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 +
468 537 if ($refundable) {
469 538 // prepare modal (refundtn) with a custom function to trigger the opening
470 539 array_push($vbo_modals_html, $vbo_app->getJmodalHtml('vbo-refund-tn', JText::translate('VBO_ISSUE_REFUND')));
471 540 echo $vbo_app->getJmodalScript('Refund', 'vboDetectRefundChanges();');
@@ -486,9 +555,9 @@
486 555 <div class="vbo-bookdet-head">
487 556 <span><?php echo JText::translate('VBO_ISSUE_REFUND'); ?></span>
488 557 </div>
489 558 <div class="vbo-bookdet-foot">
490 - <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');">
491 560 <?php echo JText::translate('VBO_REFUND'); ?>
492 561 </button>
493 562 </div>
494 563 </div>
@@ -493,9 +562,8 @@
493 562 </div>
494 563 </div>
495 564 <?php
496 565 }
497 - //
498 566
499 567 if (!$printreceipt && !empty($row['channel'])) {
500 568 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
501 569 if ($ota_logo_img === false) {
@@ -594,9 +662,9 @@
594 662 </div>
595 663 </div>
596 664 <?php
597 665 }
598 - 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) {
599 667 /**
600 668 * Guest misconduct reporting API for Booking.com.
601 669 * Only after reservation check-in date and no later than 7 days after check-out date.
602 670 *
@@ -670,9 +738,9 @@
670 738 },
671 739 (res) => {
672 740 // parse the JSON response that contains the categories object with all fields for the reporting
673 741 try {
674 - var misconduct_fields_rs = JSON.parse(res);
742 + var misconduct_fields_rs = typeof res === 'string' ? JSON.parse(res) : res;
675 743
676 744 // make sure the request was successful
677 745 if (!misconduct_fields_rs.status) {
678 746 alert(misconduct_fields_rs.error);
@@ -857,9 +925,9 @@
857 925 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikchannelmanager&task=submit_bcom_guestmisconduct'); ?>",
858 926 data: submit_fields
859 927 }).done(function(res) {
860 928 try {
861 - var misconduct_rs = JSON.parse(res);
929 + var misconduct_rs = typeof res === 'string' ? JSON.parse(res) : res;
862 930 console.log(submit_fields, misconduct_rs);
863 931
864 932 // make sure the request was successful
865 933 if (!misconduct_rs.status) {
@@ -988,9 +1056,9 @@
988 1056 $ir_data_callback = function($data) {
989 1057 return (is_object($data) && !empty($data->av_type));
990 1058 };
991 1059 $prev_ir_data = $history_obj->getEventsWithData('IR', $ir_data_callback, true);
992 - if (is_array($prev_ir_data) && count($prev_ir_data)) {
1060 + if (is_array($prev_ir_data) && $prev_ir_data) {
993 1061 // display a message about the availability type at the time of creation of the inquiry reservation
994 1062
995 1063 // parse original stay dates into DateTime objects
996 1064 $orig_checkin_dt_obj = new JDate($prev_ir_data[0]->checkin_date);
@@ -997,9 +1065,9 @@
997 1065 $orig_checkout_dt_obj = new JDate($prev_ir_data[0]->checkout_date);
998 1066 ?>
999 1067 <div class="vbo-bookdet-container vbo-bookdet-inquiry-alert">
1000 1068 <div class="vbo-bookdet-inquiry-alert-dismiss">
1001 - <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>
1002 1070 </div>
1003 1071 <div class="vbo-bookdet-inquiry-alert-message">
1004 1072 <div class="vbo-bookdet-inquiry-alert-top">
1005 1073 <span><?php echo JText::translate('VBO_WEB_INQUIRY_ALERT'); ?></span>
@@ -1033,8 +1101,43 @@
1033 1101 </div>
1034 1102 <div class="vbo-bookdet-inquiry-alert-bottom">
1035 1103 <span><?php echo JText::translate('VBO_WEB_INQUIRY_SUGG'); ?></span>
1036 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 + ?>
1037 1140 </div>
1038 1141 </div>
1039 1142 <?php
1040 1143 }
@@ -1050,16 +1153,23 @@
1050 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>
1051 1154 </div>
1052 1155 <?php
1053 1156 }
1054 - 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)) {
1055 1165
1056 1166 if (VBOPlatformDetection::isWordPress()) {
1057 1167 /**
1058 1168 * @wponly display warning message if no valid Shortcodes found
1059 1169 */
1060 - $model = JModel::getInstance('vikbooking', 'shortcodes');
1061 - $itemid = $model->best('booking');
1170 + $model = JModel::getInstance('vikbooking', 'shortcodes');
1171 + $itemid = $model->best('booking');
1062 1172 if (!$itemid) {
1063 1173 VikError::raiseWarning('', 'No Shortcodes found, or no Shortcodes being used in Pages/Posts.');
1064 1174 }
1065 1175 }
@@ -1069,9 +1179,9 @@
1069 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>
1070 1180 </div>
1071 1181 <?php
1072 1182 }
1073 - 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))) {
1074 1184 ?>
1075 1185 <div class="vbo-bookingdet-command">
1076 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>
1077 1187 </div>
@@ -1096,9 +1206,9 @@
1096 1206 </div>
1097 1207 <?php
1098 1208 }
1099 1209 }
1100 - if ($row['status'] == "standby" || ($row['status'] == "cancelled" && $row['checkout'] >= time())) {
1210 + if ($row['status'] == "standby" || ($row['status'] == "cancelled" && $row['checkout'] >= $current_ts)) {
1101 1211 ?>
1102 1212 <div class="vbo-bookingdet-command">
1103 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>
1104 1214 </div>
@@ -1210,11 +1320,84 @@
1210 1320 <div class="vbo-bookingdet-tab" data-vbotab="vbo-tab-admin"><?php echo JText::translate('VBOBOOKDETTABADMIN'); ?></div>
1211 1321 </div>
1212 1322 </div>
1213 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 +
1214 1341 <div class="vbo-bookingdet-tab-cont" id="vbo-tab-details" style="display: block;">
1215 1342 <div class="vbo-bookingdet-innercontainer">
1216 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 + ?>
1217 1400 <div class="vbo-bookingdet-detcont<?php echo $row['closure'] > 0 ? ' vbo-bookingdet-closure' : ''; ?>">
1218 1401 <?php
1219 1402 $custdata_parts = explode("\n", $row['custdata']);
1220 1403 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
@@ -1238,11 +1421,11 @@
1238 1421 }
1239 1422 unset($custdet_parts[0]);
1240 1423 if ((!strcasecmp(trim($custdet_parts[1]), 'http') || !strcasecmp(trim($custdet_parts[1]), 'https')) && !empty($custdet_parts[2]) && strpos($custdet_parts[2], '//') !== false) {
1241 1424 // this is a URI
1242 - $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>';
1243 1426 } else {
1244 - $custd_val = trim(implode(':', $custdet_parts));
1427 + $custd_val = htmlspecialchars(trim(implode(':', $custdet_parts)));
1245 1428 }
1246 1429 }
1247 1430 ?>
1248 1431 <div class="vbo-bookingdet-userdetail">
@@ -1348,8 +1531,9 @@
1348 1531 $channelparts = explode('_', $row['channel']);
1349 1532 if ($ch_logo = VikBooking::getVcmChannelsLogo($row['channel'], true)) {
1350 1533 $tiny_logo_url = $ch_logo->getTinyLogoURL();
1351 1534 }
1535 + $displayOtaBid = !strcasecmp((string) $row['type'], 'Inquiry') && $row['status'] == 'standby' ? '' : $row['idorderota'];
1352 1536 ?>
1353 1537 <div class="vbo-bookingdet-detcont-label vbo-bookingdet-detcont-label-idorderota <?php echo strtolower(preg_replace('/[^a-z0-9]/i', '', $channelparts[0])); ?>">
1354 1538 <span class="label label-info">
1355 1539 <span class="vbo-bookingdet-ota-details">
@@ -1361,10 +1545,11 @@
1361 1545 }
1362 1546 ?>
1363 1547 <span class="vbo-bookingdet-ota-name"><?php echo $otachannel_name . ' ID'; ?></span>
1364 1548 </span>
1365 - <span class="badge"><?php echo !strcasecmp((string)$row['type'], 'Inquiry') && $row['status'] == 'standby' ? '-----' : $row['idorderota']; ?></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>
1366 1550 </span>
1551 + <textarea class="vbo-textarea-copyable" data-copy="otabid"><?php echo htmlentities($displayOtaBid); ?></textarea>
1367 1552 </div>
1368 1553 <?php
1369 1554 }
1370 1555 if (strlen((string)$row['confirmnumber'])) {
@@ -1513,10 +1698,9 @@
1513 1698 <!-- Define role to detect the supported hook -->
1514 1699 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"invoice","type":"field"} -->
1515 1700
1516 1701 <?php
1517 - if (isset($bookingSidebarForms['invoice']))
1518 - {
1702 + if (isset($bookingSidebarForms['invoice'])) {
1519 1703 echo $bookingSidebarForms['invoice'];
1520 1704 }
1521 1705 ?>
1522 1706
@@ -1537,9 +1721,9 @@
1537 1721 </div>
1538 1722 </div>
1539 1723 <?php if (!empty($row['custmail'])) : ?>
1540 1724 <div class="vbo-bookingdet-btncont">
1541 - <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>
1542 1726 </div>
1543 1727 <?php endif; ?>
1544 1728 </div>
1545 1729
@@ -1546,10 +1730,9 @@
1546 1730 <!-- Define role to detect the supported hook -->
1547 1731 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"email","type":"field"} -->
1548 1732
1549 1733 <?php
1550 - if (isset($bookingSidebarForms['email']))
1551 - {
1734 + if (isset($bookingSidebarForms['email'])) {
1552 1735 echo $bookingSidebarForms['email'];
1553 1736 }
1554 1737 ?>
1555 1738
@@ -1561,13 +1744,27 @@
1561 1744 <div class="vbo-bookingdet-inpwrap">
1562 1745 <div class="vbo-bookingdet-inpcont">
1563 1746 <?php echo $vbo_app->printPhoneInputField(array('name' => 'custphone', 'id' => 'custphone', 'value' => $this->escape($row['phone'])), array('nationalMode' => false, 'fullNumberOnBlur' => true)); ?>
1564 1747 </div>
1565 - <?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 + ?>
1566 1753 <div class="vbo-bookingdet-btncont">
1567 - <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>
1568 1755 </div>
1569 - <?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 + ?>
1570 1767 </div>
1571 1768
1572 1769 <!-- Define role to detect the supported hook -->
1573 1770 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"phone","type":"field"} -->
@@ -1572,24 +1769,48 @@
1572 1769 <!-- Define role to detect the supported hook -->
1573 1770 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","key":"phone","type":"field"} -->
1574 1771
1575 1772 <?php
1576 - if (isset($bookingSidebarForms['phone']))
1577 - {
1773 + if (isset($bookingSidebarForms['phone'])) {
1578 1774 echo $bookingSidebarForms['phone'];
1579 1775 }
1580 1776 ?>
1581 1777
1582 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>
1583 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 +
1584 1807 <!-- Define role to detect the supported hook -->
1585 1808 <!-- {"rule":"customizer","event":"onDisplayViewVikBookingEditorderSidebar","type":"fieldset"} -->
1586 1809
1587 1810 <?php
1588 - foreach ($bookingSidebarForms as $legend => $form)
1589 - {
1590 - if (in_array($legend, ['userdetails', 'invoice', 'email', 'phone']))
1591 - {
1811 + foreach ($bookingSidebarForms as $legend => $form) {
1812 + if (in_array($legend, ['userdetails', 'invoice', 'email', 'phone'])) {
1592 1813 // skip default forms
1593 1814 continue;
1594 1815 }
1595 1816 ?>
@@ -1639,10 +1860,10 @@
1639 1860 <td class="vbo-bookingdet-summary-room-firstcell">
1640 1861 <div class="vbo-bookingdet-summary-room-wrap">
1641 1862 <div class="vbo-bookingdet-summary-roomnum"><?php VikBookingIcons::e($room_icon); ?> <?php echo JText::translate('VBEDITORDERTHREE').' '.$num; ?></div>
1642 1863 <?php
1643 - //Room Specific Unit
1644 - 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'])) {
1645 1866 $room_params = json_decode($or['params'], true);
1646 1867 $arr_features = array();
1647 1868 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
1648 1869 if (is_array($room_params) && array_key_exists('features', $room_params) && !empty($room_params['features'])) {
@@ -1657,9 +1878,9 @@
1657 1878 }
1658 1879 }
1659 1880 }
1660 1881 }
1661 - if (count($arr_features)) {
1882 + if ($arr_features) {
1662 1883 // $or['id'] equals to the ID of each matching record in _ordersrooms
1663 1884 ?>
1664 1885 <div class="vbo-bookingdet-summary-roomnum-chunit">
1665 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']] : ''); ?>
@@ -1685,9 +1906,9 @@
1685 1906 if ($arrpeople[$num]['children'] > 0) {
1686 1907 $age_str = '';
1687 1908 if (!empty($arrpeople[$num]['children_age'])) {
1688 1909 $json_child = json_decode($arrpeople[$num]['children_age'], true);
1689 - 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']) {
1690 1911 $age_str = ' '.JText::sprintf('VBORDERCHILDAGES', implode(', ', $json_child['age']));
1691 1912 }
1692 1913 }
1693 1914 ?>
@@ -1776,9 +1997,9 @@
1776 1997 </div>
1777 1998 <?php
1778 1999 }
1779 2000
1780 - 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']) {
1781 2002 // print split stay information for this room
1782 2003 $room_stay_checkin = !empty($room_stay_dates[$ind]['checkin_ts']) ? $room_stay_dates[$ind]['checkin_ts'] : $room_stay_dates[$ind]['checkin'];
1783 2004 $room_stay_checkout = !empty($room_stay_dates[$ind]['checkout_ts']) ? $room_stay_dates[$ind]['checkout_ts'] : $room_stay_dates[$ind]['checkout'];
1784 2005 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
@@ -1790,9 +2011,9 @@
1790 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>
1791 2012 </div>
1792 2013 </div>
1793 2014 <?php
1794 - } 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']) {
1795 2016 // print modified stay dates information for this room
1796 2017 $room_stay_checkin = $room_stay_records[$ind]['checkin'];
1797 2018 $room_stay_checkout = $room_stay_records[$ind]['checkout'];
1798 2019 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
@@ -1838,8 +2059,17 @@
1838 2059 $actopt = $dbo->loadAssocList();
1839 2060 if (!$actopt) {
1840 2061 continue;
1841 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 +
1842 2072 $counter++;
1843 2073 $chvar = '';
1844 2074 if (!empty($actopt[0]['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
1845 2075 $optagenames = VikBooking::getOptionIntervalsAges($actopt[0]['ageintervals']);
@@ -1875,9 +2105,9 @@
1875 2105 }
1876 2106 $actopt[0]['chageintv'] = $chvar;
1877 2107 $actopt[0]['name'] .= ' ('.$optagenames[($chvar - 1)].')';
1878 2108 $realcost = (intval($actopt[0]['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $room_stay_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
1879 - } else {
2109 + } elseif (is_numeric($stept[1])) {
1880 2110 // VBO 1.11 - options percentage cost of the room total fee
1881 2111 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
1882 2112 $deftar_basecosts = $or['cust_cost'];
1883 2113 } else {
@@ -1886,8 +2116,10 @@
1886 2116 }
1887 2117 $actopt[0]['cost'] = (int)$actopt[0]['pcentroom'] ? ($deftar_basecosts * $actopt[0]['cost'] / 100) : $actopt[0]['cost'];
1888 2118 //
1889 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;
1890 2122 }
1891 2123 if ($actopt[0]['maxprice'] > 0 && $realcost > $actopt[0]['maxprice']) {
1892 2124 $realcost = $actopt[0]['maxprice'];
1893 2125 if (intval($actopt[0]['hmany']) == 1 && intval($stept[1]) > 1) {
@@ -1894,8 +2126,19 @@
1894 2126 $realcost = $actopt[0]['maxprice'] * $stept[1];
1895 2127 }
1896 2128 }
1897 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 +
1898 2141 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt[0]['idiva']);
1899 2142 ?>
1900 2143 <tr class="vbo-bookingdet-summary-options">
1901 2144 <td class="vbo-bookingdet-summary-options-title"><?php echo $counter == 1 ? JText::translate('VBEDITORDEREIGHT') : '&nbsp;'; ?></td>
@@ -1983,9 +2226,9 @@
1983 2226 //Reservation Total
1984 2227 //Taxes Breakdown (only if tot_taxes is greater than 0)
1985 2228 $tax_breakdown = array();
1986 2229 $base_aliq = 0;
1987 - if (count($all_id_prices) > 0 && $row['tot_taxes'] > 0) {
2230 + if ($all_id_prices && $row['tot_taxes'] > 0) {
1988 2231 //only last type of price assuming that the tax breakdown is equivalent in case of different rates
1989 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;";
1990 2233 $dbo->setQuery($q);
1991 2234 $breakdown_info = $dbo->loadAssoc();
@@ -1991,9 +2234,9 @@
1991 2234 $breakdown_info = $dbo->loadAssoc();
1992 2235 if ($breakdown_info) {
1993 2236 if (!empty($breakdown_info['breakdown']) && !empty($breakdown_info['aliq'])) {
1994 2237 $tax_breakdown = json_decode($breakdown_info['breakdown'], true);
1995 - $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();
1996 2239 $base_aliq = $breakdown_info['aliq'];
1997 2240 }
1998 2241 }
1999 2242 }
@@ -2034,9 +2277,9 @@
2034 2277 <div class="vbdiscenter-entry">
2035 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>
2036 2279 </div>
2037 2280 <?php
2038 - if (count($tax_breakdown)) {
2281 + if ($tax_breakdown) {
2039 2282 foreach ($tax_breakdown as $tbkk => $tbkv) {
2040 2283 $tax_break_cost = $row['tot_taxes'] * floatval($tbkv['aliq']) / $base_aliq;
2041 2284 ?>
2042 2285 <div class="vbdiscenter-entry vbdiscenter-entry-breakdown">
@@ -2054,9 +2297,19 @@
2054 2297 </div>
2055 2298 <div class="vbdiscenter-entry">
2056 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>
2057 2300 </div>
2301 + <?php
2302 + if ($booking_has_damage_dep) {
2303 + // allow to overwrite (or see) the amount of damage deposit
2304 + ?>
2058 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">
2059 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>
2060 2313 </div>
2061 2314 <div class="vbdiscenter-entrycentered">
2062 2315 <button type="submit" class="btn btn-success"><?php echo JText::translate('VBAPPLYDISCOUNTSAVE'); ?></button>
@@ -2063,9 +2316,26 @@
2063 2316 </div>
2064 2317 </div>
2065 2318 </td>
2066 2319 <td>
2067 - <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 + ?>
2068 2338 </td>
2069 2339 </tr>
2070 2340 <?php
2071 2341 if ($row['total'] > 0 && !$row['closure']) {
@@ -2070,8 +2340,12 @@
2070 2340 <?php
2071 2341 if ($row['total'] > 0 && !$row['closure']) {
2072 2342 $has_paid = ($row['totpaid'] > 0);
2073 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 + }
2074 2348 if ($has_paid || $row['status'] != 'standby') {
2075 2349 ?>
2076 2350 <tr class="vbo-bookingdet-summary-totpaid">
2077 2351 <td>&nbsp;</td>
@@ -2129,9 +2403,9 @@
2129 2403 </tr>
2130 2404 <?php
2131 2405 }
2132 2406 }
2133 - 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')) {
2134 2408 /**
2135 2409 * The amount payable can be modified by the admin.
2136 2410 *
2137 2411 * @since 1.14 (J) - 1.4.0 (WP)
@@ -2237,9 +2511,9 @@
2237 2511 <?php
2238 2512 if (!$row['closure']) {
2239 2513 ?>
2240 2514 <div class="vbo-bookingdet-admin-entry">
2241 - <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>
2242 2516 <span style="display: block;"><?php echo JText::translate('VBOSEARCHEXISTCUST'); ?></span>
2243 2517 <span class="vbo-eorder-assigncust" style="margin-bottom: 1px;">
2244 2518 <input type="text" id="vbo-searchcust" autocomplete="off" value="" placeholder="<?php echo JText::translate('VBOSEARCHCUSTBY'); ?>" size="30" style="margin-bottom: 0;" />
2245 2519 </span>
@@ -2275,11 +2549,11 @@
2275 2549 <?php
2276 2550 }
2277 2551 $chpayment = '';
2278 2552 if ($payments) {
2279 - $chpayment = '<div><select name="newpayment" id="newpayment" onchange="changePayment();"><option value="">'.JText::translate('VBCHANGEPAYLABEL').'</option>';
2553 + $chpayment = '<div><select name="newpayment" id="newpayment" onchange="changePayment();"><option value="">- ' . JText::translate('VBCHANGEPAYLABEL') . ' -</option>';
2280 2554 foreach ($payments as $pay) {
2281 - $chpayment .= '<option value="'.$pay['id'].'">'.(is_array($payment) && $payment['id'] == $pay['id'] ? ' ::' : '').$pay['name'].'</option>';
2555 + $chpayment .= '<option value="' . $pay['id'] . '">' . (is_array($payment) && $payment['id'] == $pay['id'] ? '- ' : '') . $pay['name'] . '</option>';
2282 2556 }
2283 2557 $chpayment .= '</select></div>';
2284 2558 }
2285 2559 echo $chpayment;
@@ -2372,9 +2646,9 @@
2372 2646 } else {
2373 2647 $channelparts = explode('_', $row['channel']);
2374 2648 // check if this is a meta search channel
2375 2649 $is_meta_search = false;
2376 - 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')) {
2377 2651 $is_meta_search = empty($row['idorderota']);
2378 2652 }
2379 2653 if ($is_meta_search) {
2380 2654 // customer of type sales channel should use front-end reservation chat handler
@@ -2469,9 +2743,9 @@
2469 2743 }
2470 2744
2471 2745 if (!empty($row['paymentlog'])) {
2472 2746 $paylogs_lbl = JText::translate('VBPAYMENTLOGTOGGLE');
2473 - if (stripos($row['paymentlog'], 'card number') !== false && strpos($row['paymentlog'], '****') !== false) {
2747 + if ($may_have_cc_details) {
2474 2748 $paylogs_lbl = JText::translate('VBO_CREDIT_CARD');
2475 2749 }
2476 2750 ?>
2477 2751 <div class="vbo-bookingdet-noteslogs-btn" data-id="paylogs">
@@ -2486,9 +2760,9 @@
2486 2760 ?>
2487 2761 </div>
2488 2762 <div class="vbo-bookingdet-noteslogs-cont">
2489 2763 <div id="vbadminnotesdiv" class="vbo-extra-panel" style="display: block;">
2490 - <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>
2491 2765 <input type="submit" name="updadmnotes" value="<?php echo JText::translate('VBADMINNOTESUPD'); ?>" class="btn btn-success" />
2492 2766 </div>
2493 2767 <?php
2494 2768 if ($takings) {
@@ -2547,9 +2821,9 @@
2547 2821 ?>
2548 2822 <tr class="vbo-booking-takings-row">
2549 2823 <td>
2550 2824 <?php
2551 - echo $currencysymb . ' ' . VikBooking::numberFormat($tn_amount_paid);
2825 + echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($tn_amount_paid), $currencysymb);
2552 2826 if (!strcasecmp($hist['type'], 'PU')) {
2553 2827 /**
2554 2828 * Allow to edit or delete the history record.
2555 2829 *
@@ -2565,9 +2839,9 @@
2565 2839 ?>
2566 2840 </td>
2567 2841 <td><?php echo JHtml::fetch('date', $hist['dt'], 'Y-m-d H:i:s'); ?></td>
2568 2842 <td><?php echo $history_obj->validType($hist['type'], true); ?></td>
2569 - <td><?php echo $currencysymb . ' ' . VikBooking::numberFormat($tn_amount_fees); ?></td>
2843 + <td><?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($tn_amount_fees), $currencysymb); ?></td>
2570 2844 <td><?php echo $tn_description; ?></td>
2571 2845 </tr>
2572 2846 <?php
2573 2847 }
@@ -2575,13 +2849,13 @@
2575 2849 </tbody>
2576 2850 <tfoot>
2577 2851 <tr>
2578 2852 <td colspan="2">
2579 - <span><?php echo $currencysymb . ' ' . VikBooking::numberFormat($booking_total_taking); ?></span>
2853 + <span><?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($booking_total_taking), $currencysymb); ?></span>
2580 2854 </td>
2581 2855 <td></td>
2582 2856 <td>
2583 - <span><?php echo $currencysymb . ' ' . VikBooking::numberFormat($booking_total_prfees); ?></span>
2857 + <span><?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($booking_total_prfees), $currencysymb); ?></span>
2584 2858 </td>
2585 2859 <td>
2586 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>
2587 2861 </td>
@@ -2605,9 +2879,9 @@
2605 2879 <span><?php echo $currencysymb; ?></span>
2606 2880 <input type="number" id="new_taking_amount" value="" min="0" max="<?php echo $row['total']; ?>" step="any" />
2607 2881 </div>
2608 2882 <span class="vbo-param-setting-comment">
2609 - <?php echo JText::translate('VBOCUSTOMERCMMSONTOTAL') . ' ' . $currencysymb . ' ' . VikBooking::numberFormat($row['total']) . ' - ' . JText::translate('VBAMOUNTPAID') . ' ' . $currencysymb . ' ' . VikBooking::numberFormat($row['totpaid']); ?>
2883 + <?php echo JText::translate('VBOCUSTOMERCMMSONTOTAL') . ' ' . VikBooking::formatCurrencyNumber(VikBooking::numberFormat($row['total']), $currencysymb) . ' - ' . JText::translate('VBAMOUNTPAID') . ' ' . VikBooking::formatCurrencyNumber(VikBooking::numberFormat($row['totpaid']), $currencysymb); ?>
2610 2884 </span>
2611 2885 </div>
2612 2886 </div>
2613 2887 <div class="vbo-param-container">
@@ -2903,10 +3177,9 @@
2903 3177 *
2904 3178 * @since 1.13
2905 3179 */
2906 3180 $cardlimit = mktime(23, 59, 59, $checkout_info['mon'], ($checkout_info['mday'] + 10), $checkout_info['year']);
2907 - $plain_log = htmlspecialchars($row['paymentlog']);
2908 - if (time() < $cardlimit && stripos($plain_log, 'card number') !== false && strpos($plain_log, '****') !== false) {
3181 + if ($current_ts < $cardlimit && $may_have_cc_details) {
2909 3182 // log contains credit card details
2910 3183 // prepare modal (Credit Card Details)
2911 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;'));
2912 3185 ?>
@@ -2948,9 +3221,9 @@
2948 3221
2949 3222 // display action buttons for payment schedules
2950 3223 ?>
2951 3224 <div class="vbo-eorder-payschedules-wrap">
2952 - <button type="button" class="btn btn-<?php echo $active_payschedules ? 'success' : 'primary'; ?> vbo-context-menu-btn vbo-context-menu-payschedules">
3225 + <button type="button" class="btn btn-<?php echo $active_payschedules || $automatic_payment_collection ? 'success' : 'primary'; ?> vbo-context-menu-btn vbo-context-menu-payschedules">
2953 3226 <span class="vbo-context-menu-lbl"><?php echo JText::translate('VBO_AUTOPAY_SCHEDULED'); ?></span>
2954 3227 <span class="vbo-context-menu-ico"><?php VikBookingIcons::e('sort-down'); ?></span>
2955 3228 </button>
2956 3229 </div>
@@ -2955,9 +3228,10 @@
2955 3228 </button>
2956 3229 </div>
2957 3230
2958 3231 <div class="vbo-eorder-newpayschedule-helper-wrap" style="display: none;">
2959 - <div class="vbo-eorder-newpayschedule-helper-cont">
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>
2960 3234 <div class="vbo-admin-container vbo-admin-container-full vbo-admin-container-compact">
2961 3235 <div class="vbo-params-wrap">
2962 3236 <div class="vbo-params-container">
2963 3237 <div class="vbo-params-block">
@@ -2969,9 +3243,9 @@
2969 3243 <div class="vbo-input-currency-wrap">
2970 3244 <span><?php echo $currencysymb; ?></span>
2971 3245 <input type="number" id="new_payschedule_amount" value="<?php echo $tot_scheduled < $row['total'] ? ($row['total'] - $tot_scheduled) : 0; ?>" min="0" step="any" />
2972 3246 </div>
2973 - <span class="vbo-param-setting-comment"><?php echo JText::translate('VBEDITORDERNINE') . ' ' . $currencysymb . ' ' . VikBooking::numberFormat($row['total']); ?></span>
3247 + <span class="vbo-param-setting-comment"><?php echo JText::translate('VBEDITORDERNINE') . ' ' . VikBooking::formatCurrencyNumber(VikBooking::numberFormat($row['total']), $currencysymb); ?></span>
2974 3248 </div>
2975 3249 </div>
2976 3250 <div class="vbo-param-container">
2977 3251 <div class="vbo-param-label">
@@ -3009,8 +3283,52 @@
3009 3283 <script type="text/javascript">
3010 3284
3011 3285 // build base buttons list for context menu
3012 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 + },
3013 3331 // add new payment schedule button
3014 3332 {
3015 3333 icon: '<?php echo VikBookingIcons::i('plus-circle'); ?>',
3016 3334 text: Joomla.JText._('VBO_NEW_PAYSCHEDULE'),
@@ -3049,10 +3367,12 @@
3049 3367 // dismiss the modal
3050 3368 VBOCore.emitEvent('vbo-eorder-new-payschedule-dismiss');
3051 3369 // populate the new schedule buttons
3052 3370 let new_pay_schedule_btns = [];
3053 - // push the button to add a new schedule
3371 + // push button to toggle automatic payment collection scheduling for all bookings
3054 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]);
3055 3375 // push all active schedules
3056 3376 new_pay_schedules.forEach((payschedule) => {
3057 3377 new_pay_schedule_btns.push(
3058 3378 vboBuildPayScheduleBtn(payschedule)
@@ -3093,8 +3413,21 @@
3093 3413 );
3094 3414 },
3095 3415 });
3096 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 +
3097 3430 // append modal body
3098 3431 jQuery('.vbo-eorder-newpayschedule-helper-cont').appendTo(modal_body);
3099 3432 },
3100 3433 }
@@ -3116,9 +3449,9 @@
3116 3449 }
3117 3450
3118 3451 return {
3119 3452 icon: ((payschedule.status || 0) > 0 ? (payschedule.status == 1 ? icn_processed : icn_error) : icn_to_process),
3120 - text: '<?php echo $currencysymb . ' '; ?>' + payschedule?.amount + ' - ' + say_dt,
3453 + text: VBOCore.getCurrency().format(payschedule?.amount) + ' - ' + say_dt,
3121 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')),
3122 3455 separator: false,
3123 3456 action: (root, config) => {
3124 3457 if (payschedule.status == 0 || !payschedule.logs) {
@@ -3133,10 +3466,12 @@
3133 3466 },
3134 3467 (new_pay_schedules) => {
3135 3468 // populate the new schedule buttons
3136 3469 let new_pay_schedule_btns = [];
3137 - // push the button to add a new schedule
3470 + // push button to toggle automatic payment collection scheduling for all bookings
3138 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]);
3139 3474 // push all active schedules
3140 3475 new_pay_schedules.forEach((payschedule) => {
3141 3476 new_pay_schedule_btns.push(
3142 3477 vboBuildPayScheduleBtn(payschedule)
@@ -3188,10 +3523,12 @@
3188 3523 // dismiss the modal
3189 3524 VBOCore.emitEvent('vbo-eorder-payschedule-logs-dismiss');
3190 3525 // populate the new schedule buttons
3191 3526 let new_pay_schedule_btns = [];
3192 - // push the button to add a new schedule
3527 + // push button to toggle automatic payment collection scheduling for all bookings
3193 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]);
3194 3531 // push all active schedules
3195 3532 new_pay_schedules.forEach((payschedule) => {
3196 3533 new_pay_schedule_btns.push(
3197 3534 vboBuildPayScheduleBtn(payschedule)
@@ -3281,9 +3618,9 @@
3281 3618 <?php
3282 3619 // render the reporting-invalidcc layout
3283 3620 echo JLayoutHelper::render('reporting.invalidcc', $layout_data, null, [
3284 3621 'component' => 'com_vikchannelmanager',
3285 - 'client' => 'administrator',
3622 + 'client' => 'admin',
3286 3623 ]);
3287 3624 ?>
3288 3625 </div>
3289 3626 <?php
@@ -3374,90 +3711,94 @@
3374 3711 <input type="hidden" name="cid[]" value="<?php echo $row['id']; ?>" />
3375 3712 <input type="hidden" name="invnotes" id="invnotes-hid" value="" />
3376 3713 </form>
3377 3714
3378 -<div class="vbo-modal-overlay-block vbo-modal-overlay-block-sms-email">
3379 - <a class="vbo-modal-overlay-close" href="javascript: void(0);"></a>
3380 - <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;">
3381 3716
3382 - <div class="vbo-modal-overlay-content-head vbo-modal-overlay-content-sms-email-head">
3383 - <h3>
3384 - <span></span>
3385 - <span class="vbo-modal-overlay-close-times" onclick="vboToggleSendEmail();">&times;</span>
3386 - </h3>
3387 - </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">
3388 3722
3389 - <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>
3390 3731
3391 - <div id="vbo-overlay-sms-cont" style="display: none;">
3392 - <h4 style="display: none;"><?php echo JText::translate('VBSENDSMSACTION'); ?>: <span id="smstophone-lbl"><?php echo $row['phone']; ?></span></h4>
3393 - <form action="index.php?option=com_vikbooking" method="post" id="vbo-modal-form-sms">
3394 - <div class="vbo-calendar-cfield-entry">
3395 - <label for="smscont"><?php echo JText::translate('VBSENDSMSCUSTCONT'); ?></label>
3396 - <span><textarea name="smscont" id="smscont" style="width: 99%; min-width: 99%;max-width: 99%; height: 120px;"></textarea></span>
3397 3732 </div>
3398 - <input type="hidden" name="phone" id="smstophone" value="<?php echo $row['phone']; ?>" />
3399 - <input type="hidden" name="goto" value="<?php echo urlencode('index.php?option=com_vikbooking&task=editorder&cid[]='.$row['id']); ?>" />
3400 - <input type="hidden" name="task" value="sendcustomsms" />
3401 - </form>
3733 + </div>
3402 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>
3403 3740
3404 - <div id="vbo-overlay-email-cont" style="display: none;">
3405 - <h4 style="display: none;"><?php echo JText::translate('VBSENDEMAILACTION'); ?>: <span id="emailto-lbl"><?php echo $row['custmail']; ?></span></h4>
3406 - <form action="index.php?option=com_vikbooking" method="post" enctype="multipart/form-data" id="vbo-modal-form-email">
3407 - <input type="hidden" name="bid" value="<?php echo $row['id']; ?>" />
3408 - <?php
3409 - $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
3410 - $dbo->setQuery($q);
3411 - $cur_emtpl = $dbo->loadResult();
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">
3412 3746
3413 - $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
3414 - $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
3747 + <?php
3748 + $cur_emtpl = VBOFactory::getConfig()->getArray('customemailtpls', []);
3749 + if ($cur_emtpl) {
3750 + ?>
3751 + <div class="vbo-param-container">
3752 + <div class="vbo-param-setting">
3753 + <select id="emtpl-customemail" onchange="vboLoadEmailTpl(this.value);">
3754 + <option value=""><?php echo JText::translate('VBEMAILCUSTFROMTPL'); ?></option>
3755 + <?php
3756 + foreach ($cur_emtpl as $emk => $emv) {
3757 + ?>
3758 + <optgroup label="<?php echo $emv['emailsubj']; ?>">
3759 + <option value="<?php echo $emk; ?>"><?php echo JText::translate('VBEMAILCUSTFROMTPLUSE'); ?></option>
3760 + <option value="rm<?php echo $emk; ?>"><?php echo JText::translate('VBEMAILCUSTFROMTPLRM'); ?></option>
3761 + </optgroup>
3762 + <?php
3763 + }
3764 + ?>
3765 + </select>
3766 + </div>
3767 + </div>
3768 + <?php
3769 + }
3415 3770
3416 - if ($cur_emtpl) {
3417 - ?>
3418 - <div class="vbo-calendar-custmail-tpls-wrap">
3419 - <select id="emtpl-customemail" onchange="vboLoadEmailTpl(this.value);">
3420 - <option value=""><?php echo JText::translate('VBEMAILCUSTFROMTPL'); ?></option>
3421 - <?php
3422 - foreach ($cur_emtpl as $emk => $emv) {
3423 - ?>
3424 - <optgroup label="<?php echo $emv['emailsubj']; ?>">
3425 - <option value="<?php echo $emk; ?>"><?php echo JText::translate('VBEMAILCUSTFROMTPLUSE'); ?></option>
3426 - <option value="rm<?php echo $emk; ?>"><?php echo JText::translate('VBEMAILCUSTFROMTPLRM'); ?></option>
3427 - </optgroup>
3428 - <?php
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>');
3429 3782 }
3430 - ?>
3431 - </select>
3432 - </div>
3433 - <?php
3434 - }
3435 -
3436 - /**
3437 - * Load all conditional text special tags.
3438 - *
3439 - * @since 1.14 (J) - 1.4.0 (WP)
3440 - */
3441 - $extra_btns = array();
3442 - $condtext_tags = VikBooking::getConditionalRulesInstance()->getSpecialTags();
3443 - if ($condtext_tags) {
3444 - $condtext_tags = array_keys($condtext_tags);
3445 - foreach ($condtext_tags as $tag) {
3446 - array_push($extra_btns, '<button type="button" class="btn btn-secondary btn-small vbo-condtext-specialtag-btn" onclick="setSpecialTplTag(\'emailcont\', \'' . $tag . '\');">' . $tag . '</button>');
3447 3783 }
3448 - }
3449 - //
3450 - ?>
3451 - <div class="vbo-calendar-cfields-wrap">
3452 - <div class="vbo-calendar-cfield-entry">
3453 - <label for="emailsubj"><?php echo JText::translate('VBSENDEMAILCUSTSUBJ'); ?></label>
3454 - <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>
3455 3792 </div>
3456 - <div class="vbo-calendar-cfield-entry">
3457 - <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">
3458 3799 <?php
3459 - $special_tags_base = array(
3800 + $special_tags_base = [
3460 3801 '{customer_name}',
3461 3802 '{booking_id}',
3462 3803 '{checkin_date}',
3463 3804 '{checkout_date}',
@@ -3470,9 +3811,9 @@
3470 3811 '{total}',
3471 3812 '{total_paid}',
3472 3813 '{remaining_balance}',
3473 3814 '{booking_link}',
3474 - );
3815 + ];
3475 3816
3476 3817 $special_tags_base_html = '';
3477 3818 foreach ($special_tags_base as $sp_tag) {
3478 3819 $special_tags_base_html .= '<button type="button" class="btn btn-secondary btn-small" onclick="setSpecialTplTag(\'emailcont\', \'' . $sp_tag . '\');">' . $sp_tag . '</button>' . "\n";
@@ -3482,20 +3823,25 @@
3482 3823 * Use the rich text editor (visual editor) to build custom email messages.
3483 3824 *
3484 3825 * @since 1.15.0 (J) - 1.5.0 (WP)
3485 3826 */
3486 - $tarea_attr = array(
3827 + $tarea_attr = [
3487 3828 'id' => 'emailcont',
3488 3829 'rows' => '7',
3489 3830 'cols' => '170',
3490 3831 'style' => 'width: 99%; min-width: 99%; max-width: 99%; height: 120px; margin-bottom: 1px;',
3491 - );
3492 - $editor_opts = array(
3493 - 'modes' => array(
3832 + ];
3833 + $editor_opts = [
3834 + 'modes' => [
3835 + 'visual',
3494 3836 'text',
3495 - 'visual',
3496 - ),
3497 - );
3837 + ],
3838 + 'gen_ai' => [
3839 + 'booking' => $row,
3840 + 'customer' => $customer,
3841 + 'environment' => 'booking',
3842 + ],
3843 + ];
3498 3844 $editor_btns = $special_tags_base;
3499 3845 if ($condtext_tags) {
3500 3846 $editor_btns = array_merge($editor_btns, $condtext_tags);
3501 3847 }
@@ -3516,92 +3862,172 @@
3516 3862
3517 3863 // render visual editor
3518 3864 echo $vbo_app->renderVisualEditor('emailcont', '', $tarea_attr, $editor_opts, $editor_btns);
3519 3865 ?>
3520 - <div class="btn-group pull-left vbo-smstpl-bgroup vbo-custmail-bgroup vik-contentbuilder-textmode-sptags">
3521 - <?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>
3522 3869 </div>
3523 3870 </div>
3524 - <div class="vbo-calendar-cfield-entry">
3525 - <label for="emailattch"><?php echo JText::translate('VBSENDEMAILCUSTATTCH'); ?></label>
3526 - <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>
3527 3879 </div>
3528 - <div class="vbo-calendar-cfield-entry">
3529 - <label for="emailfrom"><?php echo JText::translate('VBSENDEMAILCUSTFROM'); ?></label>
3530 - <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>
3531 3888 </div>
3889 +
3532 3890 </div>
3533 - <input type="hidden" name="email" id="emailto" value="<?php echo $row['custmail']; ?>" />
3534 - <input type="hidden" name="goto" value="<?php echo urlencode('index.php?option=com_vikbooking&task=editorder&cid[]='.$row['id']); ?>" />
3535 - <input type="hidden" name="task" value="sendcustomemail" />
3536 - </form>
3891 + </div>
3537 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>
3538 3899
3539 - </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>
3540 3907
3541 - <div class="vbo-modal-overlay-content-footer">
3542 - <div class="vbo-modal-overlay-content-footer-right">
3543 - <div id="vbo-modal-footer-sms" style="display: none;">
3544 - <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>
3545 3954 </div>
3546 - <div id="vbo-modal-footer-email" style="display: none;">
3547 - <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>
3548 - </div>
3549 3955 </div>
3550 3956 </div>
3551 -
3552 3957 </div>
3553 3958 </div>
3554 3959
3555 3960 <script type="text/javascript">
3556 -var vbo_overlay_on = false;
3557 3961 var vbo_print_only = false;
3558 -if (jQuery.isFunction(jQuery.fn.tooltip)) {
3962 +if (typeof jQuery.fn.tooltip === 'function') {
3559 3963 jQuery(".hasTooltip").tooltip();
3560 3964 }
3561 -function vboToggleSendSMS() {
3965 +function vboDisplaySendSMS() {
3562 3966 var cur_phone = jQuery("#smstophone").val();
3563 3967 var phone_set = jQuery("#custphone").trigger('vboupdatephonenumber').val();
3564 3968 if (phone_set.length && phone_set != cur_phone) {
3565 3969 jQuery("#smstophone").val(phone_set);
3566 - jQuery("#smstophone-lbl").text(phone_set);
3567 3970 }
3568 3971
3569 - // toggle email/sms contents
3570 - jQuery("#vbo-overlay-email-cont, #vbo-modal-footer-email").hide();
3571 - jQuery("#vbo-overlay-sms-cont, #vbo-modal-footer-sms").show();
3572 - var use_modal_title = jQuery("#vbo-overlay-sms-cont").find('h4').first().html();
3573 - 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 + });
3574 3980
3575 - jQuery(".vbo-modal-overlay-block-sms-email").fadeToggle(400, function() {
3576 - if (jQuery(".vbo-modal-overlay-block-sms-email").is(":visible")) {
3577 - vbo_overlay_on = true;
3578 - } else {
3579 - vbo_overlay_on = false;
3580 - }
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 + },
3581 3994 });
3995 +
3996 + jQuery('.vbo-editorder-sms-send-wrap').appendTo(modal_body);
3582 3997 }
3583 -function vboToggleSendEmail() {
3998 +function vboDisplaySendEmail() {
3584 3999 var cur_email = jQuery("#emailto").val();
3585 4000 var email_set = jQuery("#custmail").val();
3586 4001 if (email_set.length && email_set != cur_email) {
3587 4002 jQuery("#emailto").val(email_set);
3588 - jQuery("#emailto-lbl").text(email_set);
3589 4003 }
3590 4004
3591 - // toggle email/sms contents
3592 - jQuery("#vbo-overlay-sms-cont, #vbo-modal-footer-sms").hide();
3593 - jQuery("#vbo-overlay-email-cont, #vbo-modal-footer-email").show();
3594 - var use_modal_title = jQuery("#vbo-overlay-email-cont").find('h4').first().html();
3595 - 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 + });
3596 4013
3597 - jQuery(".vbo-modal-overlay-block-sms-email").fadeToggle(400, function() {
3598 - if (jQuery(".vbo-modal-overlay-block-sms-email").is(":visible")) {
3599 - vbo_overlay_on = true;
3600 - } else {
3601 - vbo_overlay_on = false;
3602 - }
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 + },
3603 4027 });
4028 +
4029 + jQuery('.vbo-editorder-email-send-wrap').appendTo(modal_body);
3604 4030 }
3605 4031 function vboKeyupEmail(event) {
3606 4032 if (event.key && event.key == 'Enter') {
3607 4033 event.preventDefault();
@@ -3638,8 +4064,12 @@
3638 4064 }
3639 4065 // reload the page to display the new information about the booking just modified
3640 4066 location.reload();
3641 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 + });
3642 4072 // remove overbooking flag
3643 4073 jQuery('.vbo-label-overbooking').on('click', function() {
3644 4074 if (confirm(Joomla.JText._('VBO_CONF_RM_OVERBOOKING_FLAG'))) {
3645 4075 VBOCore.doAjax(
@@ -3735,24 +4165,8 @@
3735 4165 return;
3736 4166 }
3737 4167 });
3738 4168 // Search customer - End
3739 - jQuery(document).mouseup(function(e) {
3740 - if (!vbo_overlay_on) {
3741 - return false;
3742 - }
3743 - var vbo_overlay_cont = jQuery(".vbo-modal-overlay-content-sms-email");
3744 - if (!vbo_overlay_cont.is(e.target) && vbo_overlay_cont.has(e.target).length === 0 && !jQuery(e.target).is('svg')) {
3745 - jQuery(".vbo-modal-overlay-block-sms-email").fadeOut();
3746 - vbo_overlay_on = false;
3747 - }
3748 - });
3749 - jQuery(document).keyup(function(e) {
3750 - if (e.keyCode == 27 && vbo_overlay_on) {
3751 - jQuery(".vbo-modal-overlay-block-sms-email").fadeOut();
3752 - vbo_overlay_on = false;
3753 - }
3754 - });
3755 4169 jQuery(".vbo-bookingdet-tab").click(function() {
3756 4170 var newtabrel = jQuery(this).attr('data-vbotab');
3757 4171 var oldtabrel = jQuery(".vbo-bookingdet-tab-active").attr('data-vbotab');
3758 4172 if (newtabrel == oldtabrel) {
@@ -3883,8 +4297,242 @@
3883 4297 idorder: '<?php echo $row['id']; ?>',
3884 4298 }
3885 4299 });
3886 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 +
3887 4535 });
3888 4536 var cur_emtpl = <?php echo json_encode($cur_emtpl); ?>;
3889 4537 function vboLoadEmailTpl(tplind) {
3890 4538 if (!(tplind.length > 0)) {
@@ -3911,9 +4559,9 @@
3911 4559 <?php
3912 4560 $pcustomemail = VikRequest::getInt('customemail', '', 'request');
3913 4561 if ($pcustomemail > 0) {
3914 4562 ?>
3915 - vboToggleSendEmail();
4563 + vboDisplaySendEmail();
3916 4564 <?php
3917 4565 }
3918 4566 if ($printreceipt) {
3919 4567 ?>