PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/controllers/admin/AdminStockCoverController.php

https://github.com/netplayer/PrestaShop
PHP | 398 lines | 287 code | 42 blank | 69 comment | 38 complexity | 0b30b5d4c271b76a36ad7dc64ae16176 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /*
  3. * 2007-2014 PrestaShop
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  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@prestashop.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 PrestaShop to newer
  18. * versions in the future. If you wish to customize PrestaShop for your
  19. * needs please refer to http://www.prestashop.com for more information.
  20. *
  21. * @author PrestaShop SA <contact@prestashop.com>
  22. * @copyright 2007-2014 PrestaShop SA
  23. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  24. * International Registered Trademark & Property of PrestaShop SA
  25. */
  26. /**
  27. * @since 1.5.0
  28. */
  29. class AdminStockCoverControllerCore extends AdminController
  30. {
  31. protected $stock_cover_warehouses;
  32. protected $stock_cover_periods;
  33. public function __construct()
  34. {
  35. $this->bootstrap = true;
  36. $this->context = Context::getContext();
  37. $this->table = 'product';
  38. $this->className = 'Product';
  39. $this->list_id = 'product';
  40. $this->lang = true;
  41. $this->colorOnBackground = true;
  42. $this->multishop_context = Shop::CONTEXT_ALL;
  43. $this->tpl_list_vars['show_filter'] = true;
  44. $this->fields_list = array(
  45. 'reference' => array(
  46. 'title' => $this->l('Reference'),
  47. 'align' => 'center',
  48. 'filter_key' => 'a!reference'
  49. ),
  50. 'ean13' => array(
  51. 'title' => $this->l('EAN13'),
  52. 'align' => 'center',
  53. 'filter_key' => 'a!ean13'
  54. ),
  55. 'upc' => array(
  56. 'title' => $this->l('UPC'),
  57. 'align' => 'center',
  58. 'filter_key' => 'a!upc'
  59. ),
  60. 'name' => array(
  61. 'title' => $this->l('Name'),
  62. 'filter_key' => 'b!name'
  63. ),
  64. 'qty_sold' => array(
  65. 'title' => $this->l('Quantity sold'),
  66. 'orderby' => false,
  67. 'search' => false,
  68. 'hint' => $this->l('Quantity sold during the defined period.'),
  69. ),
  70. 'coverage' => array(
  71. 'title' => $this->l('Coverage'),
  72. 'orderby' => false,
  73. 'search' => false,
  74. 'hint' => $this->l('Days left before your stock runs out.'),
  75. ),
  76. 'stock' => array(
  77. 'title' => $this->l('Quantity'),
  78. 'orderby' => false,
  79. 'search' => false,
  80. 'hint' => $this->l('Physical (usable) quantity.')
  81. ),
  82. );
  83. // pre-defines coverage periods
  84. $this->stock_cover_periods = array(
  85. $this->l('One week') => 7,
  86. $this->l('Two weeks') => 14,
  87. $this->l('Three weeks') => 21,
  88. $this->l('One month') => 31,
  89. $this->l('Six months') => 186,
  90. $this->l('One year') => 365
  91. );
  92. // gets the list of warehouses available
  93. $this->stock_cover_warehouses = Warehouse::getWarehouses(true);
  94. // gets the final list of warehouses
  95. array_unshift($this->stock_cover_warehouses, array('id_warehouse' => -1, 'name' => $this->l('All Warehouses')));
  96. parent::__construct();
  97. }
  98. public function initPageHeaderToolbar()
  99. {
  100. $this->page_header_toolbar_title = $this->l('Stock coverage');
  101. if ($this->display == 'details')
  102. $this->page_header_toolbar_btn['back_to_list'] = array(
  103. 'href' => Context::getContext()->link->getAdminLink('AdminStockCover')
  104. .(Tools::getValue('coverage_period') ? '&coverage_period='.Tools::getValue('coverage_period') : '')
  105. .(Tools::getValue('warn_days') ? '&warn_days='.Tools::getValue('warn_days') : '')
  106. .(Tools::getValue('id_warehouse') ? '&id_warehouse='.Tools::getValue('id_warehouse') : ''),
  107. 'desc' => $this->l('Back to list', null, null, false),
  108. 'icon' => 'process-icon-back'
  109. );
  110. parent::initPageHeaderToolbar();
  111. }
  112. public function renderDetails()
  113. {
  114. if (Tools::isSubmit('id_product')) // if a product id is submit
  115. {
  116. $this->lang = false;
  117. $this->list_id = 'details';
  118. $this->tpl_list_vars['show_filter'] = false;
  119. $this->actions = array();
  120. $this->list_simple_header = true;
  121. $this->table = 'product_attribute';
  122. $lang_id = (int)$this->context->language->id;
  123. $id_product = (int)Tools::getValue('id_product');
  124. $period = (Tools::getValue('period') ? (int)Tools::getValue('period') : 7);
  125. $warehouse = Tools::getValue('id_warehouse', -1);
  126. $where_warehouse = '';
  127. if ($warehouse != -1)
  128. $where_warehouse = ' AND s.id_warehouse = '.(int)$warehouse;
  129. $this->_select = 'a.id_product_attribute as id, a.id_product, stock_view.reference, stock_view.ean13,
  130. stock_view.upc, stock_view.usable_quantity as stock';
  131. $this->_join = ' INNER JOIN
  132. (
  133. SELECT SUM(s.usable_quantity) as usable_quantity, s.id_product_attribute, s.reference, s.ean13, s.upc
  134. FROM '._DB_PREFIX_.'stock s
  135. WHERE s.id_product = '.($id_product).
  136. $where_warehouse.'
  137. GROUP BY s.id_product_attribute
  138. )
  139. stock_view ON (stock_view.id_product_attribute = a.id_product_attribute)';
  140. $this->_where = 'AND a.id_product = '.$id_product;
  141. $this->_groupBy = 'a.id_product_attribute';
  142. return parent::renderList();
  143. }
  144. }
  145. /**
  146. * AdminController::renderList() override
  147. * @see AdminController::renderList()
  148. */
  149. public function renderList()
  150. {
  151. $this->addRowAction('details');
  152. $this->toolbar_btn = array();
  153. // disables link
  154. $this->list_no_link = true;
  155. // query
  156. $this->_select = 'a.id_product as id, COUNT(pa.id_product_attribute) as variations, SUM(s.usable_quantity) as stock';
  157. $this->_join = 'LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (pa.id_product = a.id_product)
  158. '.Shop::addSqlAssociation('product_attribute', 'pa', false).'
  159. INNER JOIN `'._DB_PREFIX_.'stock` s ON (s.id_product = a.id_product)';
  160. $this->_group = 'GROUP BY a.id_product';
  161. self::$currentIndex .= '&coverage_period='.(int)$this->getCurrentCoveragePeriod().'&warn_days='.(int)$this->getCurrentWarning();
  162. if ($this->getCurrentCoverageWarehouse() != -1)
  163. {
  164. $this->_where .= ' AND s.id_warehouse = '.(int)$this->getCurrentCoverageWarehouse();
  165. self::$currentIndex .= '&id_warehouse='.(int)$this->getCurrentCoverageWarehouse();
  166. }
  167. // Hack for multi shop ..
  168. $this->_where .= ' AND b.id_shop = 1';
  169. $this->tpl_list_vars['stock_cover_periods'] = $this->stock_cover_periods;
  170. $this->tpl_list_vars['stock_cover_cur_period'] = $this->getCurrentCoveragePeriod();
  171. $this->tpl_list_vars['stock_cover_warehouses'] = $this->stock_cover_warehouses;
  172. $this->tpl_list_vars['stock_cover_cur_warehouse'] = $this->getCurrentCoverageWarehouse();
  173. $this->tpl_list_vars['stock_cover_warn_days'] = $this->getCurrentWarning();
  174. $this->ajax_params = array(
  175. 'period' => $this->getCurrentCoveragePeriod(),
  176. 'id_warehouse' => $this->getCurrentCoverageWarehouse(),
  177. 'warn_days' => $this->getCurrentWarning()
  178. );
  179. $this->displayInformation($this->l('Considering the coverage period chosen and the quantity of products/combinations that you sold.'));
  180. $this->displayInformation($this->l('This interface gives you an idea of when a product will run out of stock.'));
  181. return parent::renderList();
  182. }
  183. /**
  184. * AdminController::getList() override
  185. * @see AdminController::getList()
  186. */
  187. public function getList($id_lang, $order_by = null, $order_way = null, $start = 0, $limit = null, $id_lang_shop = false)
  188. {
  189. parent::getList($id_lang, $order_by, $order_way, $start, $limit, $id_lang_shop);
  190. if ($this->display == 'details')
  191. {
  192. $nb_items = count($this->_list);
  193. for ($i = 0; $i < $nb_items; ++$i)
  194. {
  195. $item = &$this->_list[$i];
  196. $item['name'] = Product::getProductName($item['id_product'], $item['id']);
  197. // computes coverage
  198. $coverage = StockManagerFactory::getManager()->getProductCoverage(
  199. $item['id_product'],
  200. $item['id'],
  201. (Tools::getValue('period') ? (int)Tools::getValue('period') : 7),
  202. (($this->getCurrentCoverageWarehouse() == -1) ? null : Tools::getValue('id_warehouse', -1))
  203. );
  204. if ($coverage != -1) // if coverage is available
  205. {
  206. if ($coverage < $this->getCurrentWarning()) // if highlight needed
  207. $item['color'] = '#BDE5F8';
  208. $item['coverage'] = $coverage;
  209. }
  210. else // infinity
  211. $item['coverage'] = '--';
  212. // computes quantity sold
  213. $qty_sold = $this->getQuantitySold($item['id_product'], $item['id'], $this->getCurrentCoveragePeriod());
  214. if (!$qty_sold)
  215. $item['qty_sold'] = '--';
  216. else
  217. $item['qty_sold'] = $qty_sold;
  218. }
  219. }
  220. else
  221. {
  222. $nb_items = count($this->_list);
  223. for ($i = 0; $i < $nb_items; ++$i)
  224. {
  225. $item = &$this->_list[$i];
  226. if (array_key_exists('variations', $item) && (int)$item['variations'] <= 0)
  227. {
  228. // computes coverage and displays (highlights if needed)
  229. $coverage = StockManagerFactory::getManager()->getProductCoverage(
  230. $item['id'],
  231. 0,
  232. $this->getCurrentCoveragePeriod(),
  233. (($this->getCurrentCoverageWarehouse() == -1) ? null : $this->getCurrentCoverageWarehouse())
  234. );
  235. if ($coverage != -1) // coverage is available
  236. {
  237. if ($coverage < $this->getCurrentWarning())
  238. $item['color'] = '#BDE5F8';
  239. $item['coverage'] = $coverage;
  240. }
  241. else // infinity
  242. $item['coverage'] = '--';
  243. // computes quantity sold
  244. $qty_sold = $this->getQuantitySold($item['id'], 0, $this->getCurrentCoveragePeriod());
  245. if (!$qty_sold)
  246. $item['qty_sold'] = '--';
  247. else
  248. $item['qty_sold'] = $qty_sold;
  249. // removes 'details' action on products without attributes
  250. $this->addRowActionSkipList('details', array($item['id']));
  251. }
  252. else
  253. {
  254. $item['stock'] = $this->l('See details');
  255. $item['reference'] = '--';
  256. $item['ean13'] = '--';
  257. $item['upc'] = '--';
  258. }
  259. }
  260. }
  261. }
  262. /**
  263. * Gets the current coverage period used
  264. *
  265. * @return int coverage period
  266. */
  267. protected function getCurrentCoveragePeriod()
  268. {
  269. static $coverage_period = 0;
  270. if ($coverage_period == 0)
  271. {
  272. $coverage_period = 7; // Week by default
  273. if ((int)Tools::getValue('coverage_period'))
  274. $coverage_period = (int)Tools::getValue('coverage_period');
  275. }
  276. return $coverage_period;
  277. }
  278. /**
  279. * Gets the current warehouse used
  280. *
  281. * @return int id_warehouse
  282. */
  283. protected function getCurrentCoverageWarehouse()
  284. {
  285. static $warehouse = 0;
  286. if ($warehouse == 0)
  287. {
  288. $warehouse = -1; // all warehouses
  289. if ((int)Tools::getValue('id_warehouse'))
  290. $warehouse = (int)Tools::getValue('id_warehouse');
  291. }
  292. return $warehouse;
  293. }
  294. /**
  295. * Gets the current warning
  296. *
  297. * @return int warn_days
  298. */
  299. protected function getCurrentWarning()
  300. {
  301. static $warning = 0;
  302. if ($warning == 0)
  303. {
  304. $warning = 0;
  305. if (Tools::getValue('warn_days') && Validate::isInt(Tools::getValue('warn_days')))
  306. $warning = (int)Tools::getValue('warn_days');
  307. }
  308. return $warning;
  309. }
  310. /**
  311. * For a given product, and a given period, returns the quantity sold
  312. *
  313. * @param int $id_product
  314. * @param int $id_product_attribute
  315. * @param int $coverage
  316. * @return int $quantity
  317. */
  318. protected function getQuantitySold($id_product, $id_product_attribute, $coverage)
  319. {
  320. $query = new DbQuery();
  321. $query->select('SUM(od.product_quantity)');
  322. $query->from('order_detail', 'od');
  323. $query->leftJoin('orders', 'o', 'od.id_order = o.id_order');
  324. $query->leftJoin('order_history', 'oh', 'o.date_upd = oh.date_add');
  325. $query->leftJoin('order_state', 'os', 'os.id_order_state = oh.id_order_state');
  326. $query->where('od.product_id = '.(int)$id_product);
  327. $query->where('od.product_attribute_id = '.(int)$id_product_attribute);
  328. $query->where('TO_DAYS(NOW()) - TO_DAYS(oh.date_add) <= '.(int)$coverage);
  329. $query->where('o.valid = 1');
  330. $query->where('os.logable = 1 AND os.delivery = 1 AND os.shipped = 1');
  331. $quantity = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
  332. return $quantity;
  333. }
  334. public function initContent()
  335. {
  336. if (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'))
  337. {
  338. $this->warnings[md5('PS_ADVANCED_STOCK_MANAGEMENT')] = $this->l('You need to activate advanced stock management before using this feature.');
  339. return false;
  340. }
  341. parent::initContent();
  342. }
  343. public function initProcess()
  344. {
  345. if (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'))
  346. {
  347. $this->warnings[md5('PS_ADVANCED_STOCK_MANAGEMENT')] = $this->l('You need to activate advanced stock management before using this feature.');
  348. return false;
  349. }
  350. if (Tools::isSubmit('detailsproduct'))
  351. $this->list_id = 'details';
  352. else
  353. $this->list_id = 'product';
  354. parent::initProcess();
  355. }
  356. }