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

/controllers/admin/AdminWarehousesController.php

https://bitbucket.org/enurkov/prestashop
PHP | 602 lines | 458 code | 53 blank | 91 comment | 35 complexity | 488e009200dd8e30cdbc6b2991aa7fab 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 AdminWarehousesControllerCore extends AdminController
  30. {
  31. public function __construct()
  32. {
  33. $this->table = 'warehouse';
  34. $this->className = 'Warehouse';
  35. $this->deleted = true;
  36. $this->lang = false;
  37. $this->multishop_context = Shop::CONTEXT_ALL;
  38. $this->fields_list = array(
  39. 'reference' => array(
  40. 'title' => $this->l('Reference'),
  41. 'width' => 150,
  42. ),
  43. 'name' => array(
  44. 'title' => $this->l('Name'),
  45. ),
  46. 'management_type' => array(
  47. 'title' => $this->l('Managment type'),
  48. 'width' => 80,
  49. ),
  50. 'employee' => array(
  51. 'title' => $this->l('Manager'),
  52. 'width' => 200,
  53. 'filter_key' => 'employee',
  54. 'havingFilter' => true
  55. ),
  56. 'location' => array(
  57. 'title' => $this->l('Location'),
  58. 'width' => 200,
  59. 'orderby' => false,
  60. 'filter' => false,
  61. 'search' => false,
  62. ),
  63. 'contact' => array(
  64. 'title' => $this->l('Phone Number'),
  65. 'width' => 200,
  66. 'orderby' => false,
  67. 'filter' => false,
  68. 'search' => false,
  69. ),
  70. );
  71. parent::__construct();
  72. }
  73. /**
  74. * AdminController::renderList() override
  75. * @see AdminController::renderList()
  76. */
  77. public function renderList()
  78. {
  79. // removes links on rows
  80. $this->list_no_link = true;
  81. // adds actions on rows
  82. $this->addRowAction('edit');
  83. $this->addRowAction('view');
  84. $this->addRowAction('delete');
  85. // query: select
  86. $this->_select = '
  87. reference,
  88. name,
  89. management_type,
  90. CONCAT(e.lastname, \' \', e.firstname) as employee,
  91. ad.phone as contact,
  92. CONCAT(ad.city, \' - \', c.iso_code) as location';
  93. // query: join
  94. $this->_join = '
  95. LEFT JOIN `'._DB_PREFIX_.'employee` e ON (e.id_employee = a.id_employee)
  96. LEFT JOIN `'._DB_PREFIX_.'address` ad ON (ad.id_address = a.id_address)
  97. LEFT JOIN `'._DB_PREFIX_.'country` c ON (c.id_country = ad.id_country)';
  98. // display help informations
  99. $this->displayInformation($this->l('This interface allows you to manage your warehouses.').'<br />');
  100. $this->displayInformation($this->l('Before adding stock in your warehouses, you should check the general default currency used.').'<br />');
  101. $this->displayInformation($this->l('Furthermore, for each warehouse, you should check:'));
  102. $this->displayInformation($this->l('the management type (according to the law in your country), the valuation currency, its associated carriers and shops.').'<br />');
  103. $this->displayInformation($this->l('Finally, you can see detailed informations on your stock per warehouse, such as its overall value, the number of products and quantities stored, etc.')
  104. .'<br /><br />');
  105. $this->displayInformation($this->l('Be careful, products from different warehouses will need to be shipped in different packages.'));
  106. return parent::renderList();
  107. }
  108. /**
  109. * AdminController::renderForm() override
  110. * @see AdminController::renderForm()
  111. */
  112. public function renderForm()
  113. {
  114. // loads current warehouse
  115. if (!($obj = $this->loadObject(true)))
  116. return;
  117. // gets the manager of the warehouse
  118. $query = new DbQuery();
  119. $query->select('id_employee, CONCAT(lastname," ",firstname) as name');
  120. $query->from('employee');
  121. $query->where('active = 1');
  122. $employees_array = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query);
  123. // sets the title of the toolbar
  124. if (Tools::isSubmit('add'.$this->table))
  125. $this->toolbar_title = $this->l('Stock: create warehouse');
  126. else
  127. $this->toolbar_title = $this->l('Stock: warehouse management');
  128. // sets the fields of the form
  129. $this->fields_form = array(
  130. 'legend' => array(
  131. 'title' => $this->l('Warehouse information'),
  132. 'image' => '../img/admin/edit.gif'
  133. ),
  134. 'input' => array(
  135. array(
  136. 'type' => 'hidden',
  137. 'name' => 'id_address',
  138. ),
  139. array(
  140. 'type' => 'text',
  141. 'label' => $this->l('Reference:'),
  142. 'name' => 'reference',
  143. 'size' => 30,
  144. 'maxlength' => 32,
  145. 'required' => true,
  146. 'desc' => $this->l('Reference for this warehouse'),
  147. ),
  148. array(
  149. 'type' => 'text',
  150. 'label' => $this->l('Name:'),
  151. 'name' => 'name',
  152. 'size' => 40,
  153. 'maxlength' => 45,
  154. 'required' => true,
  155. 'desc' => $this->l('Name of this warehouse'),
  156. 'hint' => $this->l('Invalid characters:').' !<>,;?=+()@#"�{}_$%:',
  157. ),
  158. array(
  159. 'type' => 'text',
  160. 'label' => $this->l('Phone:'),
  161. 'name' => 'phone',
  162. 'size' => 15,
  163. 'maxlength' => 16,
  164. 'desc' => $this->l('Phone number for this warehouse')
  165. ),
  166. array(
  167. 'type' => 'text',
  168. 'label' => $this->l('Address:'),
  169. 'name' => 'address',
  170. 'size' => 100,
  171. 'maxlength' => 128,
  172. 'required' => true
  173. ),
  174. array(
  175. 'type' => 'text',
  176. 'label' => $this->l('Address:').' (2)',
  177. 'name' => 'address2',
  178. 'size' => 100,
  179. 'maxlength' => 128,
  180. 'desc' => $this->l('Address of this warehouse (complementary address is optional).'),
  181. ),
  182. array(
  183. 'type' => 'text',
  184. 'label' => $this->l('Postcode/Zip Code:'),
  185. 'name' => 'postcode',
  186. 'size' => 10,
  187. 'maxlength' => 12,
  188. 'required' => true,
  189. ),
  190. array(
  191. 'type' => 'text',
  192. 'label' => $this->l('City:'),
  193. 'name' => 'city',
  194. 'size' => 20,
  195. 'maxlength' => 32,
  196. 'required' => true,
  197. ),
  198. array(
  199. 'type' => 'select',
  200. 'label' => $this->l('Country:'),
  201. 'name' => 'id_country',
  202. 'required' => true,
  203. 'default_value' => (int)$this->context->country->id,
  204. 'options' => array(
  205. 'query' => Country::getCountries($this->context->language->id, false),
  206. 'id' => 'id_country',
  207. 'name' => 'name',
  208. ),
  209. 'desc' => $this->l('Country where the state, region or city is located')
  210. ),
  211. array(
  212. 'type' => 'select',
  213. 'label' => $this->l('State:'),
  214. 'name' => 'id_state',
  215. 'required' => true,
  216. 'options' => array(
  217. 'query' => array(),
  218. 'id' => 'id_state',
  219. 'name' => 'name'
  220. )
  221. ),
  222. array(
  223. 'type' => 'select',
  224. 'label' => $this->l('Manager:'),
  225. 'name' => 'id_employee',
  226. 'required' => true,
  227. 'options' => array(
  228. 'query' => $employees_array,
  229. 'id' => 'id_employee',
  230. 'name' => 'name'
  231. ),
  232. ),
  233. array(
  234. 'type' => 'select',
  235. 'label' => $this->l('Carriers:'),
  236. 'name' => 'ids_carriers[]',
  237. 'required' => false,
  238. 'multiple' => true,
  239. 'options' => array(
  240. 'query' => Carrier::getCarriers($this->context->language->id, false, false, false, null, Carrier::ALL_CARRIERS),
  241. 'id' => 'id_reference',
  242. 'name' => 'name'
  243. ),
  244. 'desc' => $this->l('Associated carriers. Use CTRL+CLICK to select several.'),
  245. 'hint' => $this->l('You can specify the carriers available to ship orders from this warehouse'),
  246. ),
  247. ),
  248. );
  249. // Shop Association
  250. if (Shop::isFeatureActive())
  251. {
  252. $this->fields_form['input'][] = array(
  253. 'type' => 'shop',
  254. 'label' => $this->l('Shops:'),
  255. 'name' => 'checkBoxShopAsso',
  256. 'desc' => $this->l('Associated shops'),
  257. 'disable_shared' => Shop::SHARE_STOCK
  258. );
  259. }
  260. // if it is still possible to change currency valuation and management type
  261. if (Tools::isSubmit('addwarehouse') || Tools::isSubmit('submitAddwarehouse'))
  262. {
  263. // adds input management type
  264. $this->fields_form['input'][] = array(
  265. 'type' => 'select',
  266. 'label' => $this->l('Management type:'),
  267. 'hint' => $this->l('Careful! You won\'t be able to change this value later!'),
  268. 'name' => 'management_type',
  269. 'required' => true,
  270. 'options' => array(
  271. 'query' => array(
  272. array(
  273. 'id' => 'WA',
  274. 'name' => $this->l('Average Weight')
  275. ),
  276. array(
  277. 'id' => 'FIFO',
  278. 'name' => $this->l('First In, First Out')
  279. ),
  280. array(
  281. 'id' => 'LIFO',
  282. 'name' => $this->l('Last In, First Out')
  283. ),
  284. ),
  285. 'id' => 'id',
  286. 'name' => 'name'
  287. ),
  288. 'desc' => $this->l('Inventory valuation method')
  289. );
  290. // adds input valuation currency
  291. $this->fields_form['input'][] = array(
  292. 'type' => 'select',
  293. 'label' => $this->l('Stock valuation currency:'),
  294. 'hint' => $this->l('Careful! You won\'t be able to change this value later!'),
  295. 'name' => 'id_currency',
  296. 'required' => true,
  297. 'options' => array(
  298. 'query' => Currency::getCurrencies(),
  299. 'id' => 'id_currency',
  300. 'name' => 'name'
  301. )
  302. );
  303. }
  304. else // else hide input
  305. {
  306. $this->fields_form['input'][] = array(
  307. 'type' => 'hidden',
  308. 'name' => 'management_type'
  309. );
  310. $this->fields_form['input'][] = array(
  311. 'type' => 'hidden',
  312. 'name' => 'id_currency'
  313. );
  314. }
  315. $this->fields_form['submit'] = array(
  316. 'title' => $this->l('Save'),
  317. 'class' => 'button'
  318. );
  319. $address = null;
  320. // loads current address for this warehouse - if possible
  321. if ($obj->id_address > 0)
  322. $address = new Address($obj->id_address);
  323. // loads current shops associated with this warehouse
  324. $shops = $obj->getShops();
  325. $ids_shop = array();
  326. foreach ($shops as $shop)
  327. $ids_shop[] = $shop['id_shop'];
  328. // loads current carriers associated with this warehouse
  329. $carriers = $obj->getCarriers(true);
  330. // if an address is available : force specific fields values
  331. if ($address != null)
  332. $this->fields_value = array(
  333. 'id_address' => $address->id,
  334. 'phone' => $address->phone,
  335. 'address' => $address->address1,
  336. 'address2' => $address->address2,
  337. 'postcode' => $address->postcode,
  338. 'city' => $address->city,
  339. 'id_country' => $address->id_country,
  340. 'id_state' => $address->id_state,
  341. );
  342. else // loads default country
  343. $this->fields_value = array(
  344. 'id_address' => 0,
  345. 'id_country' => Configuration::get('PS_COUNTRY_DEFAULT')
  346. );
  347. // loads shops and carriers
  348. $this->fields_value['ids_shops[]'] = $ids_shop;
  349. $this->fields_value['ids_carriers[]'] = $carriers;
  350. if (!Validate::isLoadedObject($obj))
  351. $this->fields_value['id_currency'] = (int)Configuration::get('PS_CURRENCY_DEFAULT');
  352. return parent::renderForm();
  353. }
  354. /**
  355. * @see AdminController::renderView()
  356. */
  357. public function renderView()
  358. {
  359. // gets necessary objects
  360. $id_warehouse = (int)Tools::getValue('id_warehouse');
  361. $warehouse = new Warehouse($id_warehouse);
  362. $employee = new Employee($warehouse->id_employee);
  363. $currency = new Currency($warehouse->id_currency);
  364. $address = new Address($warehouse->id_address);
  365. $shops = $warehouse->getShops();
  366. // checks objects
  367. if (!Validate::isLoadedObject($warehouse) ||
  368. !Validate::isLoadedObject($employee) ||
  369. !Validate::isLoadedObject($currency) ||
  370. !Validate::isLoadedObject($address))
  371. return parent::renderView();
  372. // assigns to our view
  373. $this->tpl_view_vars = array(
  374. 'warehouse' => $warehouse,
  375. 'employee' => $employee,
  376. 'currency' => $currency,
  377. 'address' => $address,
  378. 'shops' => $shops,
  379. 'warehouse_num_products' => $warehouse->getNumberOfProducts(),
  380. 'warehouse_value' => Tools::displayPrice(Tools::ps_round($warehouse->getStockValue(), 2), $currency),
  381. 'warehouse_quantities' => $warehouse->getQuantitiesofProducts(),
  382. );
  383. return parent::renderView();
  384. }
  385. /**
  386. * @see AdminController::afterAdd()
  387. * Called once $object is set.
  388. * Used to process the associations with address/shops/carriers
  389. */
  390. protected function afterAdd($object)
  391. {
  392. // handles address association
  393. $address = new Address($object->id_address);
  394. if (Validate::isLoadedObject($address))
  395. {
  396. $address->id_warehouse = $object->id_address;
  397. $address->save();
  398. }
  399. // handles carriers associations
  400. if (Tools::isSubmit('ids_carriers'))
  401. $object->setCarriers(Tools::getValue('ids_carriers'));
  402. return true;
  403. }
  404. /**
  405. * AdminController::getList() override
  406. * @see AdminController::getList()
  407. */
  408. public function getList($id_lang, $order_by = null, $order_way = null, $start = 0, $limit = null, $id_lang_shop = false)
  409. {
  410. parent::getList($id_lang, $order_by, $order_way, $start, $limit, $id_lang_shop);
  411. // foreach item in the list to render
  412. $nb_items = count($this->_list);
  413. for ($i = 0; $i < $nb_items; ++$i)
  414. {
  415. // depending on the management type, translates the management type
  416. $item = &$this->_list[$i];
  417. switch ($item['management_type']) // management type can be either WA/FIFO/LIFO
  418. {
  419. case 'WA':
  420. $item['management_type'] = $this->l('WA');
  421. break;
  422. case 'FIFO':
  423. $item['management_type'] = $this->l('FIFO');
  424. break;
  425. case 'LIFO':
  426. $item['management_type'] = $this->l('LIFO');
  427. break;
  428. }
  429. }
  430. }
  431. public function initContent()
  432. {
  433. if (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'))
  434. {
  435. $this->warnings[md5('PS_ADVANCED_STOCK_MANAGEMENT')] = $this->l('You need to activate advanced stock management prior to use this feature.');
  436. return false;
  437. }
  438. parent::initContent();
  439. }
  440. public function initProcess()
  441. {
  442. if (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'))
  443. {
  444. $this->warnings[md5('PS_ADVANCED_STOCK_MANAGEMENT')] = $this->l('You need to activate advanced stock management prior to use this feature.');
  445. return false;
  446. }
  447. parent::initProcess();
  448. }
  449. /**
  450. * @see AdminController::processAdd();
  451. */
  452. public function processAdd()
  453. {
  454. if (Tools::isSubmit('submitAdd'.$this->table))
  455. {
  456. if (!($obj = $this->loadObject(true)))
  457. return;
  458. $this->updateAddress();
  459. // hack for enable the possibility to update a warehouse without recreate new id
  460. $this->deleted = false;
  461. return parent::processAdd();
  462. }
  463. }
  464. protected function updateAddress()
  465. {
  466. // updates/creates address if it does not exist
  467. if (Tools::isSubmit('id_address') && (int)Tools::getValue('id_address') > 0)
  468. $address = new Address((int)Tools::getValue('id_address')); // updates address
  469. else
  470. $address = new Address(); // creates address
  471. // sets the address
  472. $address->alias = Tools::getValue('reference', null);
  473. $address->lastname = 'warehouse'; // skip problem with numeric characters in warehouse name
  474. $address->firstname = 'warehouse'; // skip problem with numeric characters in warehouse name
  475. $address->address1 = Tools::getValue('address', null);
  476. $address->address2 = Tools::getValue('address2', null);
  477. $address->postcode = Tools::getValue('postcode', null);
  478. $address->phone = Tools::getValue('phone', null);
  479. $address->id_country = Tools::getValue('id_country', null);
  480. $address->id_state = Tools::getValue('id_state', null);
  481. $address->city = Tools::getValue('city', null);
  482. // validates the address
  483. $validation = $address->validateController();
  484. // checks address validity
  485. if (count($validation) > 0) // if not valid
  486. {
  487. foreach ($validation as $item)
  488. $this->errors[] = $item;
  489. $this->errors[] = Tools::displayError('The address is not correct. Check if all required fields are filled.');
  490. }
  491. else // valid
  492. {
  493. if (Tools::isSubmit('id_address') && Tools::getValue('id_address') > 0)
  494. $address->update();
  495. else
  496. {
  497. $address->save();
  498. $_POST['id_address'] = $address->id;
  499. }
  500. }
  501. }
  502. /**
  503. * @see AdminController::processDelete();
  504. */
  505. public function processDelete()
  506. {
  507. if (Tools::isSubmit('delete'.$this->table))
  508. {
  509. // check if the warehouse exists and can be deleted
  510. if (!($obj = $this->loadObject(true)))
  511. return;
  512. else if ($obj->getQuantitiesOfProducts() > 0) // not possible : products
  513. $this->errors[] = $this->l('It is not possible to delete a Warehouse when there are products in it.');
  514. else if (SupplyOrder::warehouseHasPendingOrders($obj->id)) // not possible : supply orders
  515. $this->errors[] = $this->l('It is not possible to delete a Warehouse if it has pending supply orders.');
  516. else // else, it can be deleted
  517. {
  518. // sets the address of the warehouse as deleted
  519. $address = new Address($obj->id_address);
  520. $address->deleted = 1;
  521. $address->save();
  522. // removes associations with carriers/shops/products location
  523. $obj->setCarriers(array());
  524. $obj->resetProductsLocations();
  525. return parent::processDelete();
  526. }
  527. }
  528. }
  529. /**
  530. * @see AdminController::processUpdate();
  531. */
  532. public function processUpdate()
  533. {
  534. // loads object
  535. if (!($obj = $this->loadObject(true)))
  536. return;
  537. $this->updateAddress();
  538. // handles carriers associations
  539. $obj->setCarriers(Tools::getValue('ids_carriers'), array());
  540. return parent::processUpdate();
  541. }
  542. protected function updateAssoShop($id_object)
  543. {
  544. parent::updateAssoShop($id_object);
  545. if (!($obj = $this->loadObject(true)))
  546. return;
  547. $obj->resetStockAvailable();
  548. }
  549. }