PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/controllers/admin/AdminStockInstantStateController.php

https://github.com/netplayer/PrestaShop
PHP | 532 lines | 381 code | 67 blank | 84 comment | 54 complexity | ab5230c8d7650675503cfb36f74eda42 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 AdminStockInstantStateControllerCore extends AdminController
  30. {
  31. protected $stock_instant_state_warehouses = array();
  32. public function __construct()
  33. {
  34. $this->bootstrap = true;
  35. $this->context = Context::getContext();
  36. $this->table = 'stock';
  37. $this->list_id = 'stock';
  38. $this->className = 'Stock';
  39. $this->tpl_list_vars['show_filter'] = true;
  40. $this->lang = false;
  41. $this->multishop_context = Shop::CONTEXT_ALL;
  42. $this->fields_list = array(
  43. 'reference' => array(
  44. 'title' => $this->l('Reference'),
  45. 'align' => 'center',
  46. 'havingFilter' => true
  47. ),
  48. 'ean13' => array(
  49. 'title' => $this->l('EAN13'),
  50. 'align' => 'center',
  51. ),
  52. 'upc' => array(
  53. 'title' => $this->l('UPC'),
  54. 'align' => 'center',
  55. ),
  56. 'name' => array(
  57. 'title' => $this->l('Name'),
  58. 'havingFilter' => true
  59. ),
  60. 'price_te' => array(
  61. 'title' => $this->l('Price (tax excl.)'),
  62. 'orderby' => true,
  63. 'search' => false,
  64. 'type' => 'price',
  65. 'currency' => true,
  66. ),
  67. 'valuation' => array(
  68. 'title' => $this->l('Valuation'),
  69. 'orderby' => false,
  70. 'search' => false,
  71. 'type' => 'price',
  72. 'currency' => true,
  73. 'hint' => $this->l('Total value of the physical quantity. The sum (for all prices) is not available for all warehouses, please filter by warehouse.')
  74. ),
  75. 'physical_quantity' => array(
  76. 'title' => $this->l('Physical quantity'),
  77. 'class' => 'fixed-width-xs',
  78. 'align' => 'center',
  79. 'orderby' => true,
  80. 'search' => false
  81. ),
  82. 'usable_quantity' => array(
  83. 'title' => $this->l('Usable quantity'),
  84. 'class' => 'fixed-width-xs',
  85. 'align' => 'center',
  86. 'orderby' => true,
  87. 'search' => false,
  88. ),
  89. 'real_quantity' => array(
  90. 'title' => $this->l('Real quantity'),
  91. 'class' => 'fixed-width-xs',
  92. 'align' => 'center',
  93. 'orderby' => false,
  94. 'search' => false,
  95. 'hint' => $this->l('Physical quantity (usable) - Client orders + Supply Orders'),
  96. ),
  97. );
  98. $this->addRowAction('details');
  99. $this->stock_instant_state_warehouses = Warehouse::getWarehouses(true);
  100. array_unshift($this->stock_instant_state_warehouses, array('id_warehouse' => -1, 'name' => $this->l('All Warehouses')));
  101. parent::__construct();
  102. }
  103. public function initPageHeaderToolbar()
  104. {
  105. $this->page_header_toolbar_title = $this->l('Instant stock status');
  106. if ($this->display == 'details')
  107. $this->page_header_toolbar_btn['back_to_list'] = array(
  108. 'href' => Context::getContext()->link->getAdminLink('AdminStockInstantState').(Tools::getValue('id_warehouse') ? '&id_warehouse='.Tools::getValue('id_warehouse') : ''),
  109. 'desc' => $this->l('Back to list', null, null, false),
  110. 'icon' => 'process-icon-back'
  111. );
  112. elseif (Tools::isSubmit('id_warehouse') && (int)Tools::getValue('id_warehouse') != -1)
  113. {
  114. $this->page_header_toolbar_btn['export-stock-state-quantities-csv'] = array(
  115. 'short' => $this->l('Export this list as CSV', null, null, false),
  116. 'href' => $this->context->link->getAdminLink('AdminStockInstantState').'&csv_quantities&id_warehouse='.(int)$this->getCurrentCoverageWarehouse(),
  117. 'desc' => $this->l('Export Quantities (CSV)', null, null, false),
  118. 'imgclass' => 'export'
  119. );
  120. $this->page_header_toolbar_btn['export-stock-state-prices-csv'] = array(
  121. 'short' => $this->l('Export this list as CSV', null, null, false),
  122. 'href' => $this->context->link->getAdminLink('AdminStockInstantState').'&csv_prices&id_warehouse='.(int)$this->getCurrentCoverageWarehouse(),
  123. 'desc' => $this->l('Export Prices (CSV)', null, null, false),
  124. 'imgclass' => 'export'
  125. );
  126. }
  127. parent::initPageHeaderToolbar();
  128. }
  129. /**
  130. * AdminController::renderList() override
  131. * @see AdminController::renderList()
  132. */
  133. public function renderList()
  134. {
  135. // query
  136. $this->_select = '
  137. IFNULL(CONCAT(pl.name, \' : \', GROUP_CONCAT(DISTINCT agl.`name`, \' - \', al.name SEPARATOR \', \')),pl.name) as name,
  138. w.id_currency';
  139. $this->_group = 'GROUP BY a.id_product, a.id_product_attribute';
  140. $this->_join = 'LEFT JOIN `'._DB_PREFIX_.'warehouse` w ON (w.id_warehouse = a.id_warehouse)';
  141. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (
  142. a.id_product = pl.id_product
  143. AND pl.id_lang = '.(int)$this->context->language->id.'
  144. )';
  145. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON (pac.id_product_attribute = a.id_product_attribute)';
  146. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'attribute` atr ON (atr.id_attribute = pac.id_attribute)';
  147. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON (
  148. al.id_attribute = pac.id_attribute
  149. AND al.id_lang = '.(int)$this->context->language->id.'
  150. )';
  151. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'attribute_group_lang` agl ON (
  152. agl.id_attribute_group = atr.id_attribute_group
  153. AND agl.id_lang = '.(int)$this->context->language->id.'
  154. )';
  155. if ($this->getCurrentCoverageWarehouse() != -1)
  156. {
  157. $this->_where .= ' AND a.id_warehouse = '.$this->getCurrentCoverageWarehouse();
  158. self::$currentIndex .= '&id_warehouse='.(int)$this->getCurrentCoverageWarehouse();
  159. }
  160. // toolbar btn
  161. $this->toolbar_btn = array();
  162. // disables link
  163. $this->list_no_link = true;
  164. // smarty
  165. $this->tpl_list_vars['stock_instant_state_warehouses'] = $this->stock_instant_state_warehouses;
  166. $this->tpl_list_vars['stock_instant_state_cur_warehouse'] = $this->getCurrentCoverageWarehouse();
  167. // adds ajax params
  168. $this->ajax_params = array('id_warehouse' => $this->getCurrentCoverageWarehouse());
  169. // displays help information
  170. $this->displayInformation($this->l('This interface allows you to display detailed information about your stock per warehouse.'));
  171. // sets toolbar
  172. $this->initToolbar();
  173. $list = parent::renderList();
  174. // if export requested
  175. if ((Tools::isSubmit('csv_quantities') || Tools::isSubmit('csv_prices')) &&
  176. (int)Tools::getValue('id_warehouse') != -1)
  177. {
  178. if (count($this->_list) > 0)
  179. {
  180. $this->renderCSV();
  181. die;
  182. }
  183. else
  184. $this->displayWarning($this->l('There is nothing to export as CSV.'));
  185. }
  186. return $list;
  187. }
  188. public function renderDetails()
  189. {
  190. if (Tools::isSubmit('id_stock')) // if a product id is submit
  191. {
  192. $this->lang = false;
  193. $this->table = 'stock';
  194. $this->list_id = 'details';
  195. $this->tpl_list_vars['show_filter'] = false;
  196. $lang_id = (int)$this->context->language->id;
  197. $this->actions = array();
  198. $this->list_simple_header = true;
  199. $ids = explode('_', Tools::getValue('id_stock'));
  200. if (count($ids) != 2)
  201. die;
  202. $id_product = $ids[0];
  203. $id_product_attribute = $ids[1];
  204. $id_warehouse = Tools::getValue('id_warehouse', -1);
  205. $this->_select = 'IFNULL(CONCAT(pl.name, \' : \', GROUP_CONCAT(DISTINCT agl.`name`, \' - \', al.name SEPARATOR \', \')),pl.name) as name,
  206. w.id_currency, a.price_te, SUM(a.physical_quantity) as physical_quantity, SUM(a.usable_quantity) as usable_quantity,
  207. (a.price_te * SUM(a.physical_quantity)) as valuation';
  208. $this->_join = ' LEFT JOIN `'._DB_PREFIX_.'warehouse` AS w ON w.id_warehouse = a.id_warehouse';
  209. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (
  210. a.id_product = pl.id_product
  211. AND pl.id_lang = '.(int)$this->context->language->id.'
  212. )';
  213. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON (pac.id_product_attribute = a.id_product_attribute)';
  214. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'attribute` atr ON (atr.id_attribute = pac.id_attribute)';
  215. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON (
  216. al.id_attribute = pac.id_attribute
  217. AND al.id_lang = '.(int)$this->context->language->id.'
  218. )';
  219. $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'attribute_group_lang` agl ON (
  220. agl.id_attribute_group = atr.id_attribute_group
  221. AND agl.id_lang = '.(int)$this->context->language->id.'
  222. )';
  223. $this->_where = 'AND a.id_product = '.(int)$id_product.' AND a.id_product_attribute = '.(int)$id_product_attribute;
  224. if ($id_warehouse != -1)
  225. $this->_where .= ' AND a.id_warehouse = '.(int)$id_warehouse;
  226. $this->_groupBy = 'GROUP BY a.price_te';
  227. self::$currentIndex = self::$currentIndex.'&id_stock='.Tools::getValue('id_stock').'&detailsstock';
  228. return parent::renderList();
  229. }
  230. }
  231. /**
  232. * AdminController::getList() override
  233. * @see AdminController::getList()
  234. */
  235. public function getList($id_lang, $order_by = null, $order_way = null, $start = 0, $limit = null, $id_lang_shop = false)
  236. {
  237. if (Tools::isSubmit('id_stock'))
  238. {
  239. parent::getList($id_lang, $order_by, $order_way, $start, $limit, $id_lang_shop);
  240. $nb_items = count($this->_list);
  241. for ($i = 0; $i < $nb_items; $i++)
  242. {
  243. $item = &$this->_list[$i];
  244. $manager = StockManagerFactory::getManager();
  245. $item['real_quantity'] = $manager->getProductRealQuantities(
  246. $item['id_product'],
  247. $item['id_product_attribute'],
  248. ($this->getCurrentCoverageWarehouse() == -1 ? null : array($this->getCurrentCoverageWarehouse())),
  249. true
  250. );
  251. }
  252. }
  253. else
  254. {
  255. if ((Tools::isSubmit('csv_quantities') || Tools::isSubmit('csv_prices')) &&
  256. (int)Tools::getValue('id_warehouse') != -1)
  257. $limit = false;
  258. $order_by_valuation = false;
  259. $order_by_real_quantity = false;
  260. if ($this->context->cookie->{$this->table.'Orderby'} == 'valuation')
  261. {
  262. unset($this->context->cookie->{$this->table.'Orderby'});
  263. $order_by_valuation = true;
  264. }
  265. else if ($this->context->cookie->{$this->table.'Orderby'} == 'real_quantity')
  266. {
  267. unset($this->context->cookie->{$this->table.'Orderby'});
  268. $order_by_real_quantity = true;
  269. }
  270. parent::getList($id_lang, $order_by, $order_way, $start, $limit, $id_lang_shop);
  271. $nb_items = count($this->_list);
  272. for ($i = 0; $i < $nb_items; ++$i)
  273. {
  274. $item = &$this->_list[$i];
  275. $item['price_te'] = '--';
  276. $item[$this->identifier] = $item['id_product'].'_'.$item['id_product_attribute'];
  277. // gets stock manager
  278. $manager = StockManagerFactory::getManager();
  279. // gets quantities and valuation
  280. $query = new DbQuery();
  281. $query->select('SUM(physical_quantity) as physical_quantity');
  282. $query->select('SUM(usable_quantity) as usable_quantity');
  283. $query->select('SUM(price_te * physical_quantity) as valuation');
  284. $query->from('stock');
  285. $query->where('id_product = '.(int)$item['id_product'].' AND id_product_attribute = '.(int)$item['id_product_attribute']);
  286. if ($this->getCurrentCoverageWarehouse() != -1)
  287. $query->where('id_warehouse = '.(int)$this->getCurrentCoverageWarehouse());
  288. $res = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow($query);
  289. $item['physical_quantity'] = $res['physical_quantity'];
  290. $item['usable_quantity'] = $res['usable_quantity'];
  291. // gets real_quantity depending on the warehouse
  292. $item['real_quantity'] = $manager->getProductRealQuantities($item['id_product'],
  293. $item['id_product_attribute'],
  294. ($this->getCurrentCoverageWarehouse() == -1 ? null : array($this->getCurrentCoverageWarehouse())),
  295. true);
  296. // removes the valuation if the filter corresponds to 'all warehouses'
  297. if ($this->getCurrentCoverageWarehouse() == -1)
  298. $item['valuation'] = 'N/A';
  299. else
  300. $item['valuation'] = $res['valuation'];
  301. }
  302. if ($this->getCurrentCoverageWarehouse() != -1 && $order_by_valuation)
  303. usort($this->_list, array($this, 'valuationCmp'));
  304. else if ($order_by_real_quantity)
  305. usort($this->_list, array($this, 'realQuantityCmp'));
  306. }
  307. }
  308. /**
  309. * CMP
  310. *
  311. * @param array $n
  312. * @param array $m
  313. */
  314. public function valuationCmp($n, $m)
  315. {
  316. if ($this->context->cookie->{$this->table.'Orderway'} == 'desc')
  317. return $n['valuation'] > $m['valuation'];
  318. else
  319. return $n['valuation'] < $m['valuation'];
  320. }
  321. /**
  322. * CMP
  323. *
  324. * @param array $n
  325. * @param array $m
  326. */
  327. public function realQuantityCmp($n, $m)
  328. {
  329. if ($this->context->cookie->{$this->table.'Orderway'} == 'desc')
  330. return $n['real_quantity'] > $m['real_quantity'];
  331. else
  332. return $n['real_quantity'] < $m['real_quantity'];
  333. }
  334. /**
  335. * Gets the current warehouse used
  336. *
  337. * @return int id_warehouse
  338. */
  339. protected function getCurrentCoverageWarehouse()
  340. {
  341. static $warehouse = 0;
  342. if ($warehouse == 0)
  343. {
  344. $warehouse = -1; // all warehouses
  345. if ((int)Tools::getValue('id_warehouse'))
  346. $warehouse = (int)Tools::getValue('id_warehouse');
  347. }
  348. return $warehouse;
  349. }
  350. /**
  351. * @see AdminController::initToolbar();
  352. */
  353. public function initToolbar()
  354. {
  355. if (Tools::isSubmit('id_warehouse') && (int)Tools::getValue('id_warehouse') != -1)
  356. {
  357. $this->toolbar_btn['export-stock-state-quantities-csv'] = array(
  358. 'short' => 'Export this list as CSV',
  359. 'href' => $this->context->link->getAdminLink('AdminStockInstantState').'&amp;csv_quantities&amp;id_warehouse='.(int)$this->getCurrentCoverageWarehouse(),
  360. 'desc' => $this->l('Export Quantities (CSV)'),
  361. 'imgclass' => 'export'
  362. );
  363. $this->toolbar_btn['export-stock-state-prices-csv'] = array(
  364. 'short' => 'Export this list as CSV',
  365. 'href' => $this->context->link->getAdminLink('AdminStockInstantState').'&amp;csv_prices&amp;id_warehouse='.(int)$this->getCurrentCoverageWarehouse(),
  366. 'desc' => $this->l('Export Prices (CSV)'),
  367. 'imgclass' => 'export'
  368. );
  369. }
  370. parent::initToolbar();
  371. unset($this->toolbar_btn['new']);
  372. }
  373. /**
  374. * Exports CSV
  375. */
  376. public function renderCSV()
  377. {
  378. if (count($this->_list) <= 0)
  379. return;
  380. // sets warehouse id and warehouse name
  381. $id_warehouse = (int)Tools::getValue('id_warehouse');
  382. $warehouse_name = Warehouse::getWarehouseNameById($id_warehouse);
  383. // if quantities requested
  384. if (Tools::isSubmit('csv_quantities'))
  385. {
  386. // filename
  387. $filename = $this->l('stock_instant_state_quantities').'_'.$warehouse_name.'.csv';
  388. // header
  389. header('Content-type: text/csv');
  390. header('Cache-Control: no-store, no-cache');
  391. header('Content-disposition: attachment; filename="'.$filename);
  392. // puts keys
  393. $keys = array('id_product', 'id_product_attribute', 'reference', 'ean13', 'upc', 'name', 'physical_quantity', 'usable_quantity', 'real_quantity');
  394. echo sprintf("%s\n", implode(';', $keys));
  395. // puts rows
  396. foreach ($this->_list as $row)
  397. {
  398. $row_csv = array($row['id_product'], $row['id_product_attribute'], $row['reference'],
  399. $row['ean13'], $row['upc'], $row['name'],
  400. $row['physical_quantity'], $row['usable_quantity'], $row['real_quantity']
  401. );
  402. // puts one row
  403. echo sprintf("%s\n", implode(';', array_map(array('CSVCore', 'wrap'), $row_csv)));
  404. }
  405. }
  406. // if prices requested
  407. else if (Tools::isSubmit('csv_prices'))
  408. {
  409. // sets filename
  410. $filename = $this->l('stock_instant_state_prices').'_'.$warehouse_name.'.csv';
  411. // header
  412. header('Content-type: text/csv');
  413. header('Cache-Control: no-store, no-cache');
  414. header('Content-disposition: attachment; filename="'.$filename);
  415. // puts keys
  416. $keys = array('id_product', 'id_product_attribute', 'reference', 'ean13', 'upc', 'name', 'price_te', 'physical_quantity', 'usable_quantity');
  417. echo sprintf("%s\n", implode(';', $keys));
  418. foreach ($this->_list as $row)
  419. {
  420. $id_product = (int)$row['id_product'];
  421. $id_product_attribute = (int)$row['id_product_attribute'];
  422. // gets prices
  423. $query = new DbQuery();
  424. $query->select('s.price_te, SUM(s.physical_quantity) as physical_quantity, SUM(s.usable_quantity) as usable_quantity');
  425. $query->from('stock', 's');
  426. $query->leftJoin('warehouse', 'w', 'w.id_warehouse = s.id_warehouse');
  427. $query->where('s.id_product = '.$id_product.' AND s.id_product_attribute = '.$id_product_attribute);
  428. $query->where('s.id_warehouse = '.$id_warehouse);
  429. $query->groupBy('s.price_te');
  430. $datas = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query);
  431. // puts data
  432. foreach ($datas as $data)
  433. {
  434. $row_csv = array($row['id_product'], $row['id_product_attribute'], $row['reference'],
  435. $row['ean13'], $row['upc'], $row['name'],
  436. $data['price_te'], $data['physical_quantity'], $data['usable_quantity']);
  437. // puts one row
  438. echo sprintf("%s\n", implode(';', array_map(array('CSVCore', 'wrap'), $row_csv)));
  439. }
  440. }
  441. }
  442. }
  443. public function initContent()
  444. {
  445. if (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'))
  446. {
  447. $this->warnings[md5('PS_ADVANCED_STOCK_MANAGEMENT')] = $this->l('You need to activate advanced stock management before using this feature.');
  448. return false;
  449. }
  450. parent::initContent();
  451. }
  452. public function initProcess()
  453. {
  454. if (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'))
  455. {
  456. $this->warnings[md5('PS_ADVANCED_STOCK_MANAGEMENT')] = $this->l('You need to activate advanced stock management before using this feature.');
  457. return false;
  458. }
  459. if (Tools::isSubmit('detailsproduct'))
  460. $this->list_id = 'details';
  461. else
  462. $this->list_id = 'stock';
  463. parent::initProcess();
  464. }
  465. }