Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/vikbooking/admin/controller.php
+++ b/vikbooking/admin/controller.php
@@ -2519,11 +2519,46 @@
$q = "SELECT `b`.`id`,`b`.`idroom` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=" . $ord['id'] . ";";
$dbo->setQuery($q);
$allbusy = $dbo->loadAssocList();
+
foreach ($allbusy as $bb) {
$q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $first . ", `checkout`=" . $second . ", `realback`=" . $realback . " WHERE `id`=" . $bb['id'] . ";";
$dbo->setQuery($q);
$dbo->execute();
}
+
+ if (!$allbusy) {
+ /**
+ * If no existing busy records were fetched, it means we have some missing or broken
+ * records in the database. Proceed with restoring them to occupy the room(s).
+ *
+ * @since 1.8.19 (J) - 1.8.9 (WP)
+ */
+ $dbo->setQuery(
+ $dbo->getQuery(true)
+ ->delete($dbo->qn('#__vikbooking_ordersbusy'))
+ ->where($dbo->qn('idorder') . ' = ' . (int) $ord['id'])
+ );
+ $dbo->execute();
+ foreach ($ordersrooms as $or) {
+ if ($room_removed !== false && $or['id'] == $prm_room_oid) {
+ continue;
+ }
+ $restoreBusyRecord = (object) [
+ 'idroom' => $or['idroom'],
+ 'checkin' => $first,
+ 'checkout' => $second,
+ 'realback' => $realback,
+ ];
+ $dbo->insertObject('#__vikbooking_busy', $restoreBusyRecord, 'id');
+ if (!empty($restoreBusyRecord->id)) {
+ $restoreBusyRelation = (object) [
+ 'idorder' => $ord['id'],
+ 'idbusy' => $restoreBusyRecord->id,
+ ];
+ $dbo->insertObject('#__vikbooking_ordersbusy', $restoreBusyRelation, 'id');
+ }
+ }
+ }
}
/**
@@ -11170,7 +11205,7 @@
$cust_old_fields = array();
$cstring_search = '<div class="vbo-custsearchres-inner">' . "n";
foreach ($customers as $k => $v) {
- $cstring_search .= '<div class="' . $selector . '" data-custid="'.$v['id'].'" data-email="'.$v['email'].'" data-phone="'.htmlspecialchars($v['phone']).'" data-country="'.$v['country'].'" data-pin="'.$v['pin'].'" data-firstname="'.htmlspecialchars($v['first_name']).'" data-lastname="'.htmlspecialchars($v['last_name']).'">'."n";
+ $cstring_search .= '<div class="' . $selector . '" data-custid="' . (int) $v['id'] . '" data-email="' . htmlspecialchars($v['email']) . '" data-phone="' . htmlspecialchars($v['phone']) . '" data-country="' . htmlspecialchars($v['country']) . '" data-pin="' . htmlspecialchars($v['pin']) . '" data-firstname="' . htmlspecialchars($v['first_name']) . '" data-lastname="' . htmlspecialchars($v['last_name']) . '">'."n";
$cstring_search .= '<span class="vbo-custsearchres-cflag">';
if (!empty($v['pic'])) {
$cstring_search .= '<img src="' . (strpos($v['pic'], 'http') === 0 ? $v['pic'] : VBO_SITE_URI . 'resources/uploads/' . $v['pic']) . '" class="vbo-country-flag vbo-customer-avatar-flag"/>'."n";
--- a/vikbooking/admin/controllers/payschedules.php
+++ b/vikbooking/admin/controllers/payschedules.php
@@ -46,7 +46,7 @@
}
// current date object
- $now_dt = JFactory::getdate('now');
+ $now_dt = JFactory::getDate('now');
// access the time with hours and minutes
$time_parts = explode(':', $time);
--- a/vikbooking/admin/controllers/quote.php
+++ b/vikbooking/admin/controllers/quote.php
@@ -135,6 +135,7 @@
'children' => array_sum(array_column($solution['rooms'], 'children')),
'id_payment' => $quote['id_payment'] ?? null,
'lock_until' => $quote['validity'] ?? null,
+ 'dont_lock' => empty($quote['validity']),
'idquote' => $quoteId,
], true);
--- a/vikbooking/admin/helpers/src/model/payschedules.php
+++ b/vikbooking/admin/helpers/src/model/payschedules.php
@@ -156,6 +156,54 @@
}
/**
+ * Method to delete one or more records.
+ *
+ * @param mixed $pks An array of record primary keys, or a single one.
+ *
+ * @return bool True if successful, false if an error occurs.
+ *
+ * @since 1.8.19 (J) - 1.8.9 (WP)
+ */
+ public function delete($pks)
+ {
+ $dbo = JFactory::getDbo();
+
+ if (!$pks) {
+ // nothing to delete
+ return false;
+ }
+
+ if (!is_array($pks)) {
+ // wrap into an array
+ $pks = [$pks];
+ }
+
+ $deleted = 0;
+
+ foreach ($pks as $pk) {
+ // ensure the item exists
+ $item = $this->getItem($pk);
+
+ if (!$item) {
+ continue;
+ }
+
+ $dbo->setQuery(
+ $dbo->getQuery(true)
+ ->delete($dbo->qn('#__vikbooking_payschedules'))
+ ->where($dbo->qn('id') . ' = ' . (int) $item->id)
+ );
+ $dbo->execute();
+
+ if ((bool) $dbo->getAffectedRows()) {
+ $deleted++;
+ }
+ }
+
+ return (bool) $deleted;
+ }
+
+ /**
* Watches and eventually processes the automatic payment collections scheduled.
*
* @param int $lim the limit of payments to process, defaults to 5 per execution.
--- a/vikbooking/admin/helpers/src/model/quote.php
+++ b/vikbooking/admin/helpers/src/model/quote.php
@@ -137,6 +137,7 @@
$dbo->qn('o.idpayment'),
$dbo->qn('o.roomsnum'),
$dbo->qn('o.total'),
+ $dbo->qn('o.lang'),
$dbo->qn('o.idquote'),
$dbo->qn('or.idroom'),
$dbo->qn('or.adults'),
@@ -214,6 +215,7 @@
'nights' => $bookingRoomsData[0]->days,
'status' => $bookingRoomsData[0]->status,
'total' => $bookingRoomsData[0]->total,
+ 'lang' => $bookingRoomsData[0]->lang,
'idpayment' => $bookingRoomsData[0]->idpayment,
'sid' => $bookingRoomsData[0]->sid,
'ts' => $bookingRoomsData[0]->ts,
@@ -390,6 +392,13 @@
// access booking registry for the first related booking (if any)
$bookingRegistry = $bookingIds ? VBOBookingRegistry::getInstance(['id' => $bookingIds[0] ?? 0]) : null;
+ // route quote URI
+ $quoteUri = VikBooking::externalroute(
+ "index.php?option=com_vikbooking&view=quote&ref={$quote->uuid}",
+ false,
+ (VikBooking::findProperItemIdType(['quote'], $bookingRegistry->getProperty('lang') ?: null) ?: null)
+ );
+
// build the list of known tag parameters
$tagParameters = [
'{first_name}' => $quote->first_name ?? '',
@@ -400,7 +409,7 @@
'{tot_adults}' => $bookingRegistry ? $bookingRegistry->countTotalAdults() : 0,
'{tot_children}' => $bookingRegistry ? $bookingRegistry->countTotalChildren() : 0,
'{tot_guests}' => $bookingRegistry ? $bookingRegistry->countTotalGuests() : 0,
- '{quote_link}' => VikBooking::externalroute("index.php?option=com_vikbooking&view=quote&ref={$quote->uuid}", false),
+ '{quote_link}' => $quoteUri,
];
/**
--- a/vikbooking/admin/helpers/src/model/reservation.php
+++ b/vikbooking/admin/helpers/src/model/reservation.php
@@ -2597,6 +2597,7 @@
$num_rooms = $this->isMultiRoom() ? count($rooms_pool) : $this->get('num_rooms', 1);
$default_checkin = $this->get('checkin', 0);
$default_checkout = $this->get('checkout', 0);
+ $check_locked = (bool) $this->get('check_locked', 0);
// determine availability
$rooms_available = true;
@@ -2624,8 +2625,13 @@
// check the remaining availability for the number of room units booked
$unitsBooked = $roomUnitsUse[$roomStay['idroom']];
$check_units = $roomStay['units'] - $unitsBooked + 1;
- // check if the room is available
- $rooms_available = VikBooking::roomBookable($roomStay['idroom'], $check_units, $roomStay['checkin'], $roomStay['checkout']);
+ if ($check_locked) {
+ // check if the room is available and not temporarily locked
+ $rooms_available = VikBooking::roomNotLocked($roomStay['idroom'], $check_units, $roomStay['checkin'], $roomStay['checkout'], true);
+ } else {
+ // check if the room is available
+ $rooms_available = VikBooking::roomBookable($roomStay['idroom'], $check_units, $roomStay['checkin'], $roomStay['checkout']);
+ }
if (!$rooms_available) {
// set an error and abort
$this->setError(sprintf(
@@ -2646,8 +2652,13 @@
// only when non closing the room we check the availability for the units requested for booking
$check_units = $check_units - $num_rooms + 1;
}
- // check if the room is available
- $rooms_available = VikBooking::roomBookable($rooms_pool[0]['id'], $check_units, $default_checkin, $default_checkout);
+ if ($check_locked) {
+ // check if the room is available and not temporarily locked
+ $rooms_available = VikBooking::roomNotLocked($rooms_pool[0]['id'], $check_units, $default_checkin, $default_checkout, true);
+ } else {
+ // check if the room is available
+ $rooms_available = VikBooking::roomBookable($rooms_pool[0]['id'], $check_units, $default_checkin, $default_checkout);
+ }
}
} else {
$all_rooms = $this->loadAllRoomsData();
@@ -3490,21 +3501,24 @@
} elseif ($status == 'standby' && empty($split_stay_data)) {
// lock room for pending status when NO split-stay data by supporting room-level dates
$lockUntil = VikBooking::getMinutesLock(true);
+
if ($this->get('lock_until')) {
// convert expected date-time string into a timestamp for custom lock until date
$lockUntil = strtotime((string) $this->get('lock_until')) ?: $lockUntil;
}
- // store room lock record
- $tmplock_record = new stdClass;
- $tmplock_record->idroom = (int) $nowroom['id'];
- $tmplock_record->checkin = $room_stay_checkin;
- $tmplock_record->checkout = $room_stay_checkout;
- $tmplock_record->until = $lockUntil;
- $tmplock_record->realback = $room_stay_realback;
- $tmplock_record->idorder = (int) $newoid;
+ if ($lockUntil && $this->get('dont_lock') !== true) {
+ // store room lock record
+ $tmplock_record = new stdClass;
+ $tmplock_record->idroom = (int) $nowroom['id'];
+ $tmplock_record->checkin = $room_stay_checkin;
+ $tmplock_record->checkout = $room_stay_checkout;
+ $tmplock_record->until = $lockUntil;
+ $tmplock_record->realback = $room_stay_realback;
+ $tmplock_record->idorder = (int) $newoid;
- $dbo->insertObject('#__vikbooking_tmplock', $tmplock_record, 'id');
+ $dbo->insertObject('#__vikbooking_tmplock', $tmplock_record, 'id');
+ }
}
}
}
--- a/vikbooking/admin/helpers/src/taxonomy/summary.php
+++ b/vikbooking/admin/helpers/src/taxonomy/summary.php
@@ -201,13 +201,17 @@
return $tax_map[$tax_id];
}
+ if (empty($tax_id)) {
+ return [];
+ }
+
$dbo = JFactory::getDbo();
$q = "SELECT * FROM `#__vikbooking_iva` WHERE `id`=" . $tax_id;
$dbo->setQuery($q, 0, 1);
// cache value and return it
- $tax_map[$tax_id] = $dbo->loadAssoc();
+ $tax_map[$tax_id] = (array) $dbo->loadAssoc();
return $tax_map[$tax_id];
}
--- a/vikbooking/admin/helpers/widgets/booking_details.php
+++ b/vikbooking/admin/helpers/widgets/booking_details.php
@@ -681,7 +681,7 @@
<div class="vbo-params-block">
<div class="vbo-param-container">
<div class="vbo-param-setting">
- <blockquote class="vbo-booking-admin-notes"><?php echo nl2br($details['adminnotes']); ?></blockquote>
+ <blockquote class="vbo-booking-admin-notes"><?php echo nl2br(htmlspecialchars($details['adminnotes'])); ?></blockquote>
</div>
</div>
</div>
--- a/vikbooking/admin/helpers/widgets/guest_messages.php
+++ b/vikbooking/admin/helpers/widgets/guest_messages.php
@@ -405,7 +405,7 @@
<div class="vbo-dashboard-guest-activity-content-head">
<div class="vbo-dashboard-guest-activity-content-info-details">
<h4 class="vbo-w-guestmessages-message-gtitle"><span><?php
- if (!$gmessage->first_name && !$gmessage->last_name) {
+ if (empty($gmessage->first_name) && empty($gmessage->last_name)) {
echo JText::translate('VBO_GUEST');
} else {
echo $gmessage->first_name . (!empty($gmessage->last_name) ? ' ' . $gmessage->last_name : '');
--- a/vikbooking/admin/layouts/quote/manage/html.php
+++ b/vikbooking/admin/layouts/quote/manage/html.php
@@ -84,6 +84,12 @@
<?php
if ($quote) {
+ // route quote URI
+ $quoteUri = VikBooking::externalroute(
+ "index.php?option=com_vikbooking&view=quote&ref={$quote->uuid}",
+ false,
+ (VikBooking::findProperItemIdType(['quote'], $quote->solutions[0]->lang ?? null) ?: null)
+ );
?>
<div class="vbo-quote-section vbo-quote-section-current" data-quote-id="<?php echo $quote->id; ?>">
<div class="vbo-quote-section-head vbo-quote-section-head-sb">
@@ -92,7 +98,7 @@
<span class="vbo-quote-section-name"><?php echo sprintf('%s #%d', JText::translate('VBO_BTYPE_QUOTE'), $quote->id); ?></span>
</div>
<div class="vbo-quote-edit-link">
- <a class="btn btn-small vbo-config-btn" target="_blank" href="<?php echo VikBooking::externalroute('index.php?option=com_vikbooking&view=quote&ref=' . $quote->uuid); ?>"><?php VikBookingIcons::e('external-link'); ?> <?php echo JText::translate('VBVIEWORDFRONT'); ?></a>
+ <a class="btn btn-small vbo-config-btn" target="_blank" href="<?php echo $quoteUri; ?>"><?php VikBookingIcons::e('external-link'); ?> <?php echo JText::translate('VBVIEWORDFRONT'); ?></a>
</div>
</div>
<div class="vbo-quote-section-body">
@@ -402,7 +408,7 @@
</div>
<div class="vbo-quote-section-body">
<div class="vbo-quote-validity-date">
- <label for="vbo-quote-valid-until"><?php echo JText::translate('VBO_QUOTE_VALIDITY'); ?></label>
+ <label for="vbo-quote-valid-until"><?php echo JText::translate('VBO_QUOTE_VALIDITY'); ?> <span class="vbo-quote-validity-date-help"><?php VikBookingIcons::e('circle-question', 'icn-nomargin'); ?></span></label>
<?php
$validUntilVal = JFactory::getDate('+2 days 23:59')->format('Y-m-d H:i');
if ($quote) {
--- a/vikbooking/admin/layouts/quote/manage/script.php
+++ b/vikbooking/admin/layouts/quote/manage/script.php
@@ -517,6 +517,18 @@
});
/**
+ * Register event listener for the valid until help icon.
+ */
+ document.querySelector('.vbo-quote-validity-date-help')?.addEventListener('click', (e) => {
+ VBOCore.displayModal({
+ extra_class: 'vbo-modal-rounded vbo-modal-tooltip',
+ body: <?php echo json_encode(JText::translate('VBO_LOCK_UNTIL_HELP')); ?>,
+ lock_scroll: true,
+ draggable: false,
+ });
+ });
+
+ /**
* Register event listener for the quote submit (save new) button.
*/
document.querySelector('.vbo-quote-submit-btn')?.addEventListener('click', (e) => {
--- a/vikbooking/admin/views/editorder/tmpl/default.php
+++ b/vikbooking/admin/views/editorder/tmpl/default.php
@@ -2714,7 +2714,7 @@
</div>
<div class="vbo-bookingdet-noteslogs-cont">
<div id="vbadminnotesdiv" class="vbo-extra-panel" style="display: block;">
- <textarea name="adminnotes" class="vbadminnotestarea"><?php echo strip_tags((string)$row['adminnotes']); ?></textarea>
+ <textarea name="adminnotes" class="vbadminnotestarea"><?php echo JHtml::fetch('esc_textarea', (string) $row['adminnotes']); ?></textarea>
<input type="submit" name="updadmnotes" value="<?php echo JText::translate('VBADMINNOTESUPD'); ?>" class="btn btn-success" />
</div>
<?php
--- a/vikbooking/admin/views/orders/tmpl/default.php
+++ b/vikbooking/admin/views/orders/tmpl/default.php
@@ -766,7 +766,7 @@
if (!empty($row['adminnotes'])) {
?>
<span class="vbo-admin-tipsicon vbo-admin-notes-icn" data-bid="<?php echo $row['id']; ?>"><?php VikBookingIcons::e('sticky-note'); ?></span>
- <div class="vbo-order-admin-notes-cnt" data-bid="<?php echo $row['id']; ?>" style="display: none;"><?php echo nl2br($row['adminnotes']); ?></div>
+ <div class="vbo-order-admin-notes-cnt" data-bid="<?php echo $row['id']; ?>" style="display: none;"><?php echo nl2br(htmlspecialchars($row['adminnotes'])); ?></div>
<?php
}
--- a/vikbooking/defines.php
+++ b/vikbooking/defines.php
@@ -12,7 +12,7 @@
defined('ABSPATH') or die('No script kiddies please!');
// Software version
-define('VIKBOOKING_SOFTWARE_VERSION', '1.8.8');
+define('VIKBOOKING_SOFTWARE_VERSION', '1.8.9');
// Base path
define('VIKBOOKING_BASE', dirname(__FILE__));
--- a/vikbooking/libraries/language/admin.php
+++ b/vikbooking/libraries/language/admin.php
@@ -8672,6 +8672,9 @@
case 'VBO_QUOTE_NOTES_HELP':
$result = __('Notes will be displayed to customer in front-end.', 'vikbooking');
break;
+ case 'VBO_LOCK_UNTIL_HELP':
+ $result = __('Set a date to temporarily lock the selected rooms. Leave blank to keep availability open.', 'vikbooking');
+ break;
}
return $result;
--- a/vikbooking/site/controller.php
+++ b/vikbooking/site/controller.php
@@ -304,6 +304,10 @@
$user_inp_val = VikRequest::getString('vbf' . $cf['id'], '', 'request');
if (intval($cf['isemail']) == 1 && $emailwasfound == false) {
$useremail = trim($user_inp_val);
+ if (!preg_match('/^(([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/', $useremail)) {
+ showSelectVb('Invalid email address provided.');
+ return;
+ }
$emailwasfound = true;
}
if ($cf['isnominative'] == 1) {
@@ -4576,9 +4580,9 @@
$checkout_m = $input->getInt('checkoutm', 0);
$categories = $input->getString('categories', '');
$roomsnum = $input->getInt('roomsnum', 1);
- $adults = $input->get('adults', array(), 'int');
- $children = $input->get('children', array(), 'int');
- $inquiry = $input->get('inquiry', array(), 'raw');
+ $adults = $input->get('adults', [], 'int');
+ $children = $input->get('children', [], 'int');
+ $inquiry = $input->get('inquiry', [], 'array');
$ulang = $input->getString('ulang', '');
$timeopst = VikBooking::getTimeOpenStore();
@@ -4625,6 +4629,8 @@
// empty or invalid field
continue;
}
+ // accept only text from submitted value
+ $info_val = strip_tags($info_val);
if ($info_type == 'nominative') {
if (empty($t_first_name)) {
$t_first_name = $info_val;
--- a/vikbooking/site/helpers/icons.php
+++ b/vikbooking/site/helpers/icons.php
@@ -100,6 +100,7 @@
'cog' => 'fas fa-gear',
'cogs' => 'fas fa-gears',
'user-cog' => 'fas fa-user-gear',
+ 'circle-question' => 'far fa-circle-question',
/**
* Resolving map used until the older FA v5.12.1.
--- a/vikbooking/site/helpers/lib.vikbooking.php
+++ b/vikbooking/site/helpers/lib.vikbooking.php
@@ -2038,21 +2038,16 @@
* This was made to return the proper number of days in advance
* in case the property is currently closed.
*/
- public static function getMinDaysAdvance($no_closing_dates = false) {
+ public static function getMinDaysAdvance($no_closing_dates = false)
+ {
// cache value in static var
static $getMinDaysAdvance = null;
if ($getMinDaysAdvance) {
return $getMinDaysAdvance;
}
- //
- $dbo = JFactory::getDbo();
-
- $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='mindaysadvance';";
- $dbo->setQuery($q);
- $dbo->execute();
- $mind = $dbo->getNumRows() ? (int)$dbo->loadResult() : 0;
+ $mind = VBOFactory::getConfig()->getInt('mindaysadvance', 0);
// update cached var
$getMinDaysAdvance = $mind;
@@ -5185,7 +5180,7 @@
return $cost;
}
- $tax_rate = VBOTaxonomySummary::getTaxRateRecord($idiva);
+ $tax_rate = VBOTaxonomySummary::getTaxRateRecord((int) $idiva);
if (!$tax_rate) {
return $cost;
}
@@ -5232,7 +5227,7 @@
return $cost;
}
- $tax_rate = VBOTaxonomySummary::getTaxRateRecord($idiva);
+ $tax_rate = VBOTaxonomySummary::getTaxRateRecord((int) $idiva);
if (!$tax_rate) {
return $cost;
}
@@ -5278,7 +5273,7 @@
return $cost;
}
- $tax_rate = VBOTaxonomySummary::getTaxRateRecord($idiva);
+ $tax_rate = VBOTaxonomySummary::getTaxRateRecord((int) $idiva);
if (!$tax_rate) {
return $cost;
}
@@ -5322,7 +5317,7 @@
return $cost;
}
- $tax_rate = VBOTaxonomySummary::getTaxRateRecord($idiva);
+ $tax_rate = VBOTaxonomySummary::getTaxRateRecord((int) $idiva);
if (!$tax_rate) {
return $cost;
}
--- a/vikbooking/site/views/oconfirm/tmpl/default.php
+++ b/vikbooking/site/views/oconfirm/tmpl/default.php
@@ -1339,7 +1339,7 @@
$dep_amount = VikBooking::calcDepositOverride($dep_amount, $days);
$dep_type = VikBooking::getTypeDeposit();
$dep_nonrefund_allowed = VikBooking::allowDepositFromRates($tars);
- if (!(count($this->mod_booking) > 0) && !VikBooking::payTotal() && VikBooking::depositAllowedDaysAdv($second) && VikBooking::depositCustomerChoice() && $dep_amount > 0 && $dep_nonrefund_allowed && ($dep_type == "fixed" || ($dep_type != "fixed" && $dep_amount < 100))) {
+ if (!(count($this->mod_booking) > 0) && !VikBooking::payTotal() && VikBooking::depositAllowedDaysAdv($first) && VikBooking::depositCustomerChoice() && $dep_amount > 0 && $dep_nonrefund_allowed && ($dep_type == "fixed" || ($dep_type != "fixed" && $dep_amount < 100))) {
$dep_amount = ($dep_amount - abs($dep_amount)) > 0.00 ? VikBooking::numberFormat($dep_amount) : $dep_amount;
$dep_string = $dep_type == "fixed" ? VikBooking::formatCurrencyNumber($dep_amount, $currencysymb) : $dep_amount . '%';
?>
--- a/vikbooking/site/views/quote/tmpl/default.php
+++ b/vikbooking/site/views/quote/tmpl/default.php
@@ -150,6 +150,11 @@
$totalRooms = count($quoteSolution->rooms);
// tell if we should "hide" this quote solution by default
$isHid = $isConfirmed && $quoteSolution->status != 'confirmed';
+ // rate components collector
+ $rateComponents = [
+ 'applied' => 0,
+ 'original' => 0,
+ ];
?>
<div class="vbo-quote-solution">
@@ -248,6 +253,9 @@
// fallback onto the last room rate obtained
$origRoomRateData = end($roomRates[$bookingRoom->id]) ?: null;
}
+ // increase rate components
+ $rateComponents['applied'] += $bookingRoom->cust_cost;
+ $rateComponents['original'] += $origRoomRateData['cost'];
}
}
?>
@@ -417,7 +425,23 @@
<div class="vbo-quote-sol-footer" style="<?php echo $isHid ? 'display: none;' : ''; ?>">
<div class="vbo-quote-sol-total">
<div class="vbo-quote-sol-total-label"><?php echo JText::translate('VBTOTAL'); ?></div>
- <div class="vbo-quote-sol-total-price"><?php echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($quoteSolution->total), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']); ?></div>
+ <div class="vbo-quote-sol-total-price">
+ <?php
+ if ($rateComponents['applied'] && $rateComponents['original'] > $rateComponents['applied']) {
+ // calculate the total cost without the custom discounted rate
+ $originalTotal = $quoteSolution->total - $rateComponents['applied'] + $rateComponents['original'];
+ // display striked-through amount
+ ?>
+ <span class="vbo-quote-sol-total-price-disc"><?php
+ echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($originalTotal), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']);
+ ?></span>
+ <?php
+ }
+
+ // display quote solution total amount
+ echo VikBooking::formatCurrencyNumber(VikBooking::numberFormat($quoteSolution->total), $currencysymb, ['<span class="vbo_currency">%s</span>', '<span class="vbo_price">%s</span>']);
+ ?>
+ </div>
<div class="vbo-quote-sol-total-subtext"><?php
echo implode(', ', [
sprintf('%d %s', $totalRooms, JText::translate($totalRooms === 1 ? 'VBSEARCHRESROOM' : 'VBSEARCHRESROOMS')),
--- a/vikbooking/vikbooking.php
+++ b/vikbooking/vikbooking.php
@@ -3,7 +3,7 @@
Plugin Name: VikBooking
Plugin URI: https://vikwp.com/plugin/vikbooking
Description: Certified Booking Engine for Hotels and Accommodations.
-Version: 1.8.8
+Version: 1.8.9
Author: E4J s.r.l.
Author URI: https://vikwp.com
License: GPL2