- {assign var='col' value=(int)(12 / $kpis|count)}
- {foreach from=$kpis item=i name=kpi}
- {if $smarty.foreach.kpi.iteration > $col+1}
-
- {/if}
-
{$i}
+
+
+
+ {foreach from=$kpis item=kpi}
+
visible) && !$kpi->visible}style="display: none;"{/if}>
+ {$kpi->generate()}
+
{/foreach}
- {/if}
+
+
+ {if $refresh}
+
+ {/if}
+
+
+
+
+
+
+
+
+
diff --git a/classes/controller/AdminController.php b/classes/controller/AdminController.php
index ea3a469f7..f41e93ff7 100644
--- a/classes/controller/AdminController.php
+++ b/classes/controller/AdminController.php
@@ -963,6 +963,18 @@ class AdminControllerCore extends Controller
return true;
}
+ protected function ajaxProcessChangeKpiVisibility()
+ {
+ $cookieKey = 'kpi_visibility_'.$this->context->controller->className.'_'.Tools::getValue('kpi_id');
+ $this->context->cookie->$cookieKey = (int) Tools::getValue('is_visible');
+ }
+
+ protected function ajaxProcessSaveKpiView()
+ {
+ $cookieKey = 'kpi_wrapping_'.$this->context->controller->className;
+ $this->context->cookie->$cookieKey = (int) Tools::getValue('no_wrapping');
+ }
+
/**
* @TODO uses redirectAdmin only if !$this->ajax
* @return bool
diff --git a/classes/helper/HelperKpi.php b/classes/helper/HelperKpi.php
index a1b54a474..342de1bb7 100644
--- a/classes/helper/HelperKpi.php
+++ b/classes/helper/HelperKpi.php
@@ -40,6 +40,7 @@ class HelperKpiCore extends Helper
public $source;
public $href;
public $tooltip;
+ public $visible;
public function generate()
{
@@ -56,7 +57,8 @@ class HelperKpiCore extends Helper
'data' => $this->data,
'source' => $this->source,
'href' => $this->href,
- 'tooltip' => $this->tooltip
+ 'tooltip' => $this->tooltip,
+ 'visible' => $this->visible,
));
return $this->tpl->fetch();
diff --git a/classes/helper/HelperKpiRow.php b/classes/helper/HelperKpiRow.php
index 7f1d4e594..b6daea61a 100644
--- a/classes/helper/HelperKpiRow.php
+++ b/classes/helper/HelperKpiRow.php
@@ -36,8 +36,22 @@ class HelperKpiRowCore extends Helper
{
$this->tpl = $this->createTemplate($this->base_tpl);
+ // set visiblity for each KPI
+ $cookieKeyPrefix = 'kpi_visibility_'.$this->context->controller->className.'_';
+ foreach ($this->kpis as &$kpi) {
+ $cookieKey = $cookieKeyPrefix.$kpi->id;
+ if (isset($this->context->cookie->$cookieKey)) {
+ $kpi->visible = (bool) $this->context->cookie->$cookieKey;
+ } else {
+ $kpi->visible = true;
+ }
+ }
+
+ $cookieKeyView = 'kpi_wrapping_'.$this->context->controller->className;
+
$this->tpl->assign('kpis', $this->kpis);
$this->tpl->assign('refresh', $this->refresh);
+ $this->tpl->assign('no_wrapping', (int) $this->context->cookie->$cookieKeyView);
return $this->tpl->fetch();
}
diff --git a/controllers/admin/AdminCartsController.php b/controllers/admin/AdminCartsController.php
index 100489af1..f284cd978 100644
--- a/controllers/admin/AdminCartsController.php
+++ b/controllers/admin/AdminCartsController.php
@@ -172,7 +172,7 @@ class AdminCartsControllerCore extends AdminController
$helper->data = ConfigurationKPI::get('CONVERSION_RATE_CHART');
}
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=conversion_rate';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-carts';
@@ -184,7 +184,7 @@ class AdminCartsControllerCore extends AdminController
$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';
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=abandoned_cart';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-average-order';
@@ -193,7 +193,7 @@ class AdminCartsControllerCore extends AdminController
$helper->title = $this->l('Average Order Value', null, null, false);
$helper->subtitle = $this->l('30 days', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=average_order_value';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-net-profit-visitor';
@@ -202,7 +202,7 @@ class AdminCartsControllerCore extends AdminController
$helper->title = $this->l('Net Profit per Visitor', null, null, false);
$helper->subtitle = $this->l('30 days', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=netprofit_visit';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpiRow();
$helper->kpis = $kpis;
diff --git a/controllers/admin/AdminCustomerPreferencesController.php b/controllers/admin/AdminCustomerPreferencesController.php
index 00c2a9e68..1050c0772 100644
--- a/controllers/admin/AdminCustomerPreferencesController.php
+++ b/controllers/admin/AdminCustomerPreferencesController.php
@@ -90,7 +90,8 @@ class AdminCustomerPreferencesControllerCore extends AdminController
'cast' => 'intval',
'size' => 5,
'type' => 'text',
- 'suffix' => $this->l('minutes')
+ 'suffix' => $this->l('minutes'),
+ 'class' => 'fixed-width-xl',
),
'PS_B2B_ENABLE' => array(
'title' => $this->l('Enable B2B mode'),
@@ -120,6 +121,41 @@ class AdminCustomerPreferencesControllerCore extends AdminController
'cast' => 'intval',
'type' => 'bool'
),
+ 'PS_KPI_FREQUENT_CUSTOMER_NB_ORDERS' => array(
+ 'title' => $this->l('Number of orders to use to calculate frequent customers'),
+ 'hint' => $this->l('Set the number of orders to use to calculate frequent customers.'),
+ 'validation' => 'isUnsignedInt',
+ 'cast' => 'intval',
+ 'type' => 'text',
+ 'class' => 'fixed-width-xxl',
+ ),
+ 'PS_KPI_REVPAC_NB_DAYS' => array(
+ 'title' => $this->l('Number of days to use to calculate RevPAC'),
+ 'hint' => $this->l('Set the number of days to use to calculate RevPAC.'),
+ 'validation' => 'isUnsignedInt',
+ 'cast' => 'intval',
+ 'type' => 'text',
+ 'suffix' => $this->l('days'),
+ 'class' => 'fixed-width-xl',
+ ),
+ 'PS_KPI_CONVERSION_RATE_NB_DAYS' => array(
+ 'title' => $this->l('Number of days to use to calculate Conversion Rate'),
+ 'hint' => $this->l('Set the number of days to use to calculate Conversion Rate.'),
+ 'validation' => 'isUnsignedInt',
+ 'cast' => 'intval',
+ 'type' => 'text',
+ 'suffix' => $this->l('days'),
+ 'class' => 'fixed-width-xl',
+ ),
+ 'PS_KPI_NEW_CUSTOMERS_NB_DAYS' => array(
+ 'title' => $this->l('Number of days to use to calculate New Customers'),
+ 'hint' => $this->l('Set the number of days to use to calculate New Customers.'),
+ 'validation' => 'isUnsignedInt',
+ 'cast' => 'intval',
+ 'type' => 'text',
+ 'suffix' => $this->l('days'),
+ 'class' => 'fixed-width-xl',
+ ),
),
'submit' => array('title' => $this->l('Save')),
),
diff --git a/controllers/admin/AdminCustomerThreadsController.php b/controllers/admin/AdminCustomerThreadsController.php
index e9534093d..00e53b7ec 100644
--- a/controllers/admin/AdminCustomerThreadsController.php
+++ b/controllers/admin/AdminCustomerThreadsController.php
@@ -515,7 +515,7 @@ class AdminCustomerThreadsControllerCore extends AdminController
$helper->color = 'color1';
$helper->title = $this->l('Pending Discussion Threads', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=pending_messages';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-age';
@@ -524,7 +524,7 @@ class AdminCustomerThreadsControllerCore extends AdminController
$helper->title = $this->l('Average Response Time', null, null, false);
$helper->subtitle = $this->l('30 days', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=avg_msg_response_time';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-messages-per-thread';
@@ -533,7 +533,7 @@ class AdminCustomerThreadsControllerCore extends AdminController
$helper->title = $this->l('Messages per Thread', null, null, false);
$helper->subtitle = $this->l('30 day', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=messages_per_thread';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpiRow();
$helper->kpis = $kpis;
diff --git a/controllers/admin/AdminCustomersController.php b/controllers/admin/AdminCustomersController.php
index b7078a0f1..eed08c47d 100644
--- a/controllers/admin/AdminCustomersController.php
+++ b/controllers/admin/AdminCustomersController.php
@@ -643,41 +643,101 @@ class AdminCustomersControllerCore extends AdminController
$time = time();
$kpis = array();
- $helper = new HelperKpi();
- $helper->id = 'box-gender';
- $helper->icon = 'icon-male';
- $helper->color = 'color1';
- $helper->title = $this->l('Customers', null, null, false);
- $helper->subtitle = $this->l('All Time', null, null, false);
- $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=customer_main_gender';
- $kpis[] = $helper->generate();
-
- $helper = new HelperKpi();
- $helper->id = 'box-age';
- $helper->icon = 'icon-calendar';
- $helper->color = 'color2';
- $helper->title = $this->l('Average Age', 'AdminTab', null, false);
- $helper->subtitle = $this->l('All Time', null, null, false);
- $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=avg_customer_age';
- $kpis[] = $helper->generate();
-
$helper = new HelperKpi();
$helper->id = 'box-orders';
- $helper->icon = 'icon-retweet';
- $helper->color = 'color3';
+ $helper->icon = 'icon-shopping-cart';
+ $helper->color = 'color1';
$helper->title = $this->l('Orders per Customer', null, null, false);
$helper->subtitle = $this->l('All Time', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=orders_per_customer';
- $kpis[] = $helper->generate();
+ $helper->tooltip = $this->l('The average number of orders placed per customer in given period of time.', null, null, false);
+ $kpis[] = $helper;
$helper = new HelperKpi();
- $helper->id = 'box-newsletter';
+ $helper->id = 'box-total-frequent-customers';
+ $helper->icon = 'icon-star';
+ $helper->color = 'color2';
+ $helper->title = $this->l('Total Frequent Customers', null, null, false);
+ $helper->subtitle = $this->l('All Time', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_frequent_customers';
+ $helper->tooltip = $this->l('The total number of frequent customers in given period of time.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-revenue-per-available-customer';
+ $helper->icon = 'icon-dollar';
+ $helper->color = 'color3';
+ $helper->title = $this->l('RevPAC', null, null, false);
+ $nbDaysRevPac = 30;
+ if (Configuration::get('PS_KPI_REVPAC_NB_DAYS') !== false) {
+ $nbDaysRevPac = Configuration::get('PS_KPI_REVPAC_NB_DAYS');
+ }
+ $helper->subtitle = sprintf($this->l('%d Days', null, null, false), (int) $nbDaysRevPac);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=revenue_per_available_customer';
+ $helper->tooltip = $this->l('Revenue per Available Customer (RevPAC) in given period of time.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-newsletter-registrations';
$helper->icon = 'icon-envelope';
$helper->color = 'color4';
- $helper->title = $this->l('Newsletter Registrations', null, null, false);
+ $helper->title = $this->l('Total Newsletter Registrations', null, null, false);
$helper->subtitle = $this->l('All Time', null, null, false);
- $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=newsletter_registrations';
- $kpis[] = $helper->generate();
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_newsletter_registrations';
+ $helper->tooltip = $this->l('The total number of newsletter registrations in given period of time.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-conversion-rate';
+ $helper->icon = 'icon-refresh';
+ $helper->color = 'color1';
+ $helper->title = $this->l('Conversion Rate', null, null, false);
+ $nbDaysConversionRate = 30;
+ if (Configuration::get('PS_KPI_CONVERSION_RATE_NB_DAYS') !== false) {
+ $nbDaysConversionRate = Configuration::get('PS_KPI_CONVERSION_RATE_NB_DAYS');
+ }
+ $helper->subtitle = sprintf($this->l('%d Days', null, null, false), (int) $nbDaysConversionRate);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=conversion_rate';
+ $helper->tooltip = $this->l('The percentage of visitors who created a booking in given period of time.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-new-customers';
+ $helper->icon = 'icon-plus-circle';
+ $helper->color = 'color4';
+ $helper->title = $this->l('New Customers', null, null, false);
+ $nbDaysNewCustomers = 30;
+ if (Configuration::get('PS_KPI_NEW_CUSTOMERS_NB_DAYS') !== false) {
+ $nbDaysNewCustomers = Configuration::get('PS_KPI_NEW_CUSTOMERS_NB_DAYS');
+ }
+ $helper->subtitle = sprintf($this->l('%d Days', null, null, false), (int) $nbDaysNewCustomers);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_new_customers';
+ $helper->tooltip = $this->l('The total number of new customers who registered in given period of time.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-banned-customers';
+ $helper->icon = 'icon-ban';
+ $helper->color = 'color2';
+ $helper->title = $this->l('Banned Customers', null, null, false);
+ $helper->subtitle = $this->l('All Time', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_banned_customers';
+ $helper->tooltip = $this->l('The total number of banned customers.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-gender';
+ $helper->icon = 'icon-male';
+ $helper->color = 'color3';
+ $helper->title = $this->l('Customers', null, null, false);
+ $helper->subtitle = $this->l('All Time', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=customer_main_gender';
+ $helper->tooltip = $this->l('The main gender from all the customers.', null, null, false);
+ $kpis[] = $helper;
+
+ Hook::exec('action'.$this->controller_name.'KPIListingModifier', array(
+ 'kpis' => &$kpis,
+ ));
$helper = new HelperKpiRow();
$helper->kpis = $kpis;
diff --git a/controllers/admin/AdminModulesController.php b/controllers/admin/AdminModulesController.php
index 0eae6b275..9869ded51 100644
--- a/controllers/admin/AdminModulesController.php
+++ b/controllers/admin/AdminModulesController.php
@@ -1329,7 +1329,7 @@ class AdminModulesControllerCore extends AdminController
$helper->color = 'color1';
$helper->title = $this->l('Installed Modules', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=installed_modules';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-disabled-modules';
@@ -1337,7 +1337,7 @@ class AdminModulesControllerCore extends AdminController
$helper->color = 'color2';
$helper->title = $this->l('Disabled Modules', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=disabled_modules';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-update-modules';
@@ -1345,7 +1345,7 @@ class AdminModulesControllerCore extends AdminController
$helper->color = 'color3';
$helper->title = $this->l('Modules to Update', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=update_modules';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpiRow();
$helper->kpis = $kpis;
diff --git a/controllers/admin/AdminPPreferencesController.php b/controllers/admin/AdminPPreferencesController.php
index 1ea8b3f50..fefdb6add 100644
--- a/controllers/admin/AdminPPreferencesController.php
+++ b/controllers/admin/AdminPPreferencesController.php
@@ -66,7 +66,8 @@ class AdminPPreferencesControllerCore extends AdminController
'hint' => $this->l('The counting of days starts from room type creation date.'),
'validation' => 'isUnsignedInt',
'cast' => 'intval',
- 'type' => 'text'
+ 'type' => 'text',
+ 'class' => 'fixed-width-xxl',
),
/*'PS_CART_REDIRECT' => array(
'title' => $this->l('Redirect after adding product to cart'),
@@ -88,6 +89,7 @@ class AdminPPreferencesControllerCore extends AdminController
'cast' => 'intval',
'type' => 'text',
'suffix' => $this->l('characters'),
+ 'class' => 'fixed-width-xl',
),
/*'PS_QTY_DISCOUNT_ON_COMBINATION' => array(
'title' => $this->l('Quantity discounts based on'),
@@ -109,7 +111,16 @@ class AdminPPreferencesControllerCore extends AdminController
'cast' => 'intval',
'required' => false,
'type' => 'bool'
- )
+ ),
+ 'PS_KPI_BEST_SELLING_ROOM_TYPE_NB_DAYS' => array(
+ 'title' => $this->l('Number of days to use to calculate best selling room type'),
+ 'hint' => $this->l('Set the number of days to use to calculate best selling room type.'),
+ 'validation' => 'isUnsignedInt',
+ 'cast' => 'intval',
+ 'type' => 'text',
+ 'suffix' => $this->l('days'),
+ 'class' => 'fixed-width-xl',
+ ),
),
'submit' => array('title' => $this->l('Save'))
),
@@ -205,7 +216,8 @@ class AdminPPreferencesControllerCore extends AdminController
'hint' => $this->l('Number of room types displayed per page. Default is 10.'),
'validation' => 'isUnsignedInt',
'cast' => 'intval',
- 'type' => 'text'
+ 'type' => 'text',
+ 'class' => 'fixed-width-xxl',
),
'PS_PRODUCTS_ORDER_BY' => array(
'title' => $this->l('Default order by'),
@@ -312,7 +324,8 @@ class AdminPPreferencesControllerCore extends AdminController
'hint' => $this->l('Number of hotel images displayed per page. Default is 9.'),
'validation' => 'isUnsignedInt',
'cast' => 'intval',
- 'type' => 'text'
+ 'type' => 'text',
+ 'class' => 'fixed-width-xxl',
),
),
'submit' => array('title' => $this->l('Save'))
diff --git a/controllers/admin/AdminProductsController.php b/controllers/admin/AdminProductsController.php
index 542c4bdb6..af72c442b 100644
--- a/controllers/admin/AdminProductsController.php
+++ b/controllers/admin/AdminProductsController.php
@@ -2304,61 +2304,103 @@ class AdminProductsControllerCore extends AdminController
$time = time();
$kpis = array();
- // if (Configuration::get('PS_STOCK_MANAGEMENT')) {
- // $helper = new HelperKpi();
- // $helper->id = 'box-products-stock';
- // $helper->icon = 'icon-archive';
- // $helper->color = 'color1';
- // $helper->title = $this->l('Out of stock items', null, null, false);
- // if (ConfigurationKPI::get('PERCENT_PRODUCT_OUT_OF_STOCK') !== false) {
- // $helper->value = ConfigurationKPI::get('PERCENT_PRODUCT_OUT_OF_STOCK');
- // }
- // $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=percent_product_out_of_stock';
- // $helper->tooltip = $this->l('X% of your room types for sale are out of stock.', null, null, false);
- // $helper->refresh = (bool)(ConfigurationKPI::get('PERCENT_PRODUCT_OUT_OF_STOCK_EXPIRE') < $time);
- // $helper->href = Context::getContext()->link->getAdminLink('AdminProducts').'&productFilter_sav!quantity=0&productFilter_active=1&submitFilterproduct=1';
- // $kpis[] = $helper->generate();
- // }
+ $helper = new HelperKpi();
+ $helper->id = 'box-best-selling-room-type';
+ $helper->icon = 'icon-star';
+ $helper->color = 'color1';
+ $helper->title = $this->l('Best Selling', null, null, false);
+ $nbDaysBestSelling = 30;
+ if (Configuration::get('PS_KPI_BEST_SELLING_ROOM_TYPE_NB_DAYS') !== false) {
+ $nbDaysBestSelling = Configuration::get('PS_KPI_BEST_SELLING_ROOM_TYPE_NB_DAYS');
+ }
+ $helper->subtitle = sprintf($this->l('%d Days', null, null, false), (int) $nbDaysBestSelling);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=best_selling_room_type';
+ $helper->tooltip = $this->l('Displays the best selling room type based on the last 30 days of sales.', null, null, false);
+ $kpis[] = $helper;
$helper = new HelperKpi();
- $helper->id = 'box-avg-gross-margin';
- $helper->icon = 'icon-tags';
+ $helper->id = 'box-total-disbled-room-types';
+ $helper->icon = 'icon-ban';
$helper->color = 'color2';
- $helper->title = $this->l('Average Gross Margin %', null, null, false);
- $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=product_avg_gross_margin';
- $helper->tooltip = $this->l('Gross margin expressed in percentage assesses how cost-effectively you sell your room types / products. Out of $100, you will retain $X to cover profit and expenses.', null, null, false);
- $kpis[] = $helper->generate();
-
- $helper = new HelperKpi();
- $helper->id = 'box-8020-sales-catalog';
- $helper->icon = 'icon-beaker';
- $helper->color = 'color3';
- $helper->title = $this->l('Purchased References', null, null, false);
- $helper->subtitle = $this->l('30 days', null, null, false);
- $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=8020_sales_catalog';
- $helper->tooltip = $this->l('X% of your references have been purchased for the past 30 days.', null, null, false);
- if (Module::isInstalled('statsbestproducts')) {
- $helper->href = Context::getContext()->link->getAdminLink('AdminStats').'&module=statsbestproducts&datepickerFrom='.date('Y-m-d', strtotime('-30 days')).'&datepickerTo='.date('Y-m-d');
- }
- $kpis[] = $helper->generate();
-
- $helper = new HelperKpi();
- $helper->id = 'box-disabled-products';
- $helper->icon = 'icon-off';
- $helper->color = 'color4';
- $helper->href = $this->context->link->getAdminLink('AdminProducts');
$helper->title = $this->l('Disabled Room Types', null, null, false);
- if (ConfigurationKPI::get('DISABLED_ROOM_TYPES') !== false) {
- $helper->value = ConfigurationKPI::get('DISABLED_ROOM_TYPES');
- }
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=disabled_room_types';
- $helper->refresh = (bool)(ConfigurationKPI::get('DISABLED_ROOM_TYPES_EXPIRE') < $time);
- $helper->tooltip = $this->l('X% of your room types are disabled and not visible to your customers', null, null, false);
$helper->href = Context::getContext()->link->getAdminLink('AdminProducts').'&productFilter_sa!active=0&submitFilterproduct=1';
- $kpis[] = $helper->generate();
+ $helper->tooltip = $this->l('The total number of room types that are currently disabled.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-rooms';
+ $helper->icon = 'icon-bed';
+ $helper->color = 'color3';
+ $helper->title = $this->l('Total Rooms', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_rooms';
+ $helper->tooltip = $this->l('The total number of rooms in all hotels.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-online-bookable-rooms';
+ $helper->icon = 'icon-globe';
+ $helper->color = 'color4';
+ $helper->title = $this->l('Total Online Bookable Rooms', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_online_bookable_rooms';
+ $helper->tooltip = $this->l('The total number of rooms that can be booked using website.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-offline-bookable-rooms';
+ $helper->icon = 'icon-building';
+ $helper->color = 'color1';
+ $helper->title = $this->l('Total Offline Bookable Rooms', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_offline_bookable_rooms';
+ $helper->tooltip = $this->l('The number of rooms that can be booked through offline channels (e.g., phone or in-person).', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-occupied-rooms';
+ $helper->icon = 'icon-user';
+ $helper->color = 'color1';
+ $helper->title = $this->l('Total Occupied Rooms', null, null, false);
+ $helper->subtitle = $this->l('Today', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_occupied_rooms';
+ $helper->tooltip = $this->l('The current count of rooms that are currently occupied by guests.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-vacant-rooms';
+ $helper->icon = 'icon-check-empty';
+ $helper->color = 'color3';
+ $helper->title = $this->l('Total Vacant Rooms', null, null, false);
+ $helper->subtitle = $this->l('Today', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_vacant_rooms';
+ $helper->tooltip = $this->l('The count of rooms that are currently unoccupied and available for booking.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-reserved-rooms';
+ $helper->icon = 'icon-calendar';
+ $helper->color = 'color4';
+ $helper->title = $this->l('Total Reserved Rooms', null, null, false);
+ $helper->subtitle = $this->l('Today', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_reserved_rooms';
+ $helper->tooltip = $this->l('The number of rooms that are currently reserved but not yet occupied.', null, null, false);
+ $kpis[] = $helper;
+
+ $helper = new HelperKpi();
+ $helper->id = 'box-total-disabled-rooms';
+ $helper->icon = 'icon-ban';
+ $helper->color = 'color2';
+ $helper->title = $this->l('Total Disabled Rooms', null, null, false);
+ $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_disabled_rooms';
+ $helper->tooltip = $this->l('The number of rooms that are currently disabled.', null, null, false);
+ $kpis[] = $helper;
+
+ Hook::exec('action'.$this->controller_name.'KPIListingModifier', array(
+ 'kpis' => &$kpis,
+ ));
$helper = new HelperKpiRow();
$helper->kpis = $kpis;
+
return $helper->generate();
}
diff --git a/controllers/admin/AdminStatsController.php b/controllers/admin/AdminStatsController.php
index cdca3016d..0514f3d4d 100644
--- a/controllers/admin/AdminStatsController.php
+++ b/controllers/admin/AdminStatsController.php
@@ -176,22 +176,29 @@ class AdminStatsControllerCore extends AdminStatsTabController
'.Shop::addSqlAssociation('category', 'c'));
}
- public static function getDisabledRoomTypes()
+ public static function getDisabledRoomTypes($idHotel = null)
{
return (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT COUNT(*)
FROM `'._DB_PREFIX_.'product` p
+ INNER JOIN `'._DB_PREFIX_.'htl_room_type` hrt
+ ON (hrt.`id_product` = p.`id_product`)
'.Shop::addSqlAssociation('product', 'p').'
- WHERE product_shop.active = 0 AND p.`booking_product` = 1');
+ WHERE product_shop.active = 0 AND p.`booking_product` = 1'.
+ (!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel, 'hrt') : ''));
}
- public static function getTotalRoomTypes()
+ public static function getTotalRoomTypes($idHotel = null)
{
return (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT COUNT(*)
FROM `'._DB_PREFIX_.'product` p
+ INNER JOIN `'._DB_PREFIX_.'htl_room_type` hrt
+ ON (hrt.`id_product` = p.`id_product`)
'.Shop::addSqlAssociation('product', 'p').'
- WHERE p.`booking_product` = 1');
+ WHERE p.`booking_product` = 1'.
+ (!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel, 'hrt') : '')
+ );
}
public static function getDisabledProducts()
@@ -412,16 +419,6 @@ class AdminStatsControllerCore extends AdminStatsTabController
return $row;
}
- public static function getAverageCustomerAge()
- {
- $value = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
- SELECT AVG(DATEDIFF("'.date('Y-m-d').' 00:00:00", birthday))
- FROM `'._DB_PREFIX_.'customer` c
- WHERE active = 1
- AND birthday IS NOT NULL AND birthday != "0000-00-00" '.Shop::addSqlRestriction());
- return round($value / 365);
- }
-
public static function getPendingMessages()
{
return CustomerThread::getTotalCustomerThreads('status LIKE "%pending%" OR status = "open"'.Shop::addSqlRestriction());
@@ -558,6 +555,27 @@ class AdminStatsControllerCore extends AdminStatsTabController
return $expenses;
}
+ public static function getBestSellingRoomType($dateFrom, $dateTo, $idHotel = null)
+ {
+ $sql = 'SELECT p.`id_product`,
+ (
+ SELECT IFNULL(SUM(ROUND((DATEDIFF(LEAST(hbd.`date_to`, "'.pSQL($dateTo).'"), GREATEST(hbd.`date_from`, "'.pSQL($dateFrom).'")) / DATEDIFF(hbd.`date_to`, hbd.`date_from`)) * hbd.`total_price_tax_excl`, 2)), 0)
+ FROM `'._DB_PREFIX_.'htl_booking_detail` hbd
+ LEFT JOIN `'._DB_PREFIX_.'orders` o
+ ON (o.`id_order` = hbd.`id_order`)
+ WHERE hbd.`id_product` = p.`id_product` AND o.`valid` = 1
+ AND hbd.`date_to` > "'.pSQL($dateFrom).'" AND hbd.`date_from` < "'.pSQL($dateTo).'"
+ ) AS totalRevenue
+ FROM `'._DB_PREFIX_.'product` p
+ INNER JOIN `'._DB_PREFIX_.'htl_room_type` hrt
+ ON (hrt.`id_product` = p.`id_product`)
+ WHERE p.`active` = 1 AND p.`booking_product` = 1'.
+ (!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel, 'hrt') : '').'
+ ORDER BY totalRevenue DESC';
+
+ return Db::getInstance()->getValue($sql);
+ }
+
public function displayAjaxGetKpi()
{
$value = $this->getLatestKpiValue(Tools::getValue('kpi'));
@@ -577,17 +595,20 @@ class AdminStatsControllerCore extends AdminStatsTabController
$value = false;
switch ($kpi) {
case 'conversion_rate':
- $visitors = AdminStatsController::getVisits(true, date('Y-m-d', strtotime('-31 day')), date('Y-m-d', strtotime('-1 day')), false /*'day'*/);
- $orders = AdminStatsController::getOrders(date('Y-m-d', strtotime('-31 day')), date('Y-m-d', strtotime('-1 day')), false /*'day'*/);
+ $nbDaysConversionRate = Configuration::get('PS_KPI_CONVERSION_RATE_NB_DAYS');
- // $data = array();
- // $from = strtotime(date('Y-m-d 00:00:00', strtotime('-31 day')));
- // $to = strtotime(date('Y-m-d 23:59:59', strtotime('-1 day')));
- // for ($date = $from; $date <= $to; $date = strtotime('+1 day', $date))
- // if (isset($visitors[$date]) && $visitors[$date])
- // $data[$date] = round(100 * ((isset($orders[$date]) && $orders[$date]) ? $orders[$date] : 0) / $visitors[$date], 2);
- // else
- // $data[$date] = 0;
+ $visitors = AdminStatsController::getVisits(
+ true,
+ date('Y-m-d', strtotime('-'.($nbDaysConversionRate + 1).' day')),
+ date('Y-m-d', strtotime('-1 day')),
+ false /*'day'*/
+ );
+
+ $orders = AdminStatsController::getOrders(
+ date('Y-m-d', strtotime('-'.($nbDaysConversionRate + 1).' day')),
+ date('Y-m-d', strtotime('-1 day')),
+ false /*'day'*/
+ );
$visits_sum = $visitors; //array_sum($visitors);
$orders_sum = $orders; //array_sum($orders);
@@ -641,7 +662,7 @@ class AdminStatsControllerCore extends AdminStatsTabController
case 'disabled_room_types':
if (AdminStatsController::getTotalRoomTypes()) {
- $value = round(100 * AdminStatsController::getDisabledRoomTypes() / AdminStatsController::getTotalRoomTypes(), 2).'%';
+ $value = round(100 * AdminStatsController::getDisabledRoomTypes(0) / AdminStatsController::getTotalRoomTypes(0), 2).'%';
} else {
$value = '0%';
}
@@ -681,10 +702,6 @@ class AdminStatsControllerCore extends AdminStatsTabController
break;
- case 'avg_customer_age':
- $value = sprintf($this->l('%d years', null, null, false), AdminStatsController::getAverageCustomerAge(), 1);
- break;
-
case 'pending_messages':
$value = (int)AdminStatsController::getPendingMessages();
break;
@@ -707,22 +724,6 @@ class AdminStatsControllerCore extends AdminStatsTabController
$value = round(AdminStatsController::getMessagesPerThread(date('Y-m-d', strtotime('-31 day')), date('Y-m-d', strtotime('-1 day'))), 1);
break;
- case 'newsletter_registrations':
- $value = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
- SELECT COUNT(*)
- FROM `'._DB_PREFIX_.'customer`
- WHERE newsletter = 1
- '.Shop::addSqlRestriction(Shop::SHARE_ORDER));
- if (Module::isInstalled('blocknewsletter')) {
- $value += Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
- SELECT COUNT(*)
- FROM `'._DB_PREFIX_.'newsletter`
- WHERE active = 1
- '.Shop::addSqlRestriction(Shop::SHARE_ORDER));
- }
-
- break;
-
case 'enabled_languages':
$value = Language::countActiveLanguages();
break;
@@ -808,17 +809,105 @@ class AdminStatsControllerCore extends AdminStatsTabController
}
break;
+
+ case 'best_selling_room_type':
+ $nbDaysBestSelling = Configuration::get('PS_KPI_BEST_SELLING_ROOM_TYPE_NB_DAYS');
+
+ if (!($idProduct = AdminStatsController::getBestSellingRoomType(
+ date('Y-m-d', strtotime('-'.($nbDaysBestSelling + 1).' day')),
+ date('Y-m-d', strtotime('-1 day')),
+ 0
+ ))) {
+ $value = $this->l('No room type', null, null, false);
+ } else {
+ $objProduct = new Product($idProduct, false, $this->context->language->id);
+ $value = $objProduct->name;
+ }
+
+ break;
+
+ case 'total_rooms':
+ $value = AdminStatsController::getTotalRooms(0);
+
+ break;
+
+ case 'total_online_bookable_rooms':
+ $value = AdminStatsController::getTotalRooms(0, 1);
+
+ break;
+
+ case 'total_offline_bookable_rooms':
+ $value = AdminStatsController::getTotalRooms(0, 0);
+
+ break;
+
+ case 'total_occupied_rooms':
+ $value = AdminStatsController::getTotalOccupiedRooms(0);
+
+ break;
+
+ case 'total_vacant_rooms':
+ $value = AdminStatsController::getAvailableRoomsForDiscreteDates(date('Y-m-d', strtotime('-1 day')), null, 0);
+ $value = $value[strtotime(date('Y-m-d', strtotime('-1 day')))];
+
+ break;
+
+ case 'total_reserved_rooms':
+ $value = AdminStatsController::getTotalReservedRooms(0);
+
+ break;
+
+ case 'total_disabled_rooms':
+ $value = AdminStatsController::getDisabledRoomsForDiscreteDates(date('Y-m-d', strtotime('-1 day')), null, 0);
+ $value = $value[strtotime(date('Y-m-d', strtotime('-1 day')))];
+
+ break;
+
+ case 'total_frequent_customers':
+ $nbOrdersFrequentCustomers = Configuration::get('PS_KPI_FREQUENT_CUSTOMER_NB_ORDERS');
+
+ $value = AdminStatsController::getTotalFrequentCustomers($nbOrdersFrequentCustomers, 0);
+
+ break;
+
+ case 'revenue_per_available_customer':
+ $nbDaysRevPac = Configuration::get('PS_KPI_REVPAC_NB_DAYS');
+
+ $value = AdminStatsController::getRevenuePerAvailableCustomer(
+ date('Y-m-d', strtotime('-'.($nbDaysRevPac + 1).' day')),
+ date('Y-m-d', strtotime('-1 day')),
+ 0
+ );
+
+ $value = Tools::displayPrice($value, $currency);
+
+ break;
+
+ case 'total_newsletter_registrations':
+ $value = AdminStatsController::getTotalNewsletterRegistrations();
+
+ break;
+
+ case 'total_new_customers':
+ $nbDaysNewCustomers = Configuration::get('PS_KPI_NEW_CUSTOMERS_NB_DAYS');
+
+ $value = AdminStatsController::getTotalNewCustomers(
+ date('Y-m-d', strtotime('-'.($nbDaysNewCustomers + 1).' day')),
+ date('Y-m-d', strtotime('-1 day')),
+ );
+
+ break;
+
+ case 'total_banned_customers':
+ $value = AdminStatsController::getTotalBannedCustomers();
+
+ break;
+
default:
$value = false;
}
- if ($value !== false) {
- $array = array('value' => $value);
- if (isset($data)) {
- $array['data'] = $data;
- }
- die(json_encode($array));
- }
- die(json_encode(array('has_errors' => true)));
+
+ return $value;
}
public static function getFrontOfficeTranslations()
@@ -946,12 +1035,17 @@ class AdminStatsControllerCore extends AdminStatsTabController
);
}
- public static function getTotalRooms($idHotel = false)
+ public static function getTotalRooms($idHotel = null, $showAtFront = null)
{
- return Db::getInstance()->getValue(
- 'SELECT COUNT(`id`) FROM `'._DB_PREFIX_.'htl_room_information` hri
- WHERE 1'.HotelBranchInformation::addHotelRestriction($idHotel, 'hri')
- );
+ $sql = 'SELECT COUNT(hri.`id`)
+ FROM `'._DB_PREFIX_.'htl_room_information` hri
+ INNER JOIN `'._DB_PREFIX_.'product` p
+ ON (p.`id_product` = hri.`id_product`)
+ WHERE p.`booking_product` = 1 '.
+ (!is_null($showAtFront) ? ' AND p.`show_at_front` = '.(int) $showAtFront : '').
+ (!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel, 'hri') : '');
+
+ return Db::getInstance()->getValue($sql);
}
public static function getOccupancyData($dateFrom, $dateTo, $idsHotel = false)
@@ -1557,6 +1651,174 @@ class AdminStatsControllerCore extends AdminStatsTabController
return $result;
}
+ public static function getDisabledRoomsForDiscreteDates($dateFrom, $dateTo = null, $idHotel = null, $useCache = true)
+ {
+ $dateTo = !$dateTo ? date('Y-m-d', strtotime('+1 day', strtotime($dateFrom))) : $dateTo;
+ $discreteDates = array();
+ $dateTemp = $dateFrom;
+ while ($dateTemp <= $dateTo) {
+ $dateNext = date('Y-m-d', strtotime('+1 day', strtotime($dateTemp)));
+ $discreteDates[] = array(
+ 'date_from' => $dateTemp,
+ 'date_to' => $dateNext,
+ 'timestamp_from' => strtotime($dateTemp),
+ );
+ $dateTemp = $dateNext;
+ };
+
+ $result = array();
+ foreach ($discreteDates as $discreteDate) {
+ $cacheKey = 'AdminStats::getDisabledRoomsForDiscreteDates'.'_'.(int) $discreteDate['timestamp_from'].'_'.
+ (!is_array($idHotel) ? (int) $idHotel : implode('_', $idHotel));
+ if (!Cache::isStored($cacheKey) || !$useCache) {
+ $sql = 'SELECT (num_inactive + num_temporarily_inactive) AS num_disabled
+ FROM (
+ SELECT (
+ SELECT IFNULL(COUNT(hri.`id`), 0)
+ FROM `'._DB_PREFIX_.'htl_room_information` hri
+ LEFT JOIN `'._DB_PREFIX_.'product` p
+ ON (p.`id_product` = hri.`id_product`)
+ WHERE hri.`id_status` = '.(int) HotelRoomInformation::STATUS_INACTIVE.'
+ AND p.`active` = 1'.
+ (!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel, 'hri') : '').'
+ ) AS num_inactive,
+ (
+ SELECT IFNULL(COUNT(hri.`id`), 0)
+ FROM `'._DB_PREFIX_.'htl_room_information` hri
+ LEFT JOIN `'._DB_PREFIX_.'htl_room_disable_dates` hrdd
+ ON (hrdd.`id_room` = hri.`id`)
+ LEFT JOIN `'._DB_PREFIX_.'product` p
+ ON (p.`id_product` = hri.`id_product`)
+ WHERE hri.`id_status` = '.(int) HotelRoomInformation::STATUS_TEMPORARY_INACTIVE.'
+ AND ("'.pSQL($discreteDate['date_from']).'" >= hrdd.`date_from` AND "'.pSQL($discreteDate['date_from']).'" < hrdd.`date_to`)
+ AND p.`active` = 1'.
+ (!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel, 'hri') : '').'
+ ) AS num_temporarily_inactive
+ ) AS t';
+
+ $value = Db::getInstance()->getValue($sql);
+ Cache::store($cacheKey, $value);
+ }
+
+ $result[$discreteDate['timestamp_from']] = Cache::retrieve($cacheKey);
+ }
+
+ return $result;
+ }
+
+ public static function getTotalOccupiedRooms($idHotel = null)
+ {
+ $sql = 'SELECT COUNT(DISTINCT hbd.`id_room`)
+ FROM `'._DB_PREFIX_.'htl_booking_detail` hbd
+ LEFT JOIN `'._DB_PREFIX_.'htl_room_information` hri
+ ON (hri.`id` = hbd.`id_room`)
+ LEFT JOIN `'._DB_PREFIX_.'product` p
+ ON (p.`id_product` = hri.`id_product`)
+ WHERE p.`active` = 1
+ AND hbd.`is_refunded` = 0
+ AND hbd.`is_cancelled` = 0
+ AND hbd.`id_status` = '.(int) HotelBookingDetail::STATUS_CHECKED_IN.
+ (!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel, 'hbd') : '');
+ $result = Db::getInstance()->getValue($sql);
+
+ return $result;
+ }
+
+ public static function getTotalReservedRooms($idHotel = null)
+ {
+ $dateToday = date('Y-m-d');
+
+ $sql = 'SELECT COUNT(DISTINCT hbd.`id_room`)
+ FROM `'._DB_PREFIX_.'htl_booking_detail` hbd
+ LEFT JOIN `'._DB_PREFIX_.'htl_room_information` hri
+ ON (hri.`id` = hbd.`id_room`)
+ LEFT JOIN `'._DB_PREFIX_.'product` p
+ ON (p.`id_product` = hri.`id_product`)
+ WHERE p.`active` = 1
+ AND hbd.`is_refunded` = 0
+ AND hbd.`is_cancelled` = 0
+ AND hbd.`id_status` != '.(int) HotelBookingDetail::STATUS_CHECKED_IN.'
+ AND hbd.`date_from` = "'.pSQL($dateToday).' 00:00:00"'.
+ (!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel, 'hbd') : '');
+ $result = Db::getInstance()->getValue($sql);
+
+ return $result;
+ }
+
+ public static function getTotalFrequentCustomers($nbOrders = 5, $idHotel = null)
+ {
+ $sql = 'SELECT COUNT(t.`id_customer`)
+ FROM (
+ SELECT o.`id_customer`, COUNT(o.`id_order`) AS nb_orders,
+ (
+ SELECT hbd.`id_hotel`
+ FROM `'._DB_PREFIX_.'htl_booking_detail` hbd
+ WHERE hbd.`id_order` = o.`id_order` LIMIT 1
+ ) AS id_hotel
+ FROM `'._DB_PREFIX_.'orders` o
+ WHERE o.`valid` = 1
+ GROUP BY o.`id_customer`
+ HAVING 1 '.(!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel) : '').'
+ ) AS t
+ WHERE t.`nb_orders` >= '.(int) $nbOrders;
+ $result = Db::getInstance()->getValue($sql);
+
+ return $result;
+ }
+
+ public static function getRevenuePerAvailableCustomer($dateFrom, $dateTo, $idHotel = null)
+ {
+ $totalRevenue = self::getRevenue($dateFrom, $dateTo, $idHotel);
+
+ $totalCustomers = Db::getInstance()->getValue(
+ 'SELECT COUNT(c.`id_customer`)
+ FROM `'._DB_PREFIX_.'customer` c
+ WHERE c.`date_add` <= "'.pSQL($dateTo).' 23:59:59"'
+ );
+
+ return $totalCustomers ? $totalRevenue / $totalCustomers : 0;
+ }
+
+ public static function getTotalNewsletterRegistrations()
+ {
+ $customerRegistrations = Db::getInstance()->getValue(
+ 'SELECT COUNT(c.`id_customer`)
+ FROM `'._DB_PREFIX_.'customer` c
+ WHERE c.`newsletter` = 1'
+ );
+
+ $visitorRegistrations = 0;
+ if (Module::isInstalled('blocknewsletter')) {
+ $visitorRegistrations = Db::getInstance()->getValue(
+ 'SELECT COUNT(n.`id`)
+ FROM `'._DB_PREFIX_.'newsletter` n
+ WHERE n.`active` = 1'
+ );
+ }
+
+ return $customerRegistrations + $visitorRegistrations;
+ }
+
+ public static function getTotalNewCustomers($dateFrom, $dateTo)
+ {
+ $sql = 'SELECT COUNT(c.`id_customer`)
+ FROM `'._DB_PREFIX_.'customer` c
+ WHERE c.`date_add` >= "'.pSQL($dateFrom).' 00:00:00" AND c.`date_add` <= "'.pSQL($dateTo).' 23:59:59"';
+ $result = Db::getInstance()->getValue($sql);
+
+ return $result;
+ }
+
+ public static function getTotalBannedCustomers()
+ {
+ $sql = 'SELECT COUNT(c.`id_customer`)
+ FROM `'._DB_PREFIX_.'customer` c
+ WHERE c.`deleted` = 1';
+ $result = Db::getInstance()->getValue($sql);
+
+ return $result;
+ }
+
public static function getOccupancyRateForDiscreteDates($dateFrom, $dateTo, $idHotel = null)
{
if ($dateFrom == $dateTo) {
diff --git a/controllers/admin/AdminTranslationsController.php b/controllers/admin/AdminTranslationsController.php
index 71ae8481b..5206b05e0 100644
--- a/controllers/admin/AdminTranslationsController.php
+++ b/controllers/admin/AdminTranslationsController.php
@@ -1325,7 +1325,7 @@ class AdminTranslationsControllerCore extends AdminController
$helper->href = $this->context->link->getAdminLink('AdminLanguages');
$helper->title = $this->l('Enabled Languages', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=enabled_languages';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-fo-translations';
@@ -1333,7 +1333,7 @@ class AdminTranslationsControllerCore extends AdminController
$helper->color = 'color3';
$helper->title = $this->l('Front office Translations', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=frontoffice_translations';
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-bo-translations';
@@ -1345,7 +1345,7 @@ class AdminTranslationsControllerCore extends AdminController
}
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=backoffice_translations';
$helper->refresh = (bool)(ConfigurationKPI::get('BACKOFFICE_TRANSLATIONS_EXPIRE') < $time);
- $kpis[] = $helper->generate();
+ $kpis[] = $helper;
$helper = new HelperKpiRow();
$helper->kpis = $kpis;
diff --git a/install/data/xml/configuration.xml b/install/data/xml/configuration.xml
index 935de20ba..023e59636 100644
--- a/install/data/xml/configuration.xml
+++ b/install/data/xml/configuration.xml
@@ -101,6 +101,9 @@
20
+
+ 30
+
0
@@ -884,6 +887,18 @@
1
+
+ 5
+
+
+ 30
+
+
+ 30
+
+
+ 30
+
0
diff --git a/js/admin.js b/js/admin.js
index 4d474721a..49d636379 100644
--- a/js/admin.js
+++ b/js/admin.js
@@ -1551,6 +1551,54 @@ function refresh_kpis()
});
}
+$(document).on('change', '.kpi-container .kpi-display-toggle', function (e) {
+ let kpiCheckbox = $(this);
+ let isVisible = parseInt(kpiCheckbox.is(':checked') & 1);
+
+ // hide or show the KPI
+ $('#' + kpiCheckbox.attr('data-kpi-id')).parent().toggle(isVisible);
+
+ // save visibility state to cookie
+ $.ajax({
+ type: 'POST',
+ headers: { 'cache-control': 'no-cache' },
+ url: window.location,
+ cache: false,
+ dataType: 'json',
+ data: {
+ ajax: 1,
+ controller: help_class_name,
+ action: 'changeKpiVisibility',
+ kpi_id: kpiCheckbox.attr('data-kpi-id'),
+ is_visible: isVisible,
+ }
+ });
+});
+
+// prevent dropdown from closing on clicking its body
+$(document).on('click', '.kpi-container .dropdown-menu', function (e) {
+ e.stopPropagation();
+});
+
+function toggleKpiView() {
+ $('.kpi-container').toggleClass('no-wrapping'); // default view is to wrap KPIs
+
+ // save view to cookie
+ $.ajax({
+ type: 'POST',
+ headers: { 'cache-control': 'no-cache' },
+ url: window.location,
+ cache: false,
+ dataType: 'json',
+ data: {
+ ajax: 1,
+ controller: help_class_name,
+ action: 'saveKpiView',
+ no_wrapping: parseInt($('.kpi-container').hasClass('no-wrapping') & 1),
+ }
+ });
+}
+
function createSqlQueryName()
{
var container = false;