PageRenderTime 52ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/controllers/admin/AdminStockInstantStateController.php

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