PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/app/code/core/Mage/Sales/Model/Resource/Report/Bestsellers/Collection.php

https://bitbucket.org/kdms/sh-magento
PHP | 371 lines | 232 code | 40 blank | 99 comment | 66 complexity | bcda810663ed2d7d54019f1f1861349b MD5 | raw file
  1. <?php
  2. /**
  3. * Magento Enterprise Edition
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Magento Enterprise Edition License
  8. * that is bundled with this package in the file LICENSE_EE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://www.magentocommerce.com/license/enterprise-edition
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Sales
  23. * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://www.magentocommerce.com/license/enterprise-edition
  25. */
  26. /**
  27. * Report bestsellers collection
  28. *
  29. * @category Mage
  30. * @package Mage_Sales
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_Sales_Model_Resource_Report_Bestsellers_Collection
  34. extends Mage_Sales_Model_Resource_Report_Collection_Abstract
  35. {
  36. /**
  37. * Rating limit
  38. *
  39. * @var int
  40. */
  41. protected $_ratingLimit = 5;
  42. /**
  43. * Columns for select
  44. *
  45. * @var array
  46. */
  47. protected $_selectedColumns = array();
  48. /**
  49. * Initialize custom resource model
  50. *
  51. */
  52. public function __construct()
  53. {
  54. parent::_construct();
  55. $this->setModel('adminhtml/report_item');
  56. $this->_resource = Mage::getResourceModel('sales/report')->init('sales/bestsellers_aggregated_daily');
  57. $this->setConnection($this->getResource()->getReadConnection());
  58. // overwrite default behaviour
  59. $this->_applyFilters = false;
  60. }
  61. /**
  62. * Retrieve columns for select
  63. *
  64. * @return array
  65. */
  66. protected function _getSelectedColumns()
  67. {
  68. $adapter = $this->getConnection();
  69. if (!$this->_selectedColumns) {
  70. if ($this->isTotals()) {
  71. $this->_selectedColumns = $this->getAggregatedColumns();
  72. } else {
  73. $this->_selectedColumns = array(
  74. 'period' => sprintf('MAX(%s)', $adapter->getDateFormatSql('period', '%Y-%m-%d')),
  75. 'qty_ordered' => 'SUM(qty_ordered)',
  76. 'product_id' => 'product_id',
  77. 'product_name' => 'MAX(product_name)',
  78. 'product_price' => 'MAX(product_price)',
  79. );
  80. if ('year' == $this->_period) {
  81. $this->_selectedColumns['period'] = $adapter->getDateFormatSql('period', '%Y');
  82. } elseif ('month' == $this->_period) {
  83. $this->_selectedColumns['period'] = $adapter->getDateFormatSql('period', '%Y-%m');
  84. }
  85. }
  86. }
  87. return $this->_selectedColumns;
  88. }
  89. /**
  90. * Make select object for date boundary
  91. *
  92. * @param mixed $from
  93. * @param mixed $to
  94. * @return Zend_Db_Select
  95. */
  96. protected function _makeBoundarySelect($from, $to)
  97. {
  98. $adapter = $this->getConnection();
  99. $cols = $this->_getSelectedColumns();
  100. $cols['qty_ordered'] = 'SUM(qty_ordered)';
  101. $sel = $adapter->select()
  102. ->from($this->getResource()->getMainTable(), $cols)
  103. ->where('period >= ?', $from)
  104. ->where('period <= ?', $to)
  105. ->group('product_id')
  106. ->order('qty_ordered DESC')
  107. ->limit($this->_ratingLimit);
  108. $this->_applyStoresFilterToSelect($sel);
  109. return $sel;
  110. }
  111. /**
  112. * Add selected data
  113. *
  114. * @return Mage_Sales_Model_Resource_Report_Bestsellers_Collection
  115. */
  116. protected function _initSelect()
  117. {
  118. $select = $this->getSelect();
  119. // if grouping by product, not by period
  120. if (!$this->_period) {
  121. $cols = $this->_getSelectedColumns();
  122. $cols['qty_ordered'] = 'SUM(qty_ordered)';
  123. if ($this->_from || $this->_to) {
  124. $mainTable = $this->getTable('sales/bestsellers_aggregated_daily');
  125. $select->from($mainTable, $cols);
  126. } else {
  127. $mainTable = $this->getTable('sales/bestsellers_aggregated_yearly');
  128. $select->from($mainTable, $cols);
  129. }
  130. //exclude removed products
  131. $subSelect = $this->getConnection()->select();
  132. $subSelect->from(array('existed_products' => $this->getTable('catalog/product')), new Zend_Db_Expr('1)'));
  133. $select->exists($subSelect, $mainTable . '.product_id = existed_products.entity_id')
  134. ->group('product_id')
  135. ->order('qty_ordered ' . Varien_Db_Select::SQL_DESC)
  136. ->limit($this->_ratingLimit);
  137. return $this;
  138. }
  139. if ('year' == $this->_period) {
  140. $mainTable = $this->getTable('sales/bestsellers_aggregated_yearly');
  141. $select->from($mainTable, $this->_getSelectedColumns());
  142. } elseif ('month' == $this->_period) {
  143. $mainTable = $this->getTable('sales/bestsellers_aggregated_monthly');
  144. $select->from($mainTable, $this->_getSelectedColumns());
  145. } else {
  146. $mainTable = $this->getTable('sales/bestsellers_aggregated_daily');
  147. $select->from($mainTable, $this->_getSelectedColumns());
  148. }
  149. if (!$this->isTotals()) {
  150. $select->group(array('period', 'product_id'));
  151. }
  152. $select->where('rating_pos <= ?', $this->_ratingLimit);
  153. return $this;
  154. }
  155. /**
  156. * Get SQL for get record count
  157. *
  158. * @return Varien_Db_Select
  159. */
  160. public function getSelectCountSql()
  161. {
  162. $this->_renderFilters();
  163. $select = clone $this->getSelect();
  164. $select->reset(Zend_Db_Select::ORDER);
  165. return $this->getConnection()->select()->from($select, 'COUNT(*)');
  166. }
  167. /**
  168. * Set ids for store restrictions
  169. *
  170. * @param array $storeIds
  171. * @return Mage_Sales_Model_Resource_Report_Bestsellers_Collection
  172. */
  173. public function addStoreRestrictions($storeIds)
  174. {
  175. if (!is_array($storeIds)) {
  176. $storeIds = array($storeIds);
  177. }
  178. $currentStoreIds = $this->_storesIds;
  179. if (isset($currentStoreIds) && $currentStoreIds != Mage_Core_Model_App::ADMIN_STORE_ID
  180. && $currentStoreIds != array(Mage_Core_Model_App::ADMIN_STORE_ID)) {
  181. if (!is_array($currentStoreIds)) {
  182. $currentStoreIds = array($currentStoreIds);
  183. }
  184. $this->_storesIds = array_intersect($currentStoreIds, $storeIds);
  185. } else {
  186. $this->_storesIds = $storeIds;
  187. }
  188. return $this;
  189. }
  190. /**
  191. * Redeclare parent method for applying filters after parent method
  192. * but before adding unions and calculating totals
  193. *
  194. * @return Mage_Sales_Model_Resource_Report_Bestsellers_Collection
  195. */
  196. protected function _beforeLoad()
  197. {
  198. parent::_beforeLoad();
  199. $this->_applyStoresFilter();
  200. if ($this->_period) {
  201. //
  202. $selectUnions = array();
  203. // apply date boundaries (before calling $this->_applyDateRangeFilter())
  204. $dtFormat = Varien_Date::DATE_INTERNAL_FORMAT;
  205. $periodFrom = (!is_null($this->_from) ? new Zend_Date($this->_from, $dtFormat) : null);
  206. $periodTo = (!is_null($this->_to) ? new Zend_Date($this->_to, $dtFormat) : null);
  207. if ('year' == $this->_period) {
  208. if ($periodFrom) {
  209. // not the first day of the year
  210. if ($periodFrom->toValue(Zend_Date::MONTH) != 1 || $periodFrom->toValue(Zend_Date::DAY) != 1) {
  211. $dtFrom = $periodFrom->getDate();
  212. // last day of the year
  213. $dtTo = $periodFrom->getDate()->setMonth(12)->setDay(31);
  214. if (!$periodTo || $dtTo->isEarlier($periodTo)) {
  215. $selectUnions[] = $this->_makeBoundarySelect(
  216. $dtFrom->toString($dtFormat),
  217. $dtTo->toString($dtFormat)
  218. );
  219. // first day of the next year
  220. $this->_from = $periodFrom->getDate()
  221. ->addYear(1)
  222. ->setMonth(1)
  223. ->setDay(1)
  224. ->toString($dtFormat);
  225. }
  226. }
  227. }
  228. if ($periodTo) {
  229. // not the last day of the year
  230. if ($periodTo->toValue(Zend_Date::MONTH) != 12 || $periodTo->toValue(Zend_Date::DAY) != 31) {
  231. $dtFrom = $periodTo->getDate()->setMonth(1)->setDay(1); // first day of the year
  232. $dtTo = $periodTo->getDate();
  233. if (!$periodFrom || $dtFrom->isLater($periodFrom)) {
  234. $selectUnions[] = $this->_makeBoundarySelect(
  235. $dtFrom->toString($dtFormat),
  236. $dtTo->toString($dtFormat)
  237. );
  238. // last day of the previous year
  239. $this->_to = $periodTo->getDate()
  240. ->subYear(1)
  241. ->setMonth(12)
  242. ->setDay(31)
  243. ->toString($dtFormat);
  244. }
  245. }
  246. }
  247. if ($periodFrom && $periodTo) {
  248. // the same year
  249. if ($periodFrom->toValue(Zend_Date::YEAR) == $periodTo->toValue(Zend_Date::YEAR)) {
  250. $dtFrom = $periodFrom->getDate();
  251. $dtTo = $periodTo->getDate();
  252. $selectUnions[] = $this->_makeBoundarySelect(
  253. $dtFrom->toString($dtFormat),
  254. $dtTo->toString($dtFormat)
  255. );
  256. $this->getSelect()->where('1<>1');
  257. }
  258. }
  259. }
  260. else if ('month' == $this->_period) {
  261. if ($periodFrom) {
  262. // not the first day of the month
  263. if ($periodFrom->toValue(Zend_Date::DAY) != 1) {
  264. $dtFrom = $periodFrom->getDate();
  265. // last day of the month
  266. $dtTo = $periodFrom->getDate()->addMonth(1)->setDay(1)->subDay(1);
  267. if (!$periodTo || $dtTo->isEarlier($periodTo)) {
  268. $selectUnions[] = $this->_makeBoundarySelect(
  269. $dtFrom->toString($dtFormat),
  270. $dtTo->toString($dtFormat)
  271. );
  272. // first day of the next month
  273. $this->_from = $periodFrom->getDate()->addMonth(1)->setDay(1)->toString($dtFormat);
  274. }
  275. }
  276. }
  277. if ($periodTo) {
  278. // not the last day of the month
  279. if ($periodTo->toValue(Zend_Date::DAY) != $periodTo->toValue(Zend_Date::MONTH_DAYS)) {
  280. $dtFrom = $periodTo->getDate()->setDay(1); // first day of the month
  281. $dtTo = $periodTo->getDate();
  282. if (!$periodFrom || $dtFrom->isLater($periodFrom)) {
  283. $selectUnions[] = $this->_makeBoundarySelect(
  284. $dtFrom->toString($dtFormat),
  285. $dtTo->toString($dtFormat)
  286. );
  287. // last day of the previous month
  288. $this->_to = $periodTo->getDate()->setDay(1)->subDay(1)->toString($dtFormat);
  289. }
  290. }
  291. }
  292. if ($periodFrom && $periodTo) {
  293. // the same month
  294. if ($periodFrom->toValue(Zend_Date::YEAR) == $periodTo->toValue(Zend_Date::YEAR)
  295. && $periodFrom->toValue(Zend_Date::MONTH) == $periodTo->toValue(Zend_Date::MONTH)
  296. ) {
  297. $dtFrom = $periodFrom->getDate();
  298. $dtTo = $periodTo->getDate();
  299. $selectUnions[] = $this->_makeBoundarySelect(
  300. $dtFrom->toString($dtFormat),
  301. $dtTo->toString($dtFormat)
  302. );
  303. $this->getSelect()->where('1<>1');
  304. }
  305. }
  306. }
  307. $this->_applyDateRangeFilter();
  308. // add unions to select
  309. if ($selectUnions) {
  310. $unionParts = array();
  311. $cloneSelect = clone $this->getSelect();
  312. $helper = Mage::getResourceHelper('core');
  313. $unionParts[] = '(' . $cloneSelect . ')';
  314. foreach ($selectUnions as $union) {
  315. $query = $helper->getQueryUsingAnalyticFunction($union);
  316. $unionParts[] = '(' . $query . ')';
  317. }
  318. $this->getSelect()->reset()->union($unionParts, Zend_Db_Select::SQL_UNION_ALL);
  319. }
  320. if ($this->isTotals()) {
  321. // calculate total
  322. $cloneSelect = clone $this->getSelect();
  323. $this->getSelect()->reset()->from($cloneSelect, $this->getAggregatedColumns());
  324. } else {
  325. // add sorting
  326. $this->getSelect()->order(array('period ASC', 'qty_ordered DESC'));
  327. }
  328. }
  329. return $this;
  330. }
  331. }