diff --git a/admin/themes/default/template/controllers/access/helpers/form/form.tpl b/admin/themes/default/template/controllers/access/helpers/form/form.tpl index d3f2a73f8..7c5a71acc 100644 --- a/admin/themes/default/template/controllers/access/helpers/form/form.tpl +++ b/admin/themes/default/template/controllers/access/helpers/form/form.tpl @@ -107,6 +107,47 @@ } perfect_access_js_gestion(this, perm, id_tab, tabsize, tabnumber, table); + if (perm == 'kpi') { + $(table + ' .kpi.' + id_tab).prop('checked', !!enabled); + } + + $(table + ' tr.kpi-row').each(function() { + var kpiTabId = $(this).data('kpi-parent'); + var kpiProfile = $(this).data('kpi-profile'); + var $kpiInputs = $(this).find('input.ajaxPower.kpi'); + if (!$kpiInputs.length || $kpiInputs.first().data('kpi-editable') != 1) { return; } + // For perm=view, read state directly from action — jQuery 1.11 .attr() doesn't update .prop() + var parentEnabled = (perm == 'view' && (id_tab == kpiTabId || id_tab == -1)) + ? !!enabled + : $(table + ' input.view.' + kpiTabId).first().is(':checked'); + if (!parentEnabled) { + $kpiInputs.prop('checked', false).prop('disabled', true); + } else { + $kpiInputs.prop('disabled', false); + if (perm == 'all' && (id_tab == -1 || id_tab == kpiTabId)) { + $kpiInputs.prop('checked', !!enabled).first().trigger('change'); + } + if (perm == 'view' && (id_tab == kpiTabId || id_tab == -1) && !!enabled) { + $kpiInputs.prop('checked', true); + $.ajax({ + url: "{$link->getAdminLink('AdminAccess')|addslashes}", + cache: false, + data: { + ajaxMode: '1', + id_tab: kpiTabId, + id_profile: kpiProfile, + perm: 'kpi', + enabled: 1, + submitAddAccess: '1', + action: 'updateAccess', + ajax: '1', + token: '{getAdminToken tab='AdminAccess'}' + } + }); + } + } + }); + $.ajax({ url: "{$link->getAdminLink('AdminAccess')|addslashes}", cache: false, @@ -349,6 +390,32 @@ + {if !empty($tab.has_kpi)} + +   » {l s='KPI'} + + + + + + + + + + + {/if} {foreach $tabs AS $child} {if $child.id_parent === $tab.id_tab} {if isset($access[$child.id_tab])} @@ -372,6 +439,32 @@ + {if !empty($child.has_kpi)} + +   » {l s='KPI'} + + + + + + + + + + + {/if} {/if} {/if} {/foreach} @@ -438,4 +531,4 @@ {/foreach} - + \ No newline at end of file diff --git a/admin/themes/default/template/controllers/carts/helpers/view/view.tpl b/admin/themes/default/template/controllers/carts/helpers/view/view.tpl index a57ed0a63..b26103a19 100644 --- a/admin/themes/default/template/controllers/carts/helpers/view/view.tpl +++ b/admin/themes/default/template/controllers/carts/helpers/view/view.tpl @@ -26,9 +26,7 @@ {extends file="helpers/view/view.tpl"} {block name="override_tpl"} -
- {$kpi} -
+
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:

  1. Always keep your account details safe.
  2. @@ -114,7 +114,7 @@
  3. Change your password regularly.
  4. 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 -*} - -
-
-
-
- {hook h="displayDashboardBadgeListBefore"} -
-
-
-
-
-

{l s="Arrivals" mod='dashguestcycle'}

-
-
-

- / -

-
-
-
-
-
-
-
-
-
-

{l s="Departures" mod='dashguestcycle'}

-
-
-

- / -

-
-
-
-
-
-
-
-
-
-

{l s="New Bookings" mod='dashguestcycle'}

-
-
-

- -

-
-
-
-
-
-
-
-
-
-

{l s='Occupied Rooms' mod='dashguestcycle'}

-
-
-

- -

-
-
-
-
-
-
-
-
-
-

- {l s="Guest Messages" mod='dashguestcycle'} -

-
-
-

- -

-
-
-
-
-
-
-
-
-
-

- {l s="Cancelled Bookings" mod='dashguestcycle'} -

-
-
-

- -

-
-
-
-
-
-
-
-
-
-

- {l s="Guests (Adults/Children)" mod='dashguestcycle'} -

-
-
-

- / -

-
-
-
-
- {hook h="displayDashboardBadgeListAfter"} -
-
-
-
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 @@
- +