* @copyright 2007-2011 PrestaShop SA * @version Release: $Revision: 7328 $ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) * International Registered Trademark & Property of PrestaShop SA */ if (!defined('_CAN_LOAD_FILES_')) exit; class StatsForecast extends Module { private $_html = ''; private $t1 = 0; private $t2 = 0; private $t3 = 0; private $t4 = 0; private $t5 = 0; private $t6 = 0; private $t7 = 0; private $t8 = 0; public function __construct() { $this->name = 'statsforecast'; $this->tab = 'analytics_stats'; $this->version = 1.0; $this->author = 'PrestaShop'; $this->need_instance = 0; parent::__construct(); $this->displayName = $this->l('Stats Dashboard'); $this->description = ''; } public function install() { return (parent::install() && $this->registerHook('AdminStatsModules')); } public function getContent() { Tools::redirectAdmin('index.php?tab=AdminStats&module=statsforecast&token='.Tools::getAdminTokenLite('AdminStats')); } public function hookAdminStatsModules() { global $cookie, $currentIndex; $ru = $currentIndex.'&module='.$this->name.'&token='.Tools::getValue('token'); $db = Db::getInstance(); if (!isset($cookie->stats_granularity)) $cookie->stats_granularity = 10; if (Tools::isSubmit('submitIdZone')) $cookie->stats_id_zone = Tools::getValue('stats_id_zone'); if (Tools::isSubmit('submitGranularity')) $cookie->stats_granularity = Tools::getValue('stats_granularity'); $currency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT')); $employee = new Employee((int)($cookie->id_employee)); $result = $db->getRow('SELECT UNIX_TIMESTAMP(\'2009-06-05 00:00:00\') as t1, UNIX_TIMESTAMP(\''.$employee->stats_date_from.' 00:00:00\') as t2'); $from = max($result['t1'], $result['t2']); $to = strtotime($employee->stats_date_to.' 23:59:59'); $result2 = $db->getRow('SELECT UNIX_TIMESTAMP(NOW()) as t1, UNIX_TIMESTAMP(\''.$employee->stats_date_to.' 23:59:59\') as t2'); $to2 = min($result2['t1'], $result2['t2']); $interval = ($to - $from) / 60 / 60 / 24; $interval2 = ($to2 - $from) / 60 / 60 / 24; $prop30 = $interval / $interval2; if ($cookie->stats_granularity == 7) $intervalAvg = $interval2 / 30; if ($cookie->stats_granularity == 4) $intervalAvg = $interval2 / 365; if ($cookie->stats_granularity == 10) $intervalAvg = $interval2; if ($cookie->stats_granularity == 42) $intervalAvg = $interval2 / 7; define('PS_BASE_URI', '/'); $result = $db->getRow('SELECT UNIX_TIMESTAMP(\'2009-06-05\') as t1, UNIX_TIMESTAMP(\''.$employee->stats_date_from.'\') as t2'); $from = max($result['t1'], $result['t2']); $to = strtotime($employee->stats_date_to.''); $dateFromGAdd = ($cookie->stats_granularity != 42 ? 'SUBSTRING(date_add, 1, '.(int)$cookie->stats_granularity.')' : 'IFNULL(MAKEDATE(YEAR(date_add),DAYOFYEAR(date_add)-WEEKDAY(date_add)), CONCAT(YEAR(date_add),"-01-01*"))'); $dateFromGInvoice = ($cookie->stats_granularity != 42 ? 'SUBSTRING(invoice_date, 1, '.(int)$cookie->stats_granularity.')' : 'IFNULL(MAKEDATE(YEAR(invoice_date),DAYOFYEAR(invoice_date)-WEEKDAY(invoice_date)), CONCAT(YEAR(invoice_date),"-01-01*"))'); $result = $db->ExecuteS(' SELECT '.$dateFromGInvoice.' as fix_date, COUNT(DISTINCT o.id_order) as countOrders, SUM(od.product_quantity) as countProducts, SUM(od.product_price * od.product_quantity / o.conversion_rate) as totalProducts FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_detail od ON o.id_order = od.id_order LEFT JOIN '._DB_PREFIX_.'product p ON od.product_id = p.id_product WHERE o.valid = 1 AND o.invoice_date BETWEEN '.ModuleGraph::getDateBetween().' GROUP BY '.$dateFromGInvoice.' ORDER BY fix_date', false); $dataTable = array(); if ($cookie->stats_granularity == 10) { $dateEnd = strtotime($employee->stats_date_to.' 23:59:59'); $dateToday = time(); for ($i = strtotime($employee->stats_date_from.' 00:00:00'); $i <= $dateEnd AND $i <= $dateToday; $i += 86400) $dataTable[$i] = array('fix_date' => date('Y-m-d', $i), 'countOrders' => 0, 'countProducts' => 0, 'totalProducts' => 0); } while ($row = $db->nextRow($result)) $dataTable[strtotime($row['fix_date'])] = $row; $this->_html .= '
'.$this->displayName.'

'.$this->l('All amounts are without taxes.').'

'.$this->l('Mode:').'
 
'; $visitArray = array(); $visits = Db::getInstance()->ExecuteS('SELECT '.$dateFromGAdd.' as fix_date, COUNT(*) as visits FROM '._DB_PREFIX_.'connections c WHERE c.date_add BETWEEN '.ModuleGraph::getDateBetween().' GROUP BY '.$dateFromGAdd, false); while ($row = $db->nextRow($visits)) $visitArray[$row['fix_date']] = $row['visits']; $discountArray = array(); $discounts = Db::getInstance()->ExecuteS(' SELECT '.$dateFromGInvoice.' as fix_date, SUM(od.value) as total FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_discount od ON o.id_order = od.id_order WHERE o.valid = 1 AND o.total_paid_real > 0 AND o.invoice_date BETWEEN '.ModuleGraph::getDateBetween().' GROUP BY '.$dateFromGInvoice, false); while ($row = $db->nextRow($discounts)) $discountArray[$row['fix_date']] = $row['total']; $today = date('Y-m-d'); foreach ($dataTable as $row) { $discountToday = (isset($discountArray[$row['fix_date']]) ? $discountArray[$row['fix_date']] : 0); $visitsToday = (int)(isset($visitArray[$row['fix_date']]) ? $visitArray[$row['fix_date']] : 0); $dateFromGReg = ($cookie->stats_granularity != 42 ? 'LIKE \''.$row['fix_date'].'%\'' : 'BETWEEN \''.substr($row['fix_date'], 0, 10).' 00:00:00\' AND DATE_ADD(\''.substr($row['fix_date'], 0, 8).substr($row['fix_date'], 8, 2).' 23:59:59\', INTERVAL 7 DAY)'); $row['registrations'] = Db::getInstance()->getValue('SELECT COUNT(*) FROM '._DB_PREFIX_.'customer WHERE date_add BETWEEN '.ModuleGraph::getDateBetween().' AND date_add '.$dateFromGReg); $totalHT = $row['totalProducts'] - $discountToday; $this->_html .= ' '; $this->t1 += $visitsToday; $this->t2 += (int)($row['registrations']); $this->t3 += (int)($row['countOrders']); $this->t4 += (int)($row['countProducts']); $this->t7 += $discountToday; $this->t8 += $totalHT; } $this->_html .= '
'.$this->l('Visits').' '.$this->l('Reg.').' '.$this->l('Orders').' '.$this->l('Items').' '.$this->l('% Reg.').' '.$this->l('% Orders').' '.$this->l('Coupons').' '.$this->l('Products Sales').'
'.$row['fix_date'].' '.$visitsToday.' '.(int)($row['registrations']).' '.(int)($row['countOrders']).' '.(int)($row['countProducts']).' '.($visitsToday ? round(100 * (int)($row['registrations']) / $visitsToday, 2).' %' : '-').' '.($visitsToday ? round(100 * (int)($row['countOrders']) / $visitsToday, 2).' %' : '-').' '.Tools::displayPrice($discountToday, $currency).' '.Tools::displayPrice($totalHT, $currency).'
'.$this->l('Visits').' '.$this->l('Reg.').' '.$this->l('Orders').' '.$this->l('Items').' '.$this->l('% Reg.').' '.$this->l('% Orders').' '.$this->l('Coupons').' '.$this->l('Products Sales').'
'.$this->l('Total').' '.(int)($this->t1).' '.(int)($this->t2).' '.(int)($this->t3).' '.(int)($this->t4).' -- -- '.Tools::displayPrice($this->t7, $currency).' '.Tools::displayPrice($this->t8, $currency).'
'.$this->l('Average').' '.(int)($this->t1 / $intervalAvg).' '.(int)($this->t2 / $intervalAvg).' '.(int)($this->t3 / $intervalAvg).' '.(int)($this->t4 / $intervalAvg).' '.($this->t1 ? round(100 * $this->t2 / $this->t1, 2) .' %' : '-').' '.($this->t1 ? round(100 * $this->t3 / $this->t1, 2) .' %' : '-').' '.Tools::displayPrice($this->t7 / $intervalAvg, $currency).' '.Tools::displayPrice($this->t8 / $intervalAvg, $currency).'
'.$this->l('Forecast').' '.(int)($this->t1 * $prop30).' '.(int)($this->t2 * $prop30).' '.(int)($this->t3 * $prop30).' '.(int)($this->t4 * $prop30).' -- -- '.Tools::displayPrice($this->t7 * $prop30, $currency).' '.Tools::displayPrice($this->t8 * $prop30, $currency).'
'; $ca = $this->getRealCA(); $visitors = Db::getInstance()->getValue('SELECT COUNT(DISTINCT id_guest) FROM '._DB_PREFIX_.'connections WHERE date_add BETWEEN '.ModuleGraph::getDateBetween()); $customers = Db::getInstance()->getValue('SELECT COUNT(DISTINCT id_customer) FROM '._DB_PREFIX_.'connections c INNER JOIN '._DB_PREFIX_.'guest g ON c.id_guest = g.id_guest WHERE id_customer != 0 AND c.date_add BETWEEN '.ModuleGraph::getDateBetween()); $carts = Db::getInstance()->getValue('SELECT COUNT(*) FROM '._DB_PREFIX_.'cart WHERE id_cart IN (SELECT id_cart FROM '._DB_PREFIX_.'cart_product) AND (date_add BETWEEN '.ModuleGraph::getDateBetween().' OR date_upd BETWEEN '.ModuleGraph::getDateBetween().')'); $fullcarts = Db::getInstance()->getValue('SELECT COUNT(*) FROM '._DB_PREFIX_.'cart WHERE id_cart IN (SELECT id_cart FROM '._DB_PREFIX_.'cart_product) AND id_address_invoice != 0 AND (date_add BETWEEN '.ModuleGraph::getDateBetween().' OR date_upd BETWEEN '.ModuleGraph::getDateBetween().')'); $orders = Db::getInstance()->getValue('SELECT COUNT(*) FROM '._DB_PREFIX_.'orders WHERE valid = 1 AND date_add BETWEEN '.ModuleGraph::getDateBetween()); $this->_html .= '
 
'.$this->l('Conversion').' '.$this->l('Visitors').'
'.$visitors.'

'.round(100 * $customers / max(1, $visitors)).' %

'.round(100 * $carts / max(1, $visitors)).' %
'.$this->l('Accounts').'
'.$customers.'
'.$this->l('Carts').'
'.$carts.'

'.round(100 * $fullcarts / max(1, $customers)).' %

'.round(100 * $fullcarts / max(1, $carts)).' %
'.$this->l('Full carts').'
'.$fullcarts.'

'.round(100 * $orders / max(1, $fullcarts)).' %
'.$this->l('Orders').'
'.$orders.'


'.$this->l('Registered visitors').' '.round(100 * $orders / max(1, $customers), 2).' % '.$this->l('Orders').'
'.$this->l('Visitors').' '.round(100 * $orders / max(1, $visitors), 2).' % '.$this->l('Orders').'
 
'.$this->l('Turn your visitors into money:').'
'.$this->l('Each visitor yields').' '.Tools::displayPrice($ca['ventil']['total'] / max(1, $visitors), $currency).'.
'.$this->l('Each registered visitor yields').' '.Tools::displayPrice($ca['ventil']['total'] / max(1, $customers), $currency).'.
'; $from = strtotime($employee->stats_date_from.' 00:00:00'); $to = strtotime($employee->stats_date_to.' 23:59:59'); $interval = ($to - $from) / 60 / 60 / 24; $prop5000 = 5000 / 30 * $interval; $this->_html .= '
 
'; $this->_html .= '
'.$this->l('Payment distibution').'
'.$this->l('Zone:').'
'; foreach ($ca['payment'] as $payment) $this->_html .= ' '; $this->_html .= '
'.$this->l('Module').''.$this->l('Count').''.$this->l('Total').''.$this->l('Cart').'
'.$payment['module'].' '.(int)$payment['nb'].'
'.($ca['ventil']['nb'] ? number_format((100 * $payment['nb'] / $ca['ventil']['nb']), 1, '.', ' ') : '0').' %
'.Tools::displayPrice($payment['total'], $currency).'
'.($ca['ventil']['total'] ? number_format((100 * $payment['total'] / $ca['ventil']['total']), 1, '.', ' ') : '0').' %
'.Tools::displayPrice($payment['cart'], $currency).'
 
'.$this->l('Category distribution').'
'.$this->l('Zone:').'
'; foreach ($ca['cat'] as $catrow) $this->_html .= ' '; $this->_html .= '
'.$this->l('Category').''.$this->l('Count').''.$this->l('Sales').''.$this->l('% Count').''.$this->l('% Sales').''.$this->l('Avg price').'
'.(empty($catrow['name']) ? $this->l('Unknown') : $catrow['name']).' '.$catrow['orderQty'].' '.Tools::displayPrice($catrow['orderSum'], $currency).' '.number_format((100 * $catrow['orderQty'] / $this->t4), 1, '.', ' ').'% '.($ca['ventil']['total'] ? number_format((100 * $catrow['orderSum'] / $ca['ventil']['total']), 1, '.', ' ') : '0').'% '.Tools::displayPrice($catrow['priveAvg'], $currency).'
 
'.$this->l('Language distribution').' '; foreach ($ca['lang'] as $ophone => $amount) { $percent = (int)($ca['langprev'][$ophone]) ? number_format((100 * $amount / $ca['langprev'][$ophone]) - 100, 1, '.', ' ') : '∞'; $this->_html .= ' '; } $this->_html .= '
'.$this->l('Customers').''.$this->l('Sales').''.$this->l('%').''.$this->l('Growth').'
'.$ophone.' '.Tools::displayPrice($amount, $currency).' '.($ca['ventil']['total'] ? number_format((100 * $amount / $ca['ventil']['total']), 1, '.', ' ').'%' : '-').' '.(($percent > 0 OR $percent == '∞') ? '' : ' ').' '.(($percent > 0 OR $percent == '∞') ? '+' : '').$percent.'%
 
'.$this->l('Zone distribution').' '; foreach ($ca['zones'] as $zone) $this->_html .= ' '; $this->_html .= '
'.$this->l('Zone').''.$this->l('Count').''.$this->l('Total').''.$this->l('% Count').''.$this->l('% Sales').'
'.(isset($zone['name']) ? $zone['name'] : $this->l('Undefined')).' '.(int)($zone['nb']).' '.Tools::displayPrice($zone['total'], $currency).' '.($ca['ventil']['nb'] ? number_format((100 * $zone['nb'] / $ca['ventil']['nb']), 1, '.', ' ') : '0').'% '.($ca['ventil']['total'] ? number_format((100 * $zone['total'] / $ca['ventil']['total']), 1, '.', ' ') : '0').'%
 
'.$this->l('Currency distribution').'
'.$this->l('Zone:').'
'; foreach ($ca['currencies'] as $currencyRow) $this->_html .= ' '; $this->_html .= '
'.$this->l('Currency').''.$this->l('Count').''.$this->l('Sales (converted)').''.$this->l('% Count').''.$this->l('% Sales').'
'.$currencyRow['name'].' '.(int)($currencyRow['nb']).' '.Tools::displayPrice($currencyRow['total'], $currency).' '.($ca['ventil']['nb'] ? number_format((100 * $currencyRow['nb'] / $ca['ventil']['nb']), 1, '.', ' ') : '0').'% '.($ca['ventil']['total'] ? number_format((100 * $currencyRow['total'] / $ca['ventil']['total']), 1, '.', ' ') : '0').'%
 
'.$this->l('Attribute distribution').' '; foreach ($ca['attributes'] as $attribut) $this->_html .= ' '; $this->_html .= '
'.$this->l('Group').''.$this->l('Attribute').''.$this->l('Count').'
'.$attribut['gname'].' '.$attribut['aname'].' '.(int)($attribut['total']).'
'; return $this->_html; } private function getRealCA() { global $cookie; $employee = new Employee($cookie->id_employee); if ((int)$cookie->stats_id_zone) { $join = ' LEFT JOIN `'._DB_PREFIX_.'address` a ON o.id_address_invoice = a.id_address LEFT JOIN `'._DB_PREFIX_.'country` co ON co.id_country = a.id_country'; $where = ' AND co.id_zone = '.$cookie->stats_id_zone.' '; } $ca = array(); $ca['cat'] = Db::getInstance()->ExecuteS(' SELECT SUM(od.`product_price` * od.`product_quantity` / o.conversion_rate) as orderSum, COUNT(*) AS orderQty, cl.name, AVG(od.`product_price` / o.conversion_rate) as priveAvg FROM `'._DB_PREFIX_.'orders` o LEFT JOIN `'._DB_PREFIX_.'order_detail` od ON o.id_order = od.id_order LEFT JOIN `'._DB_PREFIX_.'product` p ON p.id_product = od.product_id LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (p.id_category_default = cl.id_category AND cl.id_lang = '.(int)($cookie->id_lang).') '.((int)$cookie->stats_id_zone ? $join : '').' WHERE o.valid = 1 AND o.`invoice_date` BETWEEN '.ModuleGraph::getDateBetween().' '.((int)$cookie->stats_id_zone ? $where : '').' GROUP BY p.id_category_default'); uasort($ca['cat'], 'statsforecast_sort'); $langValues = ''; $languages = Db::getInstance()->ExecuteS('SELECT id_lang, iso_code FROM `'._DB_PREFIX_.'lang` WHERE active = 1'); foreach ($languages as $language) $langValues .= 'SUM(IF(o.id_lang = '.(int)$language['id_lang'].', total_products / o.conversion_rate, 0)) as '.pSQL($language['iso_code']).','; $langValues = rtrim($langValues, ','); $ca['lang'] = Db::getInstance()->getRow(' SELECT '.$langValues.' FROM `'._DB_PREFIX_.'orders` o WHERE o.valid = 1 AND o.`invoice_date` BETWEEN '.ModuleGraph::getDateBetween()); arsort($ca['lang']); $ca['langprev'] = Db::getInstance()->getRow(' SELECT '.$langValues.' FROM `'._DB_PREFIX_.'orders` o WHERE o.valid = 1 AND ADDDATE(o.`invoice_date`, interval 30 day) BETWEEN \''.$employee->stats_date_from.' 00:00:00\' AND \''.min(date('Y-m-d H:i:s'), $employee->stats_date_to.' 23:59:59').'\''); $ca['payment'] = Db::getInstance()->ExecuteS(' SELECT module, SUM(total_products / o.conversion_rate) as total, COUNT(*) as nb, AVG(total_products / o.conversion_rate) as cart FROM `'._DB_PREFIX_.'orders` o '.((int)$cookie->stats_id_zone ? $join : '').' WHERE o.valid = 1 AND o.`invoice_date` BETWEEN '.ModuleGraph::getDateBetween().' '.((int)$cookie->stats_id_zone ? $where : '').' GROUP BY o.module ORDER BY total DESC'); $ca['zones'] = Db::getInstance()->ExecuteS(' SELECT z.name, SUM(o.total_products / o.conversion_rate) as total, COUNT(*) as nb FROM `'._DB_PREFIX_.'orders` o LEFT JOIN `'._DB_PREFIX_.'address` a ON o.id_address_invoice = a.id_address LEFT JOIN `'._DB_PREFIX_.'country` c ON c.id_country = a.id_country LEFT JOIN `'._DB_PREFIX_.'zone` z ON z.id_zone = c.id_zone WHERE o.valid = 1 AND o.`invoice_date` BETWEEN '.ModuleGraph::getDateBetween().' GROUP BY c.id_zone ORDER BY total DESC'); $ca['currencies'] = Db::getInstance()->ExecuteS(' SELECT cu.name, SUM(o.total_products / o.conversion_rate) as total, COUNT(*) as nb FROM `'._DB_PREFIX_.'orders` o LEFT JOIN `'._DB_PREFIX_.'currency` cu ON o.id_currency = cu.id_currency '.((int)$cookie->stats_id_zone ? $join : '').' WHERE o.valid = 1 AND o.`invoice_date` BETWEEN '.ModuleGraph::getDateBetween().' '.((int)$cookie->stats_id_zone ? $where : '').' GROUP BY o.id_currency ORDER BY total DESC'); $ca['ventil'] = Db::getInstance()->getRow(' SELECT SUM(total_products / o.conversion_rate) as total, COUNT(*) AS nb FROM `'._DB_PREFIX_.'orders` o WHERE o.valid = 1 AND o.`invoice_date` BETWEEN '.ModuleGraph::getDateBetween()); $ca['attributes'] = Db::getInstance()->ExecuteS(' SELECT /*pac.id_attribute,*/ agl.name as gname, al.name as aname, COUNT(*) as total FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'order_detail od ON o.id_order = od.id_order INNER JOIN '._DB_PREFIX_.'product_attribute_combination pac ON od.product_attribute_id = pac.id_product_attribute INNER JOIN '._DB_PREFIX_.'attribute a ON pac.id_attribute = a.id_attribute INNER JOIN '._DB_PREFIX_.'attribute_group_lang agl ON (a.id_attribute_group = agl.id_attribute_group AND agl.id_lang = '.(int)($cookie->id_lang).') INNER JOIN '._DB_PREFIX_.'attribute_lang al ON (a.id_attribute = al.id_attribute AND al.id_lang = '.(int)($cookie->id_lang).') WHERE o.valid = 1 AND o.`invoice_date` BETWEEN '.ModuleGraph::getDateBetween().' GROUP BY pac.id_attribute'); return $ca; } } function statsforecast_sort($a, $b) { if ($a['orderSum'] == $b['orderSum']) return 0; return ($a['orderSum'] > $b['orderSum']) ? -1 : 1; } ?>