diff --git a/admin/themes/default/template/controllers/languages/helpers/form/form.tpl b/admin/themes/default/template/controllers/languages/helpers/form/form.tpl
index 8d1dc403e..77baa0e70 100644
--- a/admin/themes/default/template/controllers/languages/helpers/form/form.tpl
+++ b/admin/themes/default/template/controllers/languages/helpers/form/form.tpl
@@ -69,11 +69,11 @@
{foreach $list.files as $key => $file}
{if !file_exists($key)}
-
+
{/if}
{$key}
{if !file_exists($key)}
-
+
{/if}
{/foreach}
diff --git a/admin/themes/default/template/controllers/orders/_current_cart_details_data.tpl b/admin/themes/default/template/controllers/orders/_current_cart_details_data.tpl
index e3405fa99..300bb29d0 100644
--- a/admin/themes/default/template/controllers/orders/_current_cart_details_data.tpl
+++ b/admin/themes/default/template/controllers/orders/_current_cart_details_data.tpl
@@ -130,7 +130,7 @@
{*
{displayPrice price=$data.amt_with_qty} | *}
- {if (isset($data.extra_demands) && $data.extra_demands) || (isset($data.additional_service) && $data.additional_service)}
+ {if (isset($data.extra_demands) && $data.extra_demands) || (isset($data.additional_service) && $data.additional_service) || (isset($data.selected_services) && $data.selected_services)}
{displayPrice price=($data.amt_with_qty + $data.additional_services_auto_add_price + $data.demand_price + $data.additional_service_price)|escape:'html':'UTF-8'}
{else}
{displayPrice price=$data.amt_with_qty|escape:'html':'UTF-8'}
diff --git a/classes/Cart.php b/classes/Cart.php
index ad5ee4302..d7421ec7d 100644
--- a/classes/Cart.php
+++ b/classes/Cart.php
@@ -1833,7 +1833,7 @@ class CartCore extends ObjectModel
$this->id,
[],
0,
- isset($product['id_hotel_cart_booking']) ? $product['id_hotel_cart_booking'] : null,
+ null,
null,
(int)$product['id_product'],
null,
@@ -1862,53 +1862,55 @@ class CartCore extends ObjectModel
// by webkul to calculate rates of the product from hotelreservation syatem tables with feature prices....
$totalPriceByProduct = 0;
$priceDisplay = Group::getPriceDisplayMethod(Group::getCurrent()->id);
- foreach ($roomTypesByIdProduct as $key => $cartRoomInfo) {
- $occupancy = array(
- array(
- 'adults' => $cartRoomInfo['adults'],
- 'children' => $cartRoomInfo['children'],
- 'child_ages' => json_decode($cartRoomInfo['child_ages'])
- )
+
+ if ($type == Cart::ADVANCE_PAYMENT || $type == Cart::ADVANCE_PAYMENT_ONLY_PRODUCTS) {
+ // getProductMinAdvPaymentAmountByIdCart already aggregates all rooms for this product internally,
+ // so call it once and add once — not inside the per-room loop.
+ $advProductPrice = $objAdvPayment->getProductMinAdvPaymentAmountByIdCart(
+ $this->id,
+ $product['id_product'],
+ 0,
+ 0,
+ $with_taxes
);
- // get the real price of the room type
- $roomTotalPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice(
- $cartRoomInfo['id_product'],
- $cartRoomInfo['date_from'],
- $cartRoomInfo['date_to'],
- $occupancy,
- Group::getCurrent()->id,
- $cartRoomInfo['id_cart'],
- $cartRoomInfo['id_guest'],
- $cartRoomInfo['id_room'],
- 0
- );
- if ($with_taxes) {
- $totalPriceByProduct = $roomTotalPrice['total_price_tax_incl'];
- } else {
- $totalPriceByProduct = $roomTotalPrice['total_price_tax_excl'];
- }
-
- // If customer has selected advance payment of the cart
- if ($type == Cart::ADVANCE_PAYMENT || $type == Cart::ADVANCE_PAYMENT_ONLY_PRODUCTS) {
- $advProductPrice = $objAdvPayment->getProductMinAdvPaymentAmountByIdCart(
- $this->id,
- $cartRoomInfo['id_product'],
- 0,
- 0,
- $with_taxes
- );
-
- // set advance payment price only if it is greater than real price
- if ($advProductPrice < $totalPriceByProduct) {
- $totalPriceByProduct = $advProductPrice;
- }
- }
-
- // Rounding as per configurations
if ($ps_round_type == Order::ROUND_TOTAL) {
- $products_total[$id_tax_rules_group.'_'.$id_address] += Tools::processPriceRounding($totalPriceByProduct);
+ $products_total[$id_tax_rules_group.'_'.$id_address] += Tools::processPriceRounding($advProductPrice);
} else {
- $products_total[$id_tax_rules_group] += Tools::processPriceRounding($totalPriceByProduct);
+ $products_total[$id_tax_rules_group] += Tools::processPriceRounding($advProductPrice);
+ }
+ } else {
+ foreach ($roomTypesByIdProduct as $key => $cartRoomInfo) {
+ $occupancy = array(
+ array(
+ 'adults' => $cartRoomInfo['adults'],
+ 'children' => $cartRoomInfo['children'],
+ 'child_ages' => json_decode($cartRoomInfo['child_ages'])
+ )
+ );
+ // get the real price of the room type
+ $roomTotalPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice(
+ $cartRoomInfo['id_product'],
+ $cartRoomInfo['date_from'],
+ $cartRoomInfo['date_to'],
+ $occupancy,
+ Group::getCurrent()->id,
+ $cartRoomInfo['id_cart'],
+ $cartRoomInfo['id_guest'],
+ $cartRoomInfo['id_room'],
+ 0
+ );
+ if ($with_taxes) {
+ $totalPriceByProduct = $roomTotalPrice['total_price_tax_incl'];
+ } else {
+ $totalPriceByProduct = $roomTotalPrice['total_price_tax_excl'];
+ }
+
+ // Rounding as per configurations
+ if ($ps_round_type == Order::ROUND_TOTAL) {
+ $products_total[$id_tax_rules_group.'_'.$id_address] += Tools::processPriceRounding($totalPriceByProduct);
+ } else {
+ $products_total[$id_tax_rules_group] += Tools::processPriceRounding($totalPriceByProduct);
+ }
}
}
}
diff --git a/classes/Profile.php b/classes/Profile.php
index 39637163a..54900fb44 100644
--- a/classes/Profile.php
+++ b/classes/Profile.php
@@ -81,7 +81,7 @@ class ProfileCore extends ObjectModel
public function add($autodate = true, $null_values = false)
{
if (parent::add($autodate, true)) {
- $result = Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'access (SELECT '.(int)$this->id.', id_tab, 0, 0, 0, 0 FROM '._DB_PREFIX_.'tab)');
+ $result = Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'access (SELECT '.(int)$this->id.', id_tab, 0, 0, 0, 0, 0 FROM '._DB_PREFIX_.'tab)');
$result &= Db::getInstance()->execute('
INSERT INTO '._DB_PREFIX_.'module_access
(`id_profile`, `id_module`, `configure`, `view`, `uninstall`)
@@ -138,6 +138,7 @@ class ProfileCore extends ObjectModel
'add' => 1,
'edit' => 1,
'delete' => 1,
+ 'kpi' => 1,
);
}
} else {
@@ -151,6 +152,7 @@ class ProfileCore extends ObjectModel
$result[$key]['delete'] = (int) $profileAccess['delete'];
$result[$key]['add'] = (int) $profileAccess['add'];
$result[$key]['edit'] = (int) $profileAccess['edit'];
+ $result[$key]['kpi'] = (int) $profileAccess['kpi'];
}
}
diff --git a/classes/SpecificPrice.php b/classes/SpecificPrice.php
index 1dd3829a2..79c63995e 100644
--- a/classes/SpecificPrice.php
+++ b/classes/SpecificPrice.php
@@ -367,12 +367,12 @@ class SpecificPriceCore extends ObjectModel
`id_shop` '.self::formatIntInQuery(0, $id_shop).' AND
`id_currency` '.self::formatIntInQuery(0, $id_currency).' AND
`id_country` '.self::formatIntInQuery(0, $id_country).
- ' AND `id_htl_cart_booking`='.(int)$id_htl_cart_booking.' '.
+ ' AND `id_htl_cart_booking` '.self::formatIntInQuery(0, $id_htl_cart_booking).' '.
(Group::isFeatureActive() ? ' AND `id_group` '.self::formatIntInQuery(0, $id_group) : '').' '.$query_extra.'
AND IF(`from_quantity` > 1, `from_quantity`, 0) <= ';
$query .= (Configuration::get('PS_QTY_DISCOUNT_ON_COMBINATION') || !$id_cart || !$real_quantity) ? (int)$quantity : max(1, (int)$real_quantity);
- $query .= ' ORDER BY `id_product_attribute` DESC, `from_quantity` DESC, `score` DESC, `to` DESC, `from` DESC';
+ $query .= ' ORDER BY `id_htl_cart_booking` DESC, `id_product_attribute` DESC, `from_quantity` DESC, `score` DESC, `to` DESC, `from` DESC';
SpecificPrice::$_specificPriceCache[$key] = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow($query);
}
diff --git a/classes/Tab.php b/classes/Tab.php
index 662ad74b5..4f8dfed89 100644
--- a/classes/Tab.php
+++ b/classes/Tab.php
@@ -137,12 +137,12 @@ class TabCore extends ObjectModel
}
/* Query definition */
- $query = 'REPLACE INTO `'._DB_PREFIX_.'access` (`id_profile`, `id_tab`, `view`, `add`, `edit`, `delete`) VALUES ';
- $query .= '(1, '.(int)$id_tab.', 1, 1, 1, 1),';
+ $query = 'REPLACE INTO `'._DB_PREFIX_.'access` (`id_profile`, `id_tab`, `view`, `add`, `edit`, `delete`, `kpi`) VALUES ';
+ $query .= '(1, '.(int)$id_tab.', 1, 1, 1, 1, 1),';
foreach ($profiles as $profile) {
$rights = $profile['id_profile'] == $context->employee->id_profile ? 1 : 0;
- $query .= '('.(int)$profile['id_profile'].', '.(int)$id_tab.', '.(int)$rights.', '.(int)$rights.', '.(int)$rights.', '.(int)$rights.'),';
+ $query .= '('.(int)$profile['id_profile'].', '.(int)$id_tab.', '.(int)$rights.', '.(int)$rights.', '.(int)$rights.', '.(int)$rights.', '.(int)$rights.'),';
}
$query = trim($query, ', ');
return Db::getInstance()->execute($query);
@@ -247,7 +247,7 @@ class TabCore extends ObjectModel
* @return array tabs
*/
protected static $_cache_tabs = array();
- public static function getTabs($id_lang, $id_parent = null)
+ public static function getTabs($id_lang, $id_parent = null, $include_kpi = false)
{
if (!isset(self::$_cache_tabs[$id_lang])) {
self::$_cache_tabs[$id_lang] = array();
@@ -274,10 +274,52 @@ class TabCore extends ObjectModel
foreach (self::$_cache_tabs[$id_lang] as $array_parent) {
$array_all = array_merge($array_all, $array_parent);
}
- return $array_all;
+ $tabs = $array_all;
+ } else {
+ $tabs = isset(self::$_cache_tabs[$id_lang][$id_parent]) ? self::$_cache_tabs[$id_lang][$id_parent] : array();
}
- return (isset(self::$_cache_tabs[$id_lang][$id_parent]) ? self::$_cache_tabs[$id_lang][$id_parent] : array());
+ if ($include_kpi) {
+ $hookKpiClasses = array();
+ $hookRows = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
+ SELECT DISTINCT SUBSTRING(h.`name`, 7, LENGTH(h.`name`) - 24) AS `class_name`
+ FROM `'._DB_PREFIX_.'hook` h
+ INNER JOIN `'._DB_PREFIX_.'hook_module` hm
+ ON hm.`id_hook` = h.`id_hook`
+ AND hm.`id_shop` = '.(int)Context::getContext()->shop->id.'
+ INNER JOIN `'._DB_PREFIX_.'module` m
+ ON m.`id_module` = hm.`id_module` AND m.`active` = 1
+ WHERE h.`name` LIKE \'action%KPIListingModifier\''
+ );
+ if (is_array($hookRows)) {
+ foreach ($hookRows as $row) {
+ $hookKpiClasses[$row['class_name']] = true;
+ }
+ }
+
+ foreach ($tabs as &$tab) {
+ if (!empty($tab['module'])) {
+ $file = _PS_MODULE_DIR_.$tab['module'].'/controllers/admin/'.$tab['class_name'].'Controller.php';
+ $class_name = $tab['class_name'].'Controller';
+ } else {
+ $file = _PS_CONTROLLER_DIR_.'admin/'.$tab['class_name'].'Controller.php';
+ $class_name = $tab['class_name'].'ControllerCore';
+ }
+ if (file_exists($file) && !class_exists($class_name)) {
+ require_once $file;
+ }
+ try {
+ $objreflect = new ReflectionMethod($class_name, 'renderKpis');
+ $tab['has_kpi'] = ($objreflect->getDeclaringClass()->getName() === $class_name)
+ || isset($hookKpiClasses[$tab['class_name']]);
+ } catch (ReflectionException $e) {
+ $tab['has_kpi'] = isset($hookKpiClasses[$tab['class_name']]);
+ }
+ }
+ unset($tab);
+ }
+
+ return $tabs;
}
/**
diff --git a/classes/controller/AdminController.php b/classes/controller/AdminController.php
index 88cb91075..bdf2d3f74 100644
--- a/classes/controller/AdminController.php
+++ b/classes/controller/AdminController.php
@@ -2307,7 +2307,9 @@ class AdminControllerCore extends Controller
$this->content .= $this->renderDetails();
} elseif (!$this->ajax) {
$this->content .= $this->renderModulesList();
- $this->content .= $this->renderKpis();
+ if ($this->tabAccess['kpi'] === 1) {
+ $this->content .= $this->renderKpis();
+ }
$this->content .= $this->renderList();
$this->content .= $this->renderOptions();
diff --git a/classes/pdf/HTMLTemplateBookingVoucher.php b/classes/pdf/HTMLTemplateBookingVoucher.php
new file mode 100644
index 000000000..c4e5d17df
--- /dev/null
+++ b/classes/pdf/HTMLTemplateBookingVoucher.php
@@ -0,0 +1,396 @@
+order = $order;
+ $this->smarty = $smarty;
+ $this->date = Tools::displayDate(date('Y-m-d'));
+ $this->title = sprintf(self::l('Booking Voucher - %s'), $this->order->reference);
+ $this->shop = new Shop((int)$this->order->id_shop);
+ }
+
+ /**
+ * @return string HTML header
+ */
+ public function getHeader()
+ {
+ $this->assignCommonHeaderData();
+ $this->smarty->assign(array('header' => self::l('Booking Voucher')));
+
+ return $this->smarty->fetch($this->getTemplate('header'));
+ }
+
+ /**
+ * Assembles all voucher data inline and renders the template.
+ *
+ * @return string HTML content
+ */
+ public function getContent()
+ {
+ // --- Bookings ---
+ $objHotelBookingDetail = new HotelBookingDetail();
+ $bookings = $objHotelBookingDetail->getBookingDataByOrderId((int)$this->order->id);
+ if (!is_array($bookings)) {
+ $bookings = array();
+ }
+
+ // --- Order state ---
+ $orderState = $this->order->getCurrentStateFull((int)$this->order->id_lang);
+
+ // --- Hotel / property ---
+ $objHotel = null;
+ $idHotel = HotelBookingDetail::getIdHotelByIdOrder((int)$this->order->id);
+ if ($idHotel) {
+ $objHotel = new HotelBranchInformation((int)$idHotel, (int)$this->order->id_lang);
+ if (!Validate::isLoadedObject($objHotel)) {
+ $objHotel = null;
+ }
+ }
+
+ $hotelAddress = '';
+ $paymentPolicy = '';
+ $cancellationPolicy = '';
+
+ if ($objHotel) {
+ $policies = is_array($objHotel->policies) ? '' : (string)$objHotel->policies;
+ if ($policies) {
+ $policyText = html_entity_decode($policies, ENT_QUOTES, 'UTF-8');
+ $policyText = preg_replace('/ /i', "\n", $policyText);
+ $policyText = strip_tags($policyText);
+ $policyText = preg_replace("/[\r\n]+/", "\n", $policyText);
+ $paymentPolicy = nl2br(trim($policyText));
+ }
+
+ $objBranchRefundRules = new HotelBranchRefundRules();
+ $refundRules = $objBranchRefundRules->getHotelRefundRules(
+ (int)$objHotel->id, 0, 1, (int)$this->order->id_lang, 1
+ );
+ if (is_array($refundRules) && !empty($refundRules)) {
+ $policyBlocks = array();
+ foreach ($refundRules as $rule) {
+ $ruleName = isset($rule['name']) ? trim(strip_tags($rule['name'])) : '';
+ $ruleDescription = isset($rule['description']) ? trim($rule['description']) : '';
+ if ($ruleName === '' && $ruleDescription === '') {
+ continue;
+ }
+ $block = $ruleName !== '' ? ''.Tools::safeOutput($ruleName).'' : '';
+ if ($ruleDescription !== '') {
+ $block .= ($block !== '' ? ': ' : '').$ruleDescription;
+ }
+ $policyBlocks[] = $block;
+ }
+ if (!empty($policyBlocks)) {
+ $cancellationPolicy = implode('
', $policyBlocks);
+ }
+ }
+
+ if ($idHotelAddress = $objHotel->getHotelIdAddress()) {
+ $objHotelAddress = new Address((int)$idHotelAddress);
+ if (Validate::isLoadedObject($objHotelAddress)) {
+ $objHotelAddress->firstname = $objHotel->hotel_name;
+ $hotelAddress = AddressFormat::generateAddress(
+ $objHotelAddress,
+ array('avoid' => array('lastname')),
+ ' ',
+ ' '
+ );
+ }
+ }
+ }
+
+ // --- Rooms, services, occupancy ---
+ $totalRooms = 0;
+ $totalRoomNights = 0;
+ $totalGuests = 0;
+ $serviceGroups = array();
+ $roomTypeRows = array();
+
+ foreach ($bookings as $booking) {
+ $nights = (int)HotelHelper::getNumberOfDays($booking['date_from'], $booking['date_to']);
+ if ($nights <= 0) {
+ $nights = 1;
+ }
+
+ $totalGuests += (int)$booking['adults'] + (int)$booking['children'];
+ $totalRoomNights += $nights;
+ $totalRooms++;
+
+ $dateFrom = ($booking['date_from'] && $booking['date_from'] !== '0000-00-00 00:00:00')
+ ? Tools::displayDate($booking['date_from'], null, false) : '--';
+ $dateTo = ($booking['date_to'] && $booking['date_to'] !== '0000-00-00 00:00:00')
+ ? Tools::displayDate($booking['date_to'], null, false) : '--';
+
+ // Services for this booking
+ $bookingServices = array();
+
+ $objBookingDemand = new HotelBookingDemands();
+ $extraDemands = $objBookingDemand->getRoomTypeBookingExtraDemands(
+ (int)$this->order->id, 0, 0, 0, 0, 0, 0, 0,
+ (int)$booking['id'], (int)$booking['id_order_detail']
+ );
+ if (is_array($extraDemands)) {
+ foreach ($extraDemands as $demand) {
+ $bookingServices[] = array('name' => $demand['name'], 'quantity' => 1);
+ }
+ }
+
+ // Auto-added services bundled with room price (for cost calculation only)
+ $objServiceProductOrderDetail = new ServiceProductOrderDetail();
+ $autoAddedWithRoomPriceTaxExcl = (float)$objServiceProductOrderDetail->getRoomTypeServiceProducts(
+ (int)$this->order->id, 0, 0,
+ isset($booking['id_product']) ? (int)$booking['id_product'] : 0,
+ isset($booking['date_from']) ? $booking['date_from'] : 0,
+ isset($booking['date_to']) ? $booking['date_to'] : 0,
+ isset($booking['id_room']) ? (int)$booking['id_room'] : 0,
+ 1, 0, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM
+ );
+
+ // Additional services chosen by guest
+ $additionalServices = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, null, 0, (int)$booking['id']
+ );
+ if (isset($additionalServices[(int)$booking['id']]['additional_services'])) {
+ foreach ($additionalServices[(int)$booking['id']]['additional_services'] as $service) {
+ $bookingServices[] = array('name' => $service['name'], 'quantity' => (int)$service['quantity']);
+ }
+ }
+
+ if (!empty($bookingServices)) {
+ $serviceGroups[] = array(
+ 'room_type_name' => isset($booking['room_type_name']) ? $booking['room_type_name'] : '',
+ 'check_in_date' => $dateFrom,
+ 'check_out_date' => $dateTo,
+ 'room_count' => $totalRooms,
+ 'services' => $bookingServices,
+ );
+ }
+
+ $roomTotalWithAutoServicesTaxExcl = (float)$booking['total_price_tax_excl'] + $autoAddedWithRoomPriceTaxExcl;
+
+ // Aggregate per room type + date range
+ $roomTypeRowKey = implode('|', array(
+ (int)$booking['id_order_detail'],
+ isset($booking['room_type_name']) ? $booking['room_type_name'] : '',
+ isset($booking['date_from']) ? $booking['date_from'] : '',
+ isset($booking['date_to']) ? $booking['date_to'] : '',
+ ));
+
+ if (!isset($roomTypeRows[$roomTypeRowKey])) {
+ $idOrderDetail = (int)$booking['id_order_detail'];
+ $detailTaxes = $idOrderDetail ? OrderDetail::getTaxListStatic($idOrderDetail) : null;
+ $orderDetailTaxLabel = self::l('No tax');
+ if ($detailTaxes) {
+ $taxTemp = array();
+ foreach ($detailTaxes as $tax) {
+ $objTax = new Tax($tax['id_tax']);
+ $taxTemp[] = sprintf(self::l('%1$s%2$s%%'), $objTax->rate + 0, ' ');
+ }
+ $orderDetailTaxLabel = implode(', ', $taxTemp);
+ }
+
+ $roomTypeRows[$roomTypeRowKey] = array(
+ 'room_type_name' => isset($booking['room_type_name']) ? $booking['room_type_name'] : '',
+ 'order_detail_tax_label' => $orderDetailTaxLabel,
+ 'rooms' => 0,
+ 'adults' => 0,
+ 'children' => 0,
+ 'nights' => $nights,
+ 'check_in_date' => $dateFrom,
+ 'check_out_date' => $dateTo,
+ 'unit_price_tax_excl' => 0,
+ 'total_price_tax_excl' => 0,
+ );
+ }
+
+ $roomTypeRows[$roomTypeRowKey]['rooms'] += 1;
+ $roomTypeRows[$roomTypeRowKey]['adults'] += (int)$booking['adults'];
+ $roomTypeRows[$roomTypeRowKey]['children'] += (int)$booking['children'];
+ $roomTypeRows[$roomTypeRowKey]['total_price_tax_excl'] += $roomTotalWithAutoServicesTaxExcl;
+ }
+
+ foreach ($roomTypeRows as &$roomTypeRow) {
+ $denominator = (int)$roomTypeRow['nights'] * (int)$roomTypeRow['rooms'];
+ if ($denominator > 0) {
+ $roomTypeRow['unit_price_tax_excl'] = Tools::ps_round(
+ $roomTypeRow['total_price_tax_excl'] / $denominator,
+ 6,
+ $this->order->round_mode
+ );
+ }
+ }
+ unset($roomTypeRow);
+
+ $guestAddress = '';
+ $guest = new Customer((int)$this->order->id_customer);
+
+ $addressId = (int)$this->order->id_address_invoice ?: (int)$this->order->id_address_delivery;
+ if ($addressId) {
+ $address = new Address($addressId);
+ if (Validate::isLoadedObject($address)) {
+ $guestAddress = AddressFormat::generateAddress($address, array(), ' ', ' ');
+ }
+ }
+
+ if ($idCustomerGuestDetail = OrderCustomerGuestDetail::isCustomerGuestBooking((int)$this->order->id)) {
+ $objGuest = new OrderCustomerGuestDetail((int)$idCustomerGuestDetail);
+ if (Validate::isLoadedObject($objGuest)) {
+ $guest = $objGuest;
+ }
+ }
+ // --- Totals ---
+ $objBookingDemand = new HotelBookingDemands();
+ $totalDemandsPriceTE = (float)$objBookingDemand->getRoomTypeBookingExtraDemands(
+ (int)$this->order->id, 0, 0, 0, 0, 1, 1, 0
+ );
+ $totalDemandsPriceTI = (float)$objBookingDemand->getRoomTypeBookingExtraDemands(
+ (int)$this->order->id, 0, 0, 0, 0, 1, 1, 1
+ );
+
+ $orderDetails = OrderDetail::getList((int)$this->order->id);
+ $idsOrderDetail = is_array($orderDetails)
+ ? array_unique(array_map('intval', array_column($orderDetails, 'id_order_detail')))
+ : array();
+
+ $footer = array(
+ 'room_price_tax_excl' => 0,
+ 'service_products_price_tax_excl' => 0,
+ 'additional_service_price_tax_excl' => 0,
+ 'total_convenience_fee_te' => 0,
+ );
+ $roomsCostTaxIncl = 0;
+ $serviceProductsCostTaxIncl = 0;
+ $additionalServicesCostTaxIncl = 0;
+ $convenienceFeeTaxIncl = 0;
+
+ if (!empty($idsOrderDetail)) {
+ $footer['room_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, true, null, null, null, $idsOrderDetail) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM, $idsOrderDetail);
+ $roomsCostTaxIncl = $this->order->getTotalProductsWithTaxes(false, true, null, null, null, $idsOrderDetail) + $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM, $idsOrderDetail);
+ $footer['service_products_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_STANDALONE, false, false, $idsOrderDetail) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_HOTEL_STANDALONE, false, false, $idsOrderDetail);
+ $serviceProductsCostTaxIncl = $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_STANDALONE, false, false, $idsOrderDetail) + $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_HOTEL_STANDALONE, false, false, $idsOrderDetail);
+ $footer['additional_service_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTE;
+ $additionalServicesCostTaxIncl = $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTI;
+ $footer['total_convenience_fee_te'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail);
+ $convenienceFeeTaxIncl = $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail);
+ }
+
+ $productDiscountsTaxIncl = (float)$this->order->total_discounts_tax_incl;
+ foreach ($this->order->getCartRules() as $cartRule) {
+ if (!empty($cartRule['free_shipping'])) {
+ $productDiscountsTaxIncl -= (float)$this->order->total_shipping_tax_incl;
+ }
+ }
+ if ($productDiscountsTaxIncl < 0) {
+ $productDiscountsTaxIncl = 0;
+ }
+
+ $footer['total_without_discount_te'] = $footer['room_price_tax_excl'] + $footer['total_convenience_fee_te'] + $footer['additional_service_price_tax_excl'] + $footer['service_products_price_tax_excl'];
+ $totalWithoutDiscountTaxIncl = $roomsCostTaxIncl + $serviceProductsCostTaxIncl + $additionalServicesCostTaxIncl + $convenienceFeeTaxIncl;
+ $footer['total_tax_without_discount'] = max(0, $totalWithoutDiscountTaxIncl - $footer['total_without_discount_te']);
+ $grandTotal = max(0.0, $totalWithoutDiscountTaxIncl - $productDiscountsTaxIncl);
+ $footer['product_discounts_tax_incl'] = $productDiscountsTaxIncl;
+ $footer['total_paid_tax_incl'] = $grandTotal;
+ $footer['amount_due'] = Tools::ps_round(
+ max(0, $grandTotal - (float)$this->order->getTotalPaid()),
+ _PS_PRICE_COMPUTE_PRECISION_,
+ $this->order->round_mode
+ );
+
+ $paymentMethods = array();
+ $payments = $this->order->getOrderPaymentDetail();
+ if (is_array($payments) && $payments) {
+ foreach ($payments as $paymentDetail) {
+ $method = isset($paymentDetail['payment_method']) ? trim($paymentDetail['payment_method']) : '';
+ if (!$method) {
+ $method = $this->order->payment;
+ }
+ $amount = isset($paymentDetail['real_paid_amount'])
+ ? (float)$paymentDetail['real_paid_amount']
+ : (float)$paymentDetail['amount'];
+ $idCurrency = isset($paymentDetail['id_currency'])
+ ? (int)$paymentDetail['id_currency']
+ : (int)$this->order->id_currency;
+ $paymentMethods[] = $method.': '.Tools::displayPrice($amount, $idCurrency);
+ }
+ }
+ $paymentMethod = $paymentMethods ? implode('
', $paymentMethods) : $this->order->payment;
+
+ $data = array(
+ 'order' => $this->order,
+ 'order_state' => $orderState,
+ 'booking_date' => Tools::displayDate($this->order->date_add, null, false),
+ 'issue_date' => Tools::displayDate(date('Y-m-d'), null, false),
+ 'hotel' => $objHotel,
+ 'hotel_address' => $hotelAddress,
+ 'guest' => $guest,
+ 'guest_address' => $guestAddress,
+ 'total_guests' => (int)$totalGuests,
+ 'total_rooms' => (int)$totalRooms,
+ 'total_room_nights' => (int)$totalRoomNights,
+ 'room_type_rows' => array_values($roomTypeRows),
+ 'service_groups' => $serviceGroups,
+ 'payment_method' => $paymentMethod,
+ 'footer' => $footer,
+ 'payment_policy' => $paymentPolicy,
+ 'cancellation_policy' => $cancellationPolicy,
+ );
+
+ if (Tools::getValue('debug')) {
+ die(json_encode($data));
+ }
+ $this->smarty->assign($data);
+
+ return $this->smarty->fetch($this->getTemplate('booking-voucher'));
+ }
+
+ /**
+ * @return string
+ */
+ public function getBulkFilename()
+ {
+ return self::l('BookingVouchers').'.pdf';
+ }
+
+ /**
+ * @return string
+ */
+ public function getFilename()
+ {
+ return sprintf(self::l('BOOKING VOUCHER - Refrence No. #%s.pdf'), $this->order->reference);
+ }
+}
diff --git a/classes/pdf/HTMLTemplateInvoice.php b/classes/pdf/HTMLTemplateInvoice.php
index c23fdd280..e5b36b518 100644
--- a/classes/pdf/HTMLTemplateInvoice.php
+++ b/classes/pdf/HTMLTemplateInvoice.php
@@ -474,8 +474,32 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
$cart_htl_data[$type_key]['date_diff'][$date_join]['num_rm'] = 1;
$fullDate = (isset($context->controller->show_full_date) && $context->controller->show_full_date && (date('Y-m-d', strtotime($data_v['date_from'])) == date('Y-m-d', strtotime($data_v['date_to'])))) ? true : false;
- $cart_htl_data[$type_key]['date_diff'][$date_join]['data_form'] = Tools::displayDate($data_v['date_from'], null, $fullDate);
- $cart_htl_data[$type_key]['date_diff'][$date_join]['data_to'] = Tools::displayDate($data_v['date_to'], null, $fullDate);
+ $display_date_from = $data_v['date_from'];
+ $display_date_to = $data_v['date_to'];
+ if ((int)$data_v['id_status'] === HotelBookingDetail::STATUS_CHECKED_OUT) {
+ if ($data_v['check_in']) {
+ $display_date_from = $data_v['check_in'];
+ }
+ if ($data_v['check_out']) {
+ $display_date_to = $data_v['check_out'];
+ }
+ } elseif ((int)$data_v['id_status'] === HotelBookingDetail::STATUS_CHECKED_IN) {
+ if ($data_v['check_in']) {
+ $display_date_from = $data_v['check_in'];
+ }
+ if ($data_v['check_out_time']) {
+ $display_date_to = date('Y-m-d', strtotime($data_v['date_to'])) . ' ' . date('H:i:s', strtotime($data_v['check_out_time']));
+ }
+ } else {
+ if ($data_v['check_in_time']) {
+ $display_date_from = date('Y-m-d', strtotime($data_v['date_from'])) . ' ' . date('H:i:s', strtotime($data_v['check_in_time']));
+ }
+ if ($data_v['check_out_time']) {
+ $display_date_to = date('Y-m-d', strtotime($data_v['date_to'])) . ' ' . date('H:i:s', strtotime($data_v['check_out_time']));
+ }
+ }
+ $cart_htl_data[$type_key]['date_diff'][$date_join]['data_form'] = Tools::displayDate($display_date_from, null, true);
+ $cart_htl_data[$type_key]['date_diff'][$date_join]['data_to'] = Tools::displayDate($display_date_to, null, true);
$cart_htl_data[$type_key]['date_diff'][$date_join]['num_days'] = $num_days;
$cart_htl_data[$type_key]['date_diff'][$date_join]['adults'] = $data_v['adults'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['children'] = $data_v['children'];
diff --git a/classes/pdf/PDF.php b/classes/pdf/PDF.php
index 833d5b17e..69985fa7f 100644
--- a/classes/pdf/PDF.php
+++ b/classes/pdf/PDF.php
@@ -41,6 +41,7 @@ class PDFCore
const TEMPLATE_ORDER_SLIP = 'OrderSlip';
const TEMPLATE_DELIVERY_SLIP = 'DeliverySlip';
const TEMPLATE_SUPPLY_ORDER_FORM = 'SupplyOrderForm';
+ const TEMPLATE_BOOKING_VOUCHER = 'BookingVoucher';
const TEMPLATE_PAYMENT_RECEIPT = 'PaymentReceipt';
/**
diff --git a/composer.json b/composer.json
index 74ff00cb0..db48f1054 100644
--- a/composer.json
+++ b/composer.json
@@ -1,22 +1,52 @@
{
- "require": {
- "php": ">=5.4 <8.0",
- "ext-simplexml": "*",
- "ext-curl": "*",
- "ext-gd": "*",
- "ext-zip": "*",
- "ext-soap": "*"
- },
- "name": "webkul/qloapps",
+ "name": "qloapps/qloapps",
"description": "QloApps is an Open-source and Free hotel reservation system and booking engine. With the help of QloApps, you can launch your hotel booking website without any cost and take & manage online bookings.",
"type": "project",
+ "homepage": "https://qloapps.com",
"license": "OSL-3.0",
+ "keywords": [
+ "qloapps",
+ "hospitality",
+ "booking-engine",
+ "hotel-booking-website",
+ "hotel-management-system",
+ "hotel-reservation-system",
+ "property-management-system",
+ "cms"
+ ],
"authors": [
{
- "name": "webkul",
- "email": "support@qloapps.com"
+ "name": "QloApps",
+ "email": "support@qloapps.com",
+ "homepage": "https://qloapps.com"
+ },
+ {
+ "name": "QloApps Community",
+ "homepage": "https://github.com/Qloapps/QloApps/graphs/contributors"
}
],
- "minimum-stability": "dev",
- "prefer-stable": true
+ "support": {
+ "docs": "https://qloapps.com/docs/",
+ "email": "support@qloapps.com",
+ "forum": "https://forums.qloapps.com/",
+ "source": "https://github.com/Qloapps/QloApps"
+ },
+ "require": {
+ "php": ">8.0 <8.5",
+ "ext-curl": "*",
+ "ext-dom": "*",
+ "ext-gd": "*",
+ "ext-mcrypt": "*",
+ "ext-openssl": "*",
+ "ext-pdo_mysql": "*",
+ "ext-phar": "*",
+ "ext-simplexml": "*",
+ "ext-soap": "*",
+ "ext-zip": "*"
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": true,
+ "config": {
+ "sort-packages": true
+ }
}
\ No newline at end of file
diff --git a/controllers/admin/AdminAccessController.php b/controllers/admin/AdminAccessController.php
index 74ef79b09..0d588c240 100644
--- a/controllers/admin/AdminAccessController.php
+++ b/controllers/admin/AdminAccessController.php
@@ -56,7 +56,7 @@ class AdminAccessControllerCore extends AdminController
{
$current_profile = (int)$this->getCurrentProfileId();
$profiles = Profile::getProfiles($this->context->language->id);
- $tabs = Tab::getTabs($this->context->language->id);
+ $tabs = Tab::getTabs($this->context->language->id, null, true);
$accesses = array();
foreach ($profiles as $profile) {
$accesses[$profile['id_profile']] = Profile::getProfileAccesses($profile['id_profile']);
@@ -214,7 +214,7 @@ class AdminAccessControllerCore extends AdminController
if (Tools::isSubmit('submitAddAccess')) {
$perm = Tools::getValue('perm');
- if (!in_array($perm, array('view', 'add', 'edit', 'delete', 'all'))) {
+ if (!in_array($perm, array('view', 'add', 'edit', 'delete', 'all', 'kpi'))) {
throw new PrestaShopException('permission does not exist');
}
diff --git a/controllers/admin/AdminCartsController.php b/controllers/admin/AdminCartsController.php
index f76331422..b72199d67 100644
--- a/controllers/admin/AdminCartsController.php
+++ b/controllers/admin/AdminCartsController.php
@@ -181,69 +181,85 @@ class AdminCartsControllerCore extends AdminController
public function renderKpis()
{
- $time = time();
- $kpis = array();
+ $objCart = new Cart(Tools::getValue('id_cart'));
+ if (Validate::isLoadedObject($objCart)) {
+ $currency = new Currency($objCart->id_currency);
+ $summary = $objCart->getSummaryDetails();
+ $tax_calculation_method = Group::getPriceDisplayMethod(Group::getCurrent()->id);
+ $total_price = ($tax_calculation_method == PS_TAX_EXC)
+ ? $summary['total_price_without_tax']
+ : $summary['total_price'];
- $daysForConversionRate = Configuration::get('PS_KPI_CONVERSION_RATE_NB_DAYS');
-
- $helper = new HelperKpi();
- $helper->id = 'box-conversion-rate';
- $helper->icon = 'icon-sort-by-attributes-alt';
- //$helper->chart = true;
- $helper->color = 'color1';
- $helper->title = $this->l('Conversion Rate', null, null, false);
- if ($daysForConversionRate == 1) {
- $helper->subtitle = $daysForConversionRate.' '.$this->l('day', null, null, false);
+ $helper = new HelperKpi();
+ $helper->id = 'box-kpi-cart';
+ $helper->icon = 'icon-shopping-cart';
+ $helper->color = 'color1';
+ $helper->title = $this->l('Total Cart', null, null, false);
+ $helper->subtitle = sprintf($this->l('Cart #%06d', null, null, false), $objCart->id);
+ $helper->value = Tools::displayPrice($total_price, $currency);
+ $this->kpis[] = $helper;
} else {
- $helper->subtitle = $daysForConversionRate.' '.$this->l('days', null, null, false);
- }
- if (ConfigurationKPI::get('CONVERSION_RATE_CHART') !== false) {
- $helper->data = ConfigurationKPI::get('CONVERSION_RATE_CHART');
- }
- $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=conversion_rate';
- $this->kpis[] = $helper;
+ $daysForConversionRate = Configuration::get('PS_KPI_CONVERSION_RATE_NB_DAYS');
- $helper = new HelperKpi();
- $helper->id = 'box-carts';
- $helper->icon = 'icon-shopping-cart';
- $helper->color = 'color2';
- $helper->title = $this->l('Abandoned Carts', null, null, false);
- $date_from = date(Context::getContext()->language->date_format_lite, strtotime('-2 day'));
- $date_to = date(Context::getContext()->language->date_format_lite, strtotime('-1 day'));
- $helper->subtitle = sprintf($this->l('From %s to %s', null, null, false), $date_from, $date_to);
- $helper->href = $this->context->link->getAdminLink('AdminCarts').'&action=filterOnlyAbandonedCarts&date_from='.date('Y-m-d', strtotime('-2 day')).'&date_to='.date('Y-m-d', strtotime('-1 day'));
- $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=abandoned_cart';
- $this->kpis[] = $helper;
+ $helper = new HelperKpi();
+ $helper->id = 'box-conversion-rate';
+ $helper->icon = 'icon-sort-by-attributes-alt';
+ //$helper->chart = true;
+ $helper->color = 'color1';
+ $helper->title = $this->l('Conversion Rate', null, null, false);
+ if ($daysForConversionRate == 1) {
+ $helper->subtitle = $daysForConversionRate.' '.$this->l('day', null, null, false);
+ } else {
+ $helper->subtitle = $daysForConversionRate.' '.$this->l('days', null, null, false);
+ }
+ if (ConfigurationKPI::get('CONVERSION_RATE_CHART') !== false) {
+ $helper->data = ConfigurationKPI::get('CONVERSION_RATE_CHART');
+ }
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=conversion_rate';
+ $this->kpis[] = $helper;
- $daysForAvgOrderVal = Configuration::get('PS_ORDER_KPI_AVG_ORDER_VALUE_NB_DAYS');
- $helper = new HelperKpi();
- $helper->id = 'box-average-order';
- $helper->icon = 'icon-money';
- $helper->color = 'color3';
- $helper->title = $this->l('Average Order Value', null, null, false);
- if ($daysForAvgOrderVal == 1) {
- $helper->subtitle = $daysForAvgOrderVal.' '.$this->l('day', null, null, false);
- } else {
- $helper->subtitle = $daysForAvgOrderVal.' '.$this->l('days', null, null, false);
+ $helper = new HelperKpi();
+ $helper->id = 'box-carts';
+ $helper->icon = 'icon-shopping-cart';
+ $helper->color = 'color2';
+ $helper->title = $this->l('Abandoned Carts', null, null, false);
+ $date_from = date(Context::getContext()->language->date_format_lite, strtotime('-2 day'));
+ $date_to = date(Context::getContext()->language->date_format_lite, strtotime('-1 day'));
+ $helper->subtitle = sprintf($this->l('From %s to %s', null, null, false), $date_from, $date_to);
+ $helper->href = $this->context->link->getAdminLink('AdminCarts').'&action=filterOnlyAbandonedCarts&date_from='.date('Y-m-d', strtotime('-2 day')).'&date_to='.date('Y-m-d', strtotime('-1 day'));
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=abandoned_cart';
+ $this->kpis[] = $helper;
+
+ $daysForAvgOrderVal = Configuration::get('PS_ORDER_KPI_AVG_ORDER_VALUE_NB_DAYS');
+ $helper = new HelperKpi();
+ $helper->id = 'box-average-order';
+ $helper->icon = 'icon-money';
+ $helper->color = 'color3';
+ $helper->title = $this->l('Average Order Value', null, null, false);
+ if ($daysForAvgOrderVal == 1) {
+ $helper->subtitle = $daysForAvgOrderVal.' '.$this->l('day', null, null, false);
+ } else {
+ $helper->subtitle = $daysForAvgOrderVal.' '.$this->l('days', null, null, false);
+ }
+
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=average_order_value';
+ $this->kpis[] = $helper;
+
+ $daysForProfitPerVisitor = Configuration::get('PS_ORDER_KPI_PER_VISITOR_PROFIT_NB_DAYS');
+ $helper = new HelperKpi();
+ $helper->id = 'box-net-profit-visitor';
+ $helper->icon = 'icon-user';
+ $helper->color = 'color4';
+ $helper->title = $this->l('Net Profit per Visitor', null, null, false);
+ if ($daysForProfitPerVisitor == 1) {
+ $helper->subtitle = $daysForProfitPerVisitor.' '.$this->l('day', null, null, false);
+ } else {
+ $helper->subtitle = $daysForProfitPerVisitor.' '.$this->l('days', null, null, false);
+ }
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=netprofit_visit';
+ $this->kpis[] = $helper;
}
- $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=average_order_value';
- $this->kpis[] = $helper;
-
- $daysForProfitPerVisitor = Configuration::get('PS_ORDER_KPI_PER_VISITOR_PROFIT_NB_DAYS');
- $helper = new HelperKpi();
- $helper->id = 'box-net-profit-visitor';
- $helper->icon = 'icon-user';
- $helper->color = 'color4';
- $helper->title = $this->l('Net Profit per Visitor', null, null, false);
- if ($daysForProfitPerVisitor == 1) {
- $helper->subtitle = $daysForProfitPerVisitor.' '.$this->l('day', null, null, false);
- } else {
- $helper->subtitle = $daysForProfitPerVisitor.' '.$this->l('days', null, null, false);
- }
- $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=netprofit_visit';
- $this->kpis[] = $helper;
-
return parent::renderKpis();
}
@@ -254,6 +270,9 @@ class AdminCartsControllerCore extends AdminController
if (!($cart = $this->loadObject(true))) {
return;
}
+ if ($this->tabAccess['kpi'] === 1) {
+ $this->content .= $this->renderKpis();
+ }
$customer = new Customer($cart->id_customer);
$currency = new Currency($cart->id_currency);
$this->context->cart = $cart;
@@ -340,16 +359,6 @@ class AdminCartsControllerCore extends AdminController
$cartHtlData = array();
}
- $helper = new HelperKpi();
- $helper->id = 'box-kpi-cart';
- $helper->icon = 'icon-shopping-cart';
- $helper->color = 'color1';
- $helper->title = $this->l('Total Cart', null, null, false);
- $helper->subtitle = sprintf($this->l('Cart #%06d', null, null, false), $cart->id);
- $helper->value = Tools::displayPrice($total_price, $currency);
- $kpi = $helper->generate();
- //end
-
// get standalone products in cart
$objServiceProductCartDetail = new ServiceProductCartDetail();
$hotelProducts = $objServiceProductCartDetail->getServiceProductsInCart(
@@ -381,7 +390,6 @@ class AdminCartsControllerCore extends AdminController
'cart_htl_data' => $cartHtlData,//by webkul hotel rooms in order data
'standalone_products' => $standaloneProducts,
'hotel_products' => $hotelProducts,
- 'kpi' => $kpi,
'products' => $products,
'discounts' => $cart->getCartRules(),
'cart_orders' => $cartOrders,
@@ -1121,7 +1129,7 @@ class AdminCartsControllerCore extends AdminController
if ($bookingInfo['id'] == $idBookingData) {
$amtWithQty = $bookingInfo['amt_with_qty'];
$bookingInfo['amt_with_qty'] = Tools::displayPrice($amtWithQty);
- $bookingInfo['total_price'] = Tools::displayPrice($amtWithQty + $bookingInfo['demand_price']);
+ $bookingInfo['total_price'] = Tools::displayPrice($amtWithQty + $bookingInfo['demand_price'] + $bookingInfo['additional_service_price'] + $bookingInfo['additional_services_auto_add_price']);
$response = array(
'curr_booking_info' => $bookingInfo,
'cart_info' => $this->ajaxReturnVars(),
diff --git a/controllers/admin/AdminDashboardController.php b/controllers/admin/AdminDashboardController.php
index 1fc4a45ae..81ff78003 100644
--- a/controllers/admin/AdminDashboardController.php
+++ b/controllers/admin/AdminDashboardController.php
@@ -168,6 +168,10 @@ class AdminDashboardControllerCore extends AdminController
return parent::renderOptions();
}
+ if ($this->tabAccess['kpi'] === 1) {
+ $this->content .= $this->renderKpis();
+ }
+
// $translations = array(
// 'Calendar' => $this->l('Calendar', 'AdminStatsTab'),
// 'Day' => $this->l('Day', 'AdminStatsTab'),
diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php
index 5290c7625..7b7c58fc2 100644
--- a/controllers/admin/AdminOrdersController.php
+++ b/controllers/admin/AdminOrdersController.php
@@ -391,12 +391,15 @@ class AdminOrdersControllerCore extends AdminController
);
}
- $this->page_header_toolbar_btn['print'] = array(
- 'short' => $this->l('Print'),
- 'href' => 'javascript:window.print()',
- 'desc' => $this->l('Print order'),
- 'class' => 'icon-print',
- );
+ if (HotelBookingDetail::getIdHotelByIdOrder($order->id, false) && !$this->lite_display) {
+ $this->page_header_toolbar_btn['booking_voucher'] = array(
+ 'short' => $this->l('Booking Voucher'),
+ 'href' => $this->context->link->getAdminLink('AdminPdf').'&submitAction=generateBookingVoucherPDF&id_order='.$order->id,
+ 'desc' => $this->l('View booking voucher'),
+ 'class' => 'icon-file-text',
+ 'target' => true,
+ );
+ }
if ($this->tabAccess['edit'] === 1) {
if (((int) $order->isReturnable())
@@ -3215,8 +3218,9 @@ class AdminOrdersControllerCore extends AdminController
if (!Validate::isLoadedObject($order = new Order(Tools::getValue('id_order')))) {
return;
}
-
- $this->content .= $this->renderKpis();
+ if ($this->tabAccess['kpi'] === 1) {
+ $this->content .= $this->renderKpis();
+ }
$customer = new Customer($order->id_customer);
$carrier = new Carrier($order->id_carrier);
diff --git a/controllers/admin/AdminPdfController.php b/controllers/admin/AdminPdfController.php
index 2e534d75b..2b74dad25 100644
--- a/controllers/admin/AdminPdfController.php
+++ b/controllers/admin/AdminPdfController.php
@@ -64,6 +64,15 @@ class AdminPdfControllerCore extends AdminController
}
}
+ public function processGenerateBookingVoucherPDF()
+ {
+ if (Tools::isSubmit('id_order')) {
+ $this->generateBookingVoucherPDFByIdOrder(Tools::getValue('id_order'));
+ } else {
+ die(Tools::displayError('The order ID is missing.'));
+ }
+ }
+
public function processGenerateOrderSlipPDF()
{
$order_slip = new OrderSlip((int)Tools::getValue('id_order_slip'));
@@ -225,6 +234,23 @@ class AdminPdfControllerCore extends AdminController
$this->generatePDF($order_invoice, PDF::TEMPLATE_INVOICE);
}
+ public function generateBookingVoucherPDFByIdOrder($id_order)
+ {
+ $order = new Order((int)$id_order);
+ if (!Validate::isLoadedObject($order)) {
+ die(Tools::displayError('The order cannot be found within your database.'));
+ }
+
+ $objHotelBookingDetail = new HotelBookingDetail();
+ $bookingDetails = $objHotelBookingDetail->getBookingDataByOrderId((int)$order->id);
+ if (empty($bookingDetails)) {
+ die(Tools::displayError('No booking voucher is available for this order.'));
+ }
+
+ $pdf = new PDF($order, PDF::TEMPLATE_BOOKING_VOUCHER, Context::getContext()->smarty);
+ $pdf->render('I');
+ }
+
public function generatePDF($object, $template)
{
$pdf = new PDF($object, $template, Context::getContext()->smarty);
diff --git a/controllers/front/OrderConfirmationController.php b/controllers/front/OrderConfirmationController.php
index f83b1fd7e..f00addd43 100644
--- a/controllers/front/OrderConfirmationController.php
+++ b/controllers/front/OrderConfirmationController.php
@@ -201,8 +201,8 @@ class OrderConfirmationControllerCore extends FrontController
//// By webkul New way to calculate product prices with feature Prices
$cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_excl'] = $data_v['total_price_tax_excl']/$num_days;
$cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] = $data_v['total_price_tax_incl']/$num_days;
- $cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_incl'] = $data_v['total_price_tax_incl']*$var_quant;
- $cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_excl'] = $data_v['total_price_tax_excl']*$var_quant;
+ $cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_incl'] += $data_v['total_price_tax_incl'];
+ $cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_excl'] += $data_v['total_price_tax_excl'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['is_backorder'] = $data_v['is_back_order'];
if ($data_v['is_back_order']) {
$any_back_order = 1;
diff --git a/controllers/front/PdfBookingVoucherController.php b/controllers/front/PdfBookingVoucherController.php
new file mode 100644
index 000000000..0ba3302c9
--- /dev/null
+++ b/controllers/front/PdfBookingVoucherController.php
@@ -0,0 +1,70 @@
+context->customer->isLogged() && !Tools::getValue('secure_key')) {
+ Tools::redirect('index.php?controller=authentication&back=pdf-booking-voucher');
+ }
+
+ $idOrder = (int)Tools::getValue('id_order');
+ if (!Validate::isUnsignedId($idOrder)) {
+ die(Tools::displayError('The booking voucher was not found.'));
+ }
+
+ $order = new Order($idOrder);
+ if (!Validate::isLoadedObject($order)) {
+ die(Tools::displayError('The booking voucher was not found.'));
+ }
+
+ $secureKey = Tools::getValue('secure_key');
+ if ($secureKey) {
+ if ($order->secure_key !== $secureKey) {
+ die(Tools::displayError('The booking voucher was not found.'));
+ }
+ } elseif ($order->id_customer != (int)$this->context->customer->id) {
+ die(Tools::displayError('The booking voucher was not found.'));
+ }
+
+ $this->order = $order;
+ }
+
+ public function display()
+ {
+ $pdf = new PDF($this->order, PDF::TEMPLATE_BOOKING_VOUCHER, $this->context->smarty);
+ $pdf->render();
+ }
+}
diff --git a/install/data/db_structure.sql b/install/data/db_structure.sql
index d9e771c58..9520ec459 100644
--- a/install/data/db_structure.sql
+++ b/install/data/db_structure.sql
@@ -8,6 +8,7 @@ CREATE TABLE `PREFIX_access` (
`add` int(11) NOT NULL,
`edit` int(11) NOT NULL,
`delete` int(11) NOT NULL,
+ `kpi` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_profile`,`id_tab`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
diff --git a/mails/en/account.html b/mails/en/account.html
index c80631219..d5e047532 100644
--- a/mails/en/account.html
+++ b/mails/en/account.html
@@ -68,10 +68,10 @@
|
-
+
Hi {firstname} {lastname},
Thank you for creating a customer account at {shop_name}.
-
+
|
@@ -83,14 +83,14 @@
| |
-
+
Your {shop_name} login details
Here are your login details:
E-mail address: {email}
-
+
|
|
@@ -106,7 +106,7 @@
| |
-
+
Important Security Tips:
- Always keep your account details safe.
@@ -114,7 +114,7 @@
- Change your password regularly.
- Should you suspect someone is using your account illegally, please notify us immediately.
-
+
|
|
@@ -126,9 +126,9 @@
|
-
+
You can now place orders on our website: {shop_name}
-
+
|
diff --git a/mails/en/awaiting_payment.html b/mails/en/awaiting_payment.html
index c6bc613c6..d83fbe902 100644
--- a/mails/en/awaiting_payment.html
+++ b/mails/en/awaiting_payment.html
@@ -69,10 +69,10 @@
-
+
Hi {firstname} {lastname},
{order_header_line_html}
-
+
|
@@ -84,13 +84,13 @@
| |
-
+
Order {order_name} - Awaiting payment
Order reference: {order_name}
Payment method: {payment_method}
-
+
|
|
@@ -103,18 +103,18 @@
{extra_mail_content_html}
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/backoffice_order.html b/mails/en/backoffice_order.html
index 0b40f8b35..f779ea6ef 100644
--- a/mails/en/backoffice_order.html
+++ b/mails/en/backoffice_order.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,12 +83,12 @@
| |
-
+
A new order has been generated on your behalf.
Please go on {order_link} to finalize the payment.
-
+
|
|
diff --git a/mails/en/booking_extra_demands.tpl b/mails/en/booking_extra_demands.tpl
index b43ac4bed..fe38cdadd 100644
--- a/mails/en/booking_extra_demands.tpl
+++ b/mails/en/booking_extra_demands.tpl
@@ -23,22 +23,22 @@
{if $smarty.foreach.demandRow.first}
-
+
{$data_v['name']}
{$rm_v['data_form']|date_format:"%d-%m-%Y"} {l s='to'} {$rm_v['data_to']|date_format:"%d-%m-%Y"}
{l s='Room'} - {$roomCount}
-
+
|
{/if}
-
+
{$demand['name']}
-
+
|
-
+
{convertPrice price=$demand['total_price_tax_excl']}
-
+
|
{/foreach}
@@ -81,31 +81,31 @@
{if $smarty.foreach.serviceRow.first}
-
+
{$data_v['name']}
{$rm_v['data_form']|date_format:"%d-%m-%Y"} {l s='to'} {$rm_v['data_to']|date_format:"%d-%m-%Y"}
{l s='Room'} - {$roomCount}
-
+
|
{/if}
-
+
{$service['name']}
-
+
|
-
+
{if $service['allow_multiple_quantity']}
{$service['quantity']}
{else}
{l s='--'}
{/if}
-
+
|
-
+
{convertPrice price=$service['total_price_tax_excl']}
-
+
|
{/foreach}
diff --git a/mails/en/booking_extra_demands.txt b/mails/en/booking_extra_demands.txt
index 3139f8ce3..21f96098b 100644
--- a/mails/en/booking_extra_demands.txt
+++ b/mails/en/booking_extra_demands.txt
@@ -13,22 +13,22 @@
{foreach name=demandRow from=$roomDemand['extra_demands'] item=demand}
{if $smarty.foreach.demandRow.first}
-
+
{$data_v['name']}
{$rm_v['data_form']|date_format:"%d-%m-%Y"} {l s='to'} {$rm_v['data_to']|date_format:"%d-%m-%Y"}
{l s='Room'} - {$roomCount}
-
+
|
{/if}
-
+
{$demand['name']}
-
+
|
-
+
{convertPrice price=$demand['total_price_tax_excl']}
-
+
|
{/foreach}
diff --git a/mails/en/contact.html b/mails/en/contact.html
index 5c5aa9d53..210b11f5d 100644
--- a/mails/en/contact.html
+++ b/mails/en/contact.html
@@ -68,9 +68,9 @@
|
-
+
Message from a {shop_name} customer
-
+
|
@@ -82,11 +82,11 @@
| |
-
+
{contact_content_html}
-
+
|
|
diff --git a/mails/en/contact_form.html b/mails/en/contact_form.html
index 73a8a7143..2a6cc0301 100644
--- a/mails/en/contact_form.html
+++ b/mails/en/contact_form.html
@@ -69,9 +69,9 @@
|
-
+
Your message to {shop_name} Customer Service
-
+
|
@@ -83,7 +83,7 @@
| |
-
+
Your message has been sent successfully.
Message: {message}
@@ -91,7 +91,7 @@
Product: {product_name}
Attached file: {attached_file}
-
+
|
|
@@ -103,10 +103,10 @@
|
-
+
We will answer as soon as possible.
-
+
|
diff --git a/mails/en/credit_slip.html b/mails/en/credit_slip.html
index 6aee0c304..40928b0e2 100644
--- a/mails/en/credit_slip.html
+++ b/mails/en/credit_slip.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,12 +83,12 @@
| |
-
+
Order {order_name} - Credit slip created
We have generated a credit slip in your name for order with the reference {order_name}.
-
+
|
|
@@ -100,10 +100,10 @@
|
-
+
You can review this credit slip and download your invoice from the "My credit slips" section of your account by clicking "My account" on our website.
-
+
|
diff --git a/mails/en/credit_slip_voucher.html b/mails/en/credit_slip_voucher.html
index e864fd62b..6f5ba20a6 100644
--- a/mails/en/credit_slip_voucher.html
+++ b/mails/en/credit_slip_voucher.html
@@ -71,9 +71,9 @@
-
+
Hi {firstname} {lastname},
-
+
|
@@ -85,7 +85,7 @@
| |
-
+
VOUCHER GENERATED
@@ -95,7 +95,7 @@
Voucher Code: {voucher_code} for an amount of {voucher_amount}.
To use this voucher just copy and paste this code during payment process for your next order.
-
+
|
|
diff --git a/mails/en/download_product.html b/mails/en/download_product.html
index a9d6b6e9a..a42775e85 100644
--- a/mails/en/download_product.html
+++ b/mails/en/download_product.html
@@ -69,10 +69,10 @@
-
+
Hi {firstname} {lastname},
Thank you for your order with the reference {order_name} from {shop_name}
-
+
|
@@ -84,14 +84,14 @@
| |
-
+
Product(s) now available for download
You have {nbProducts} product(s) now available for download using the following link(s):
{virtualProducts}
-
+
|
|
@@ -103,18 +103,18 @@
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/employee_password.html b/mails/en/employee_password.html
index 7b1b059c9..d17759824 100644
--- a/mails/en/employee_password.html
+++ b/mails/en/employee_password.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,7 +83,7 @@
| |
-
+
Your {shop_name} login information
@@ -93,7 +93,7 @@
Password: {passwd}
E-mail address: {email}
-
+
|
|
diff --git a/mails/en/forward_msg.html b/mails/en/forward_msg.html
index 07728db09..f9d56a845 100644
--- a/mails/en/forward_msg.html
+++ b/mails/en/forward_msg.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,7 +83,7 @@
| |
-
+
Customer service - Forwarded discussion
@@ -91,7 +91,7 @@
Discussion history: {messages}
{employee} added "{comment}"
-
+
|
|
diff --git a/mails/en/guest_to_customer.html b/mails/en/guest_to_customer.html
index 0dc1e5c9a..fbed53b8a 100644
--- a/mails/en/guest_to_customer.html
+++ b/mails/en/guest_to_customer.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,7 +83,7 @@
| |
-
+
Your customer account creation
@@ -91,7 +91,7 @@
E-mail address: {email}
Password: {passwd}
-
+
|
|
@@ -103,19 +103,19 @@
|
-
+
Please be careful when sharing these login details with others.
-
+
|
|
-
+
You can access your customer account on our website: {shop_url}
-
+
|
diff --git a/mails/en/in_transit.html b/mails/en/in_transit.html
index 6c5318515..56b82dd3e 100644
--- a/mails/en/in_transit.html
+++ b/mails/en/in_transit.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,14 +83,14 @@
| |
-
+
Order {order_name} - In transit
Your order with the reference {order_name} is currently in transit.
You can track your package using the following link: {followup}
-
+
|
|
@@ -102,18 +102,18 @@
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/log_alert.html b/mails/en/log_alert.html
index 13766029f..66299ede6 100644
--- a/mails/en/log_alert.html
+++ b/mails/en/log_alert.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,13 +83,13 @@
| |
-
+
You have received a new log alert
Warning: you have received a new log alert in your Back Office.
You can check for it in the "Tools" > "Logs" section of your Back Office.
-
+
|
|
diff --git a/mails/en/order_canceled.html b/mails/en/order_canceled.html
index 5271ab209..52f2eb3f4 100644
--- a/mails/en/order_canceled.html
+++ b/mails/en/order_canceled.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,12 +83,12 @@
| |
-
+
Order canceled - {order_name}
Your order with the reference {order_name} has been canceled.
-
+
|
|
@@ -104,7 +104,7 @@
| |
-
+
Here are your order details:
@@ -112,7 +112,7 @@
Order reference: {order_name}
Order total: {total_paid}
-
+
{order_hotel_detail_html}
|
@@ -127,18 +127,18 @@
{extra_mail_content_html}
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/order_changed.html b/mails/en/order_changed.html
index c224bc3ff..4e700defb 100644
--- a/mails/en/order_changed.html
+++ b/mails/en/order_changed.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,12 +83,12 @@
| |
-
+
Order {order_name} - Order changed
Your order with the reference {order_name} from {hotel_hotel_name} has been changed by the merchant.
-
+
|
|
@@ -100,18 +100,18 @@
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/order_conf.html b/mails/en/order_conf.html
index 5e58397d2..dc29689fd 100755
--- a/mails/en/order_conf.html
+++ b/mails/en/order_conf.html
@@ -71,10 +71,10 @@
-
+
Hi {firstname} {lastname},
{order_header_line_html}
-
+
|
@@ -86,14 +86,14 @@
| |
-
+
Order details
Order: {order_name} Placed on {date}
Payment: {payment}
-
+
|
|
@@ -123,18 +123,18 @@
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/order_conf_admin.html b/mails/en/order_conf_admin.html
index 28729c428..a5117aa9e 100755
--- a/mails/en/order_conf_admin.html
+++ b/mails/en/order_conf_admin.html
@@ -70,10 +70,10 @@
-
+
Hi {firstname} {lastname},
{order_header_line_html}
-
+
|
@@ -85,14 +85,14 @@
| |
-
+
Customer details
Name: {customer_name}
Email: {customer_email}
-
+
|
|
@@ -108,14 +108,14 @@
| |
-
+
Order details
Order: {order_name} Placed on {date}
Payment: {payment}
-
+
|
|
diff --git a/mails/en/order_conf_cart_rules.tpl b/mails/en/order_conf_cart_rules.tpl
index 7a1a683b0..bf4468f07 100644
--- a/mails/en/order_conf_cart_rules.tpl
+++ b/mails/en/order_conf_cart_rules.tpl
@@ -5,9 +5,9 @@
|
-
+
{$cart_rule['voucher_name']}
-
+
|
|
@@ -18,9 +18,9 @@
|
-
+
{$cart_rule['voucher_reduction']}
-
+
|
|
diff --git a/mails/en/order_conf_product_list.tpl b/mails/en/order_conf_product_list.tpl
index 525e38b70..ba0127f33 100644
--- a/mails/en/order_conf_product_list.tpl
+++ b/mails/en/order_conf_product_list.tpl
@@ -5,9 +5,9 @@
| |
-
+
{$product['reference']}
-
+
|
|
@@ -18,9 +18,9 @@
| |
-
+
{$product['name']}
-
+
|
|
@@ -31,9 +31,9 @@
| |
-
+
{$product['unit_price']}
-
+
|
|
@@ -44,9 +44,9 @@
| |
-
+
{$product['quantity']}
-
+
|
|
@@ -57,9 +57,9 @@
| |
-
+
{$product['price']}
-
+
|
|
@@ -73,10 +73,10 @@
| |
-
+
{$product['name']}
{$customization['customization_text']}
-
+
|
|
@@ -87,9 +87,9 @@
| |
-
+
{$product['unit_price']}
-
+
|
|
@@ -100,9 +100,9 @@
| |
-
+
{$customization['customization_quantity']}
-
+
|
|
@@ -113,9 +113,9 @@
| |
-
+
{$customization['quantity']}
-
+
|
|
diff --git a/mails/en/order_customer_comment.html b/mails/en/order_customer_comment.html
index 6dd6fedcf..c9c18b7f1 100644
--- a/mails/en/order_customer_comment.html
+++ b/mails/en/order_customer_comment.html
@@ -68,9 +68,9 @@
|
-
+
Message from a customer
-
+
|
@@ -82,14 +82,14 @@
| |
-
+
You have received a new message regarding booking with the reference {order_name}.
Name: {firstname} {lastname}
E-mail: {email}
Customer message: {message}
-
+
|
|
diff --git a/mails/en/order_hotel_detail.tpl b/mails/en/order_hotel_detail.tpl
index 710025127..a6d98eb90 100644
--- a/mails/en/order_hotel_detail.tpl
+++ b/mails/en/order_hotel_detail.tpl
@@ -1,5 +1,5 @@
{if isset($list['hotel_name']) && $list['hotel_name']}
-
+
{l s='Hotel details'}:
@@ -9,5 +9,5 @@
{l s='Hotel Email'}: {$list['hotel_email']}
{l s='Total Rooms'}: {$list['num_rooms']}
-
+
{/if}
\ No newline at end of file
diff --git a/mails/en/order_merchant_comment.html b/mails/en/order_merchant_comment.html
index 4cbc9d7b8..e57e34375 100644
--- a/mails/en/order_merchant_comment.html
+++ b/mails/en/order_merchant_comment.html
@@ -68,9 +68,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -82,7 +82,7 @@
| |
-
+
Message from {shop_name}
@@ -90,7 +90,7 @@
You have received a new message from {shop_name} regarding booking with the reference {order_name}.
Message: {message}
-
+
|
|
diff --git a/mails/en/order_refund_completed_admin.html b/mails/en/order_refund_completed_admin.html
index 0c1baf06c..d1647d8fc 100755
--- a/mails/en/order_refund_completed_admin.html
+++ b/mails/en/order_refund_completed_admin.html
@@ -71,10 +71,10 @@
-
+
Hi {firstname} {lastname},
A request has been completed for the {refund_for_txt} cancellation.
-
+
|
@@ -87,7 +87,7 @@
| |
-
+
Order details
Order: {order_reference} Placed on {order_date}
@@ -96,7 +96,7 @@
Payment Mode: {payment_mode}
Transaction Id: {id_transaction}
-
+
|
|
@@ -119,12 +119,12 @@
| |
-
+
Customer details
Customer name: {customer_name}
Customer email: {customer_email}
-
+
|
|
diff --git a/mails/en/order_refund_completed_customer.html b/mails/en/order_refund_completed_customer.html
index 211a19f11..0cb997673 100755
--- a/mails/en/order_refund_completed_customer.html
+++ b/mails/en/order_refund_completed_customer.html
@@ -71,10 +71,10 @@
-
+
Hi {firstname} {lastname},
Your request for {refund_for_txt} cancellation has been completed.
-
+
|
@@ -86,7 +86,7 @@
| |
-
+
Order details
Order: {order_reference} Placed on {order_date}
@@ -95,7 +95,7 @@
Payment Mode: {payment_mode}
Transaction Id: {id_transaction}
-
+
|
|
@@ -117,10 +117,10 @@
|
-
+
You can review your booking cancelation requests from the "Booking Refund Requests" section of your customer account by clicking "My account".
-
+
|
diff --git a/mails/en/order_refund_denied_admin.html b/mails/en/order_refund_denied_admin.html
index 2a1ef1624..ddb75a8d2 100755
--- a/mails/en/order_refund_denied_admin.html
+++ b/mails/en/order_refund_denied_admin.html
@@ -71,10 +71,10 @@
-
+
Hi {firstname} {lastname},
A request has been denied for the {refund_for_txt} cancellation.
-
+
|
@@ -87,13 +87,13 @@
| |
-
+
Order details
Order: {order_reference} Placed on {order_date}
Refund Status: {status_name}
-
+
|
|
@@ -116,12 +116,12 @@
| |
-
+
Customer details
Customer name: {customer_name}
Customer email: {customer_email}
-
+
|
|
diff --git a/mails/en/order_refund_denied_customer.html b/mails/en/order_refund_denied_customer.html
index c997eb0a3..67ea54f76 100755
--- a/mails/en/order_refund_denied_customer.html
+++ b/mails/en/order_refund_denied_customer.html
@@ -71,10 +71,10 @@
-
+
Hi {firstname} {lastname},
Your request for {refund_for_txt} cancellation has been denied.
-
+
|
@@ -86,13 +86,13 @@
| |
-
+
Order details
Order: {order_reference} Placed on {order_date}
Refund Status: {status_name}
-
+
|
|
@@ -114,10 +114,10 @@
|
-
+
You can review your booking cancelation requests from the "Booking Refund Requests" section of your customer account by clicking "My account".
-
+
|
diff --git a/mails/en/order_refund_pending_admin.html b/mails/en/order_refund_pending_admin.html
index 36d245469..e85a274c7 100755
--- a/mails/en/order_refund_pending_admin.html
+++ b/mails/en/order_refund_pending_admin.html
@@ -71,10 +71,10 @@
-
+
Hi {firstname} {lastname},
A request has been generated for {refund_for_txt} cancellations.
-
+
|
@@ -87,14 +87,14 @@
| |
-
+
Order details
Order: {order_reference} Placed on {order_date}
Refund Status: {status_name}
Cancelation Reason: {cancelation_reason}
-
+
|
|
@@ -117,12 +117,12 @@
| |
-
+
Customer details
Customer name: {customer_name}
Customer email: {customer_email}
-
+
|
|
diff --git a/mails/en/order_refund_pending_customer.html b/mails/en/order_refund_pending_customer.html
index 2b439d093..6e885fa96 100755
--- a/mails/en/order_refund_pending_customer.html
+++ b/mails/en/order_refund_pending_customer.html
@@ -71,10 +71,10 @@
-
+
Hi {firstname} {lastname},
Your request for {refund_for_txt} cancellation has been submitted successfully.
-
+
|
@@ -86,13 +86,13 @@
| |
-
+
Order details
Order: {order_reference} Placed on {order_date}
Refund Status: {status_name}
-
+
|
|
@@ -114,10 +114,10 @@
|
-
+
You can review your booking cancelation requests from the "Booking Refund Requests" section of your customer account by clicking "My account".
-
+
|
diff --git a/mails/en/order_return_state.html b/mails/en/order_return_state.html
index fd3de585a..104104849 100644
--- a/mails/en/order_return_state.html
+++ b/mails/en/order_return_state.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,13 +83,13 @@
| |
-
+
Return #{id_order_return} - update
We have updated the progress on your return #{id_order_return}, the new status is: "{state_order_return}"
-
+
|
|
@@ -102,10 +102,10 @@
{extra_mail_content_html}
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
diff --git a/mails/en/overbooking.html b/mails/en/overbooking.html
index b58f70c8b..8ca343851 100755
--- a/mails/en/overbooking.html
+++ b/mails/en/overbooking.html
@@ -71,12 +71,12 @@
-
+
Hi {firstname} {lastname},
Thank you for booking with {hotel_hotel_name}!
Bookings in this order are Not Confirmed yet !!
We are sorry for your inconvenience. Please contact hotel to get final confirmation for your bookings.
-
+
|
@@ -88,14 +88,14 @@
| |
-
+
Order details
Order: {order_name} Placed on {date}
Payment: {payment}
Status: {order_status}
-
+
|
|
@@ -127,18 +127,18 @@
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our shop.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our shop.
-
+
|
diff --git a/mails/en/overbooking_admin.html b/mails/en/overbooking_admin.html
index a19795a02..c64acd1ec 100755
--- a/mails/en/overbooking_admin.html
+++ b/mails/en/overbooking_admin.html
@@ -70,12 +70,12 @@
-
+
Hi {firstname} {lastname},
New bookings are created on {hotel_hotel_name}!
Bookings in this order have Overbookings !!
This order is not confirmed yet. Please check the order details to resolve overbookings.
-
+
|
@@ -87,14 +87,14 @@
| |
-
+
Customer details
Name: {customer_name}
Email: {customer_email}
-
+
|
|
@@ -110,7 +110,7 @@
| |
-
+
Order details
@@ -118,7 +118,7 @@
Payment: {payment}
Status: {order_status}
-
+
|
|
diff --git a/mails/en/partial_payment_accepted.html b/mails/en/partial_payment_accepted.html
index 61b578477..953846164 100644
--- a/mails/en/partial_payment_accepted.html
+++ b/mails/en/partial_payment_accepted.html
@@ -69,10 +69,10 @@
-
+
Hi {firstname} {lastname},
{order_header_line_html}
-
+
|
@@ -84,7 +84,7 @@
| |
-
+
Order {order_name} - Payment processed
@@ -93,7 +93,7 @@
Total Booking Amount: {total_paid}
Partial Payment Amount: {advance_paid_amount}
Total Paid Amount: {total_paid_real}
-
+
|
|
@@ -106,18 +106,18 @@
{extra_mail_content_html}
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/password.html b/mails/en/password.html
index e6fd5726b..803a94c72 100644
--- a/mails/en/password.html
+++ b/mails/en/password.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,14 +83,14 @@
| |
-
+
Your new {shop_name} login details
E-mail address: {email}
Password: {passwd}
-
+
|
|
@@ -102,18 +102,18 @@
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/password_query.html b/mails/en/password_query.html
index 3a9071826..3825facc8 100644
--- a/mails/en/password_query.html
+++ b/mails/en/password_query.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,7 +83,7 @@
| |
-
+
Password reset request for {shop_name}
@@ -91,7 +91,7 @@
Please note that this will change your current password.
To confirm this action, please use the following link: {url}
-
+
|
|
diff --git a/mails/en/payment_accepted.html b/mails/en/payment_accepted.html
index 97d84f255..b99974481 100644
--- a/mails/en/payment_accepted.html
+++ b/mails/en/payment_accepted.html
@@ -69,10 +69,10 @@
-
+
Hi {firstname} {lastname},
{order_header_line_html}
-
+
|
@@ -84,12 +84,12 @@
| |
-
+
Order {order_name} - Payment processed
Your payment for order with the reference {order_name} was successfully processed.
-
+
|
|
@@ -102,18 +102,18 @@
{extra_mail_content_html}
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/payment_error.html b/mails/en/payment_error.html
index ba3a129d7..af3d28bb5 100644
--- a/mails/en/payment_error.html
+++ b/mails/en/payment_error.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,13 +83,13 @@
| |
-
+
Order {order_name} - Payment processing error
There is a problem with your payment for {shop_name} order with the reference {order_name}. Please contact us at your earliest convenience.
-
+
|
|
@@ -102,18 +102,18 @@
{extra_mail_content_html}
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/processing.html b/mails/en/processing.html
index de01bd0ab..cc1fabbe7 100644
--- a/mails/en/processing.html
+++ b/mails/en/processing.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,12 +83,12 @@
| |
-
+
Order {order_name} - Processing
We are currently processing your {shop_name} order with the reference {order_name}.
-
+
|
|
@@ -101,18 +101,18 @@
{extra_mail_content_html}
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/refund.html b/mails/en/refund.html
index 5004f8183..b0f59304a 100644
--- a/mails/en/refund.html
+++ b/mails/en/refund.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,12 +83,12 @@
| |
-
+
Order {order_name} - Refund processed
We have processed your {shop_name} refund for order with the reference {order_name}.
-
+
|
|
@@ -101,18 +101,18 @@
{extra_mail_content_html}
|
-
+
You can review your order and download your invoice from the "Order history" section of your customer account by clicking "My account" on our website.
-
+
|
|
-
+
If you have a guest account, you can follow your order via the "Guest Tracking" section on our website.
-
+
|
diff --git a/mails/en/reply_msg.html b/mails/en/reply_msg.html
index 7eafe00e4..de24a620d 100644
--- a/mails/en/reply_msg.html
+++ b/mails/en/reply_msg.html
@@ -80,7 +80,7 @@
| |
-
+
Message from {contact_name} Title: {subject}
diff --git a/mails/en/shipped.html b/mails/en/shipped.html
index f0e3c9a5e..815ce0a3b 100644
--- a/mails/en/shipped.html
+++ b/mails/en/shipped.html
@@ -69,10 +69,10 @@
-
+
Hi {firstname} {lastname},
Your order has been shipped
-
+
|
@@ -84,13 +84,13 @@
| |
-
+
Order {order_name} - Shipped
Your order with the reference {order_name} has been shipped.
Thank you for booking with {shop_name}!
-
+
|
|
diff --git a/mails/en/voucher.html b/mails/en/voucher.html
index 5be2a4031..471eebe48 100644
--- a/mails/en/voucher.html
+++ b/mails/en/voucher.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,14 +83,14 @@
| |
-
+
Order {order_name} - Voucher created
A voucher has been created in your name as a result of your order with the reference {order_name}.
Voucher code: {voucher_num} in the amount of {voucher_amount}
Simply copy/paste this code during the payment process for your next order.
-
+
|
|
diff --git a/mails/en/voucher_new.html b/mails/en/voucher_new.html
index 634666db7..6bc02205d 100644
--- a/mails/en/voucher_new.html
+++ b/mails/en/voucher_new.html
@@ -69,9 +69,9 @@
|
-
+
Hi {firstname} {lastname},
-
+
|
@@ -83,13 +83,13 @@
| |
-
+
This is to inform you about the creation of a voucher.
Here is the code of your voucher: {voucher_num}
Simply copy/paste this code during the payment process for your next order.
-
+
|
|
diff --git a/modules/bankwire/views/templates/mail/mail_template_html.tpl b/modules/bankwire/views/templates/mail/mail_template_html.tpl
index 7d1634d33..012591c35 100644
--- a/modules/bankwire/views/templates/mail/mail_template_html.tpl
+++ b/modules/bankwire/views/templates/mail/mail_template_html.tpl
@@ -25,7 +25,7 @@
| |
-
+
{l s='Here are the bank details for your transfer:' mod='bankwire' lang=$lang}
@@ -35,7 +35,7 @@
{l s='Account details:' mod='bankwire' lang=$lang} {$bankwire_details}
{l s='Bank address:' mod='bankwire' lang=$lang} {$bankwire_address}
-
+
|
|
diff --git a/modules/blocknewsletter/mails/en/newsletter_conf.html b/modules/blocknewsletter/mails/en/newsletter_conf.html
index cff837649..2c5f51f75 100644
--- a/modules/blocknewsletter/mails/en/newsletter_conf.html
+++ b/modules/blocknewsletter/mails/en/newsletter_conf.html
@@ -68,9 +68,9 @@
|
|
-
+
Hi,
-
+
|
@@ -82,13 +82,13 @@
| |
-
+
Thank you for subscribing to our newsletter! If you wish to unsubscribe, please click here.
-
+
|
|
diff --git a/modules/blocknewsletter/mails/en/newsletter_verif.html b/modules/blocknewsletter/mails/en/newsletter_verif.html
index 1c55f012e..9ec521952 100644
--- a/modules/blocknewsletter/mails/en/newsletter_verif.html
+++ b/modules/blocknewsletter/mails/en/newsletter_verif.html
@@ -68,9 +68,9 @@
|
-
+
Hi,
-
+
|
@@ -82,11 +82,11 @@
| |
-
+
Thank you for subscribing to our newsletter, please confirm your request by clicking here.
-
+
|
|
diff --git a/modules/blocknewsletter/mails/en/newsletter_voucher.html b/modules/blocknewsletter/mails/en/newsletter_voucher.html
index 457b8a35e..89cbaa5e7 100644
--- a/modules/blocknewsletter/mails/en/newsletter_voucher.html
+++ b/modules/blocknewsletter/mails/en/newsletter_voucher.html
@@ -69,9 +69,9 @@
|
-
+
Hi,
-
+
|
@@ -83,7 +83,7 @@
| |
-
+
Newsletter subscription
@@ -94,7 +94,7 @@
Please note that the voucher will be valid on your first order.
-
+
|
|
diff --git a/modules/cheque/views/templates/mail/mail_template_html.tpl b/modules/cheque/views/templates/mail/mail_template_html.tpl
index 8b33da90c..607e4fe81 100644
--- a/modules/cheque/views/templates/mail/mail_template_html.tpl
+++ b/modules/cheque/views/templates/mail/mail_template_html.tpl
@@ -25,7 +25,7 @@
| |
-
+
{l s='Here are the bank details for your check:' mod='cheque' lang=$lang}
@@ -34,7 +34,7 @@
{l s='Payable to the order of:' mod='cheque' lang=$lang} {$cheque_name}
{l s='Please mail your check to:' mod='cheque' lang=$lang} {$cheque_address_html}
-
+
|
|
diff --git a/modules/dashguestcycle/dashguestcycle.php b/modules/dashguestcycle/dashguestcycle.php
index d630c926a..6aae1cb46 100644
--- a/modules/dashguestcycle/dashguestcycle.php
+++ b/modules/dashguestcycle/dashguestcycle.php
@@ -46,7 +46,7 @@ class DashGuestCycle extends Module
public function install()
{
return (parent::install()
- && $this->registerHook('dashboardTop')
+ && $this->registerHook('actionAdminDashboardKPIListingModifier')
&& $this->registerHook('dashboardZoneTwo')
&& $this->registerHook('dashboardData')
&& $this->registerHook('actionAdminControllerSetMedia')
@@ -60,9 +60,120 @@ class DashGuestCycle extends Module
}
}
- public function hookDashboardTop()
+ public function hookActionAdminDashboardKPIListingModifier(array $params)
{
- return $this->display(__FILE__, 'dashboard-top.tpl');
+ $idHotel = (int)$this->context->cookie->stats_id_hotel;
+ $kpiValues = $this->getKpiValues($idHotel);
+
+ $kpisData = array(
+ array(
+ 'id' => 'box-dgc-arrivals',
+ 'color' => 'color1',
+ 'title' => $this->l('Arrivals'),
+ 'tooltip' => $this->l('The number of arrivals scheduled for today.'),
+ 'value' => $kpiValues['box-dgc-arrivals'],
+ ),
+ array(
+ 'id' => 'box-dgc-departures',
+ 'color' => 'color2',
+ 'title' => $this->l('Departures'),
+ 'tooltip' => $this->l('The number of departures scheduled for today.'),
+ 'value' => $kpiValues['box-dgc-departures'],
+ ),
+ array(
+ 'id' => 'box-dgc-new-bookings',
+ 'color' => 'color3',
+ 'title' => $this->l('New Bookings'),
+ 'tooltip' => $this->l('The number of new bookings created today so far.'),
+ 'value' => $kpiValues['box-dgc-new-bookings'],
+ ),
+ array(
+ 'id' => 'box-dgc-occupied',
+ 'color' => 'color4',
+ 'title' => $this->l('Occupied Rooms'),
+ 'tooltip' => $this->l('The count of rooms currently occupied by guests.'),
+ 'value' => $kpiValues['box-dgc-occupied'],
+ ),
+ array(
+ 'id' => 'box-dgc-messages',
+ 'color' => 'color5',
+ 'title' => $this->l('Guest Messages'),
+ 'tooltip' => $this->l('The number of new messages received from guests today.'),
+ 'value' => $kpiValues['box-dgc-messages'],
+ ),
+ array(
+ 'id' => 'box-dgc-cancelled',
+ 'color' => 'color6',
+ 'title' => $this->l('Cancelled Bookings'),
+ 'tooltip' => $this->l('The number of bookings cancelled today so far.'),
+ 'value' => $kpiValues['box-dgc-cancelled'],
+ ),
+ array(
+ 'id' => 'box-dgc-guests',
+ 'color' => 'color1',
+ 'title' => $this->l('Guests (Adults/Children)'),
+ 'tooltip' => $this->l('The number of adults and children scheduled to stay today.'),
+ 'value' => $kpiValues['box-dgc-guests'],
+ ),
+ );
+
+ foreach ($kpisData as $data) {
+ $helper = new HelperKpi();
+ $helper->id = $data['id'];
+ $helper->color = $data['color'];
+ $helper->title = $data['title'];
+ $helper->tooltip = $data['tooltip'];
+ $helper->value = $data['value'];
+ $params['kpis'][] = $helper;
+ }
+ }
+
+ private function getKpiValues($idHotel)
+ {
+ $dateToday = date('Y-m-d');
+
+ if (Configuration::get('PS_DASHBOARD_SIMULATION')) {
+ $totalArrivals = rand(100, 1000);
+ $arrived = rand(0, $totalArrivals);
+ $totalDepartures = rand(100, 1000);
+ $departed = rand(0, $totalDepartures);
+ $newBookings = rand(10, 500);
+ $occupied = rand(10, 500);
+ $newMessages = rand(0, 20);
+ $cancelledBookings = rand(0, 20);
+ $totalAdults = rand(100, 1000);
+ $children = rand(0, $totalAdults);
+ } else {
+ $arrivalsData = AdminStatsController::getArrivalsByDate($dateToday, $idHotel);
+ $departuresData = AdminStatsController::getDeparturesByDate($dateToday, $idHotel);
+ $guestsData = AdminStatsController::getGuestsByDate($dateToday, $idHotel);
+
+ $arrived = (int) $arrivalsData['arrived'];
+ $totalArrivals = (int) $arrivalsData['total_arrivals'];
+ $departed = (int) $departuresData['departed'];
+ $totalDepartures = (int) $departuresData['total_departures'];
+ $newBookings = count(AdminStatsController::getNewBookingsInfoByDate($dateToday, $idHotel));
+ $occupied = (int) AdminStatsController::getDistinctRoomBookingsCount(
+ date('Y-m-d', strtotime('-1 day')),
+ $dateToday,
+ $idHotel,
+ HotelBookingDetail::STATUS_CHECKED_IN
+ );
+ $newMessages = (int) CustomerMessage::getMessagesByDate($dateToday);
+ $cancelledBookings = (int) AdminStatsController::getCancelledBookingsByDate($dateToday, $idHotel);
+ $totalAdults = (int) $guestsData['adults'];
+ $children = (int) $guestsData['children'];
+ }
+
+ return array(
+ 'box-dgc-arrivals' => sprintf('%02d', $arrived).'/'.sprintf('%02d', $totalArrivals),
+ 'box-dgc-departures' => sprintf('%02d', $departed).'/'.sprintf('%02d', $totalDepartures),
+ 'box-dgc-new-bookings' => sprintf('%02d', $newBookings),
+ 'box-dgc-occupied' => sprintf('%02d', $occupied),
+ 'box-dgc-messages' => sprintf('%02d', $newMessages),
+ 'box-dgc-cancelled' => sprintf('%02d', $cancelledBookings),
+ 'box-dgc-guests' => sprintf('%02d', $totalAdults).'/'.sprintf('%02d', $children),
+ );
}
public function hookDashboardZoneTwo()
@@ -76,37 +187,10 @@ class DashGuestCycle extends Module
$dataTable = array();
$dateToday = date('Y-m-d');
- if (Configuration::get('PS_DASHBOARD_SIMULATION')) {
- $dataValue['dgc_total_arrivals'] = sprintf('%02d', rand(100, 1000));
- $dataValue['dgc_arrived'] = sprintf('%02d', rand(0, $dataValue['dgc_total_arrivals']));
- $dataValue['dgc_total_departures'] = sprintf('%02d', rand(100, 1000));
- $dataValue['dgc_departed'] = sprintf('%02d', rand(0, $dataValue['dgc_total_departures']));
- $dataValue['dgc_new_bookings'] = sprintf('%02d', rand(10, 500));
- $dataValue['dgc_occupied'] = sprintf('%02d', rand(10, 500));
- $dataValue['dgc_new_messages'] = sprintf('%02d', rand(0, 20));
- $dataValue['dgc_cancelled_bookings'] = sprintf('%02d', rand(0, 20));
- $dataValue['dgc_guests_adults'] = sprintf('%02d', rand(100, 1000));
- $dataValue['dgc_guests_children'] = sprintf('%02d', rand(0, $dataValue['dgc_guests_adults']));
- } else {
- // set badges data
- $arrivalsData = AdminStatsController::getArrivalsByDate($dateToday, $params['id_hotel']);
- $departuresData = AdminStatsController::getDeparturesByDate($dateToday, $params['id_hotel']);
- $guestsData = AdminStatsController::getGuestsByDate($dateToday, $params['id_hotel']);
- $dataValue['dgc_arrived'] = sprintf('%02d', $arrivalsData['arrived']);
- $dataValue['dgc_total_arrivals'] = sprintf('%02d', $arrivalsData['total_arrivals']);
- $dataValue['dgc_departed'] = sprintf('%02d', $departuresData['departed']);
- $dataValue['dgc_total_departures'] = sprintf('%02d', $departuresData['total_departures']);
- $dataValue['dgc_new_bookings'] = sprintf('%02d', count(AdminStatsController::getNewBookingsInfoByDate($dateToday, $params['id_hotel'])));
- $dataValue['dgc_occupied'] = sprintf('%02d', AdminStatsController::getDistinctRoomBookingsCount(
- date('Y-m-d', strtotime('-1 day')),
- $dateToday,
- $params['id_hotel'],
- HotelBookingDetail::STATUS_CHECKED_IN
- ));
- $dataValue['dgc_new_messages'] = sprintf('%02d', CustomerMessage::getMessagesByDate($dateToday));
- $dataValue['dgc_cancelled_bookings'] = sprintf('%02d', AdminStatsController::getCancelledBookingsByDate($dateToday, $params['id_hotel']));
- $dataValue['dgc_guests_adults'] = sprintf('%02d', $guestsData['adults']);
- $dataValue['dgc_guests_children'] = sprintf('%02d', $guestsData['children']);
+
+ // KPI box values — updated on every AJAX refresh (demo toggle, date change)
+ foreach ($this->getKpiValues((int) $params['id_hotel']) as $boxId => $value) {
+ $dataValue[$boxId . ' .value'] = $value;
}
// set tables data
diff --git a/modules/dashguestcycle/views/css/dashguestcycle.css b/modules/dashguestcycle/views/css/dashguestcycle.css
index 0f8e7ca14..7fd58544d 100644
--- a/modules/dashguestcycle/views/css/dashguestcycle.css
+++ b/modules/dashguestcycle/views/css/dashguestcycle.css
@@ -20,76 +20,6 @@
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
-#dashguestcycle {
- padding-bottom: 5px;
-}
-
-#dashguestcycle .badges-wrapper {
- white-space: nowrap;
- overflow: auto;
- margin: -5px;
- margin-bottom: 0px;
- padding-bottom: 10px;
- font-size: 0;
-}
-
-#dashguestcycle .badge-wrapper {
- display: inline-block;
- width: 14.28%;
- min-width: 145px;
- padding: 5px;
-}
-
-#dashguestcycle .badge-item {
- position: relative;
- min-width: 135px;
- height: 80px;
- border-radius: 10px;
- background: #FFFFFF;
- box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.15);
-}
-
-#dashguestcycle .badge-strip {
- position: absolute;
- width: 10px;
- height: 100%;
- border-top-left-radius: 10px;
- border-bottom-left-radius: 10px;
-}
-
-#dashguestcycle .badge-content-wrapper {
- height: 100%;
-}
-
-#dashguestcycle .badge-content-wrapper p {
- color: #00AFF0;
- margin-bottom: 0;
-}
-
-#dashguestcycle .title-wrapper, #dashguestcycle .value-wrapper {
- display: table;
- width: 100%;
- height: 50%;
- padding: 0 10px;
-}
-
-#dashguestcycle .title-wrapper p {
- display: table-cell;
- vertical-align: middle;
- font-weight: normal;
- font-size: 13px;
- line-height: 15px;
- white-space: normal;
-}
-
-#dashguestcycle .value-wrapper p {
- display: table-cell;
- vertical-align: top;
- font-weight: bold;
- font-size: 24px;
- line-height: 30px;
-}
-
#dashguestcycle .tab-content {
max-height: 300px;
overflow-y: auto;
@@ -97,4 +27,107 @@
#dashguestcycle table tbody>tr>td {
padding: 8px 7px;
+}
+
+/* ── KPI row container: strip panel chrome ──────────────────────────────── */
+.kpi-container {
+ background: transparent !important;
+ border: none !important;
+ box-shadow: none !important;
+ padding: 0 0 15px !important;
+}
+
+.kpi-container .kpis-wrap {
+ flex-wrap: nowrap !important;
+ overflow-x: auto;
+ gap: 8px;
+ margin: 0 !important;
+}
+
+.kpi-container .kpis-wrap .kpi-wrap {
+ width: 14.28% !important;
+ min-width: 110px;
+ padding: 0 !important;
+ margin-bottom: 0 !important;
+}
+
+.kpi-container .box-stats {
+ height: 80px !important;
+ background: #fff !important;
+ border-radius: 10px !important;
+ overflow: hidden;
+ font-size: inherit !important;
+}
+
+.kpi-container .box-stats .kpi-content {
+ border: none !important;
+ border-left: 10px solid !important;
+ border-radius: 0 !important;
+ height: 100% !important;
+ padding: 8px 12px !important;
+ align-items: center !important;
+ gap: 0 !important;
+}
+
+.kpi-container .box-stats .kpi-content .kpi-data {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 100%;
+ gap: 4px;
+}
+
+.kpi-container .box-stats .kpi-content .title-subtitle {
+ justify-content: center !important;
+ width: 100%;
+}
+
+.kpi-container .box-stats .kpi-content .title-subtitle .title-container .title {
+ font-size: 13px !important;
+ font-weight: normal !important;
+ color: #555 !important;
+ display: block;
+ text-align: center;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.kpi-container .box-stats .kpi-content .value-container {
+ width: 100%;
+ text-align: center;
+}
+
+.kpi-container .box-stats .kpi-content .value-container .value {
+ font-size: 24px !important;
+ font-weight: bold !important;
+ min-height: auto !important;
+ display: block;
+ text-align: center;
+}
+
+.kpi-container .box-stats .kpi-content .arrow {
+ display: none !important;
+}
+
+.kpi-container .box-stats.color1 .kpi-content { border-left-color: #266FFE !important; }
+.kpi-container .box-stats.color1 .value { color: #266FFE !important; }
+
+.kpi-container .box-stats.color2 .kpi-content { border-left-color: #72C3F0 !important; }
+.kpi-container .box-stats.color2 .value { color: #72C3F0 !important; }
+
+.kpi-container .box-stats.color3 .kpi-content { border-left-color: #56CE56 !important; }
+.kpi-container .box-stats.color3 .value { color: #56CE56 !important; }
+
+.kpi-container .box-stats.color4 .kpi-content { border-left-color: #FFC148 !important; }
+.kpi-container .box-stats.color4 .value { color: #FFC148 !important; }
+
+.kpi-container .box-stats.color5 .kpi-content { border-left-color: #A569DF !important; }
+.kpi-container .box-stats.color5 .value { color: #A569DF !important; }
+
+.kpi-container .box-stats.color6 .kpi-content { border-left-color: #FF4036 !important; }
+.kpi-container .box-stats.color6 .value { color: #FF4036 !important; }
+
+.kpi-container .actions-wrap {
+ display: none !important;
}
\ No newline at end of file
diff --git a/modules/dashguestcycle/views/templates/hook/dashboard-top.tpl b/modules/dashguestcycle/views/templates/hook/dashboard-top.tpl
deleted file mode 100644
index 1d904e3b9..000000000
--- a/modules/dashguestcycle/views/templates/hook/dashboard-top.tpl
+++ /dev/null
@@ -1,143 +0,0 @@
-{**
-* NOTICE OF LICENSE
-*
-* This source file is subject to the Open Software License version 3.0
-* that is bundled with this package in the file LICENSE.md
-* It is also available through the world-wide-web at this URL:
-* https://opensource.org/license/osl-3-0-php
-* If you did not receive a copy of the license and are unable to
-* obtain it through the world-wide-web, please send an email
-* to support@qloapps.com so we can send you a copy immediately.
-*
-* DISCLAIMER
-*
-* Do not edit or add to this file if you wish to upgrade this module to a newer
-* versions in the future. If you wish to customize this module for your needs
-* please refer to https://store.webkul.com/customisation-guidelines for more information.
-*
-* @author Webkul IN
-* @copyright Since 2010 Webkul
-* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
-*}
-
-
diff --git a/modules/hotelreservationsystem/classes/HotelBranchInformation.php b/modules/hotelreservationsystem/classes/HotelBranchInformation.php
index b4fb0ada8..0797c7035 100644
--- a/modules/hotelreservationsystem/classes/HotelBranchInformation.php
+++ b/modules/hotelreservationsystem/classes/HotelBranchInformation.php
@@ -51,7 +51,7 @@ class HotelBranchInformation extends ObjectModel
'fields' => array(
'id_category' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'email' => array('type' => self::TYPE_STRING,'validate' => 'isEmail', 'size' => 255, 'required' => true),
- 'rating' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
+ 'rating' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'check_in' => array('type' => self::TYPE_STRING, 'required' => true),
'check_out' => array('type' => self::TYPE_STRING, 'required' => true),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
@@ -1160,7 +1160,7 @@ class HotelBranchInformation extends ObjectModel
{
// set additional hotel address and restriction fields validations here
if (isset($this->webservice_validation) && $this->webservice_validation) {
- if ($this->rating < 1 || $this->rating > 5) {
+ if ($this->rating && ($this->rating < 1 || $this->rating > 5)) {
$message = Tools::displayError('Rating must be between 1 and 5.');
} elseif (!strtotime($this->check_in)) {
$message = Tools::displayError('Check In time is invalid.');
diff --git a/modules/hotelreservationsystem/controllers/admin/AdminAddHotelController.php b/modules/hotelreservationsystem/controllers/admin/AdminAddHotelController.php
index f804b11ba..868012630 100644
--- a/modules/hotelreservationsystem/controllers/admin/AdminAddHotelController.php
+++ b/modules/hotelreservationsystem/controllers/admin/AdminAddHotelController.php
@@ -391,10 +391,6 @@ class AdminAddHotelController extends ModuleAdminController
$this->errors[] = $this->l('Check Out time must be before Check In time.');
}
- if (!$rating) {
- $this->errors[] = $this->l('Rating is required field.');
- }
-
if (!$address = trim($address)) {
$this->errors[] = $this->l('Address is required field.');
}
diff --git a/modules/hotelreservationsystem/views/templates/admin/add_hotel/helpers/form/form.tpl b/modules/hotelreservationsystem/views/templates/admin/add_hotel/helpers/form/form.tpl
index 22ae63e61..978872548 100644
--- a/modules/hotelreservationsystem/views/templates/admin/add_hotel/helpers/form/form.tpl
+++ b/modules/hotelreservationsystem/views/templates/admin/add_hotel/helpers/form/form.tpl
@@ -214,11 +214,11 @@