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

/controllers/admin/AdminSupplyOrdersController.php

https://github.com/netplayer/PrestaShop
PHP | 2187 lines | 1609 code | 277 blank | 301 comment | 244 complexity | af15dcb31dec3424fd2bc8f02c2c3c22 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  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 AdminSupplyOrdersControllerCore extends AdminController
  30. {
  31. /*
  32. * @var array List of warehouses
  33. */
  34. protected $warehouses;
  35. public function __construct()
  36. {
  37. $this->bootstrap = true;
  38. $this->context = Context::getContext();
  39. $this->table = 'supply_order';
  40. $this->className = 'SupplyOrder';
  41. $this->identifier = 'id_supply_order';
  42. $this->lang = false;
  43. $this->is_template_list = false;
  44. $this->multishop_context = Shop::CONTEXT_ALL;
  45. $this->addRowAction('updatereceipt');
  46. $this->addRowAction('changestate');
  47. $this->addRowAction('edit');
  48. $this->addRowAction('view');
  49. $this->addRowAction('details');
  50. $this->list_no_link = true;
  51. $this->fields_list = array(
  52. 'reference' => array(
  53. 'title' => $this->l('Reference'),
  54. 'havingFilter' => true
  55. ),
  56. 'supplier' => array(
  57. 'title' => $this->l('Supplier'),
  58. 'filter_key' => 's!name'
  59. ),
  60. 'warehouse' => array(
  61. 'title' => $this->l('Warehouse'),
  62. 'filter_key' => 'w!name'
  63. ),
  64. 'state' => array(
  65. 'title' => $this->l('Status'),
  66. 'filter_key' => 'stl!name',
  67. 'color' => 'color',
  68. ),
  69. 'date_add' => array(
  70. 'title' => $this->l('Creation'),
  71. 'align' => 'left',
  72. 'type' => 'date',
  73. 'havingFilter' => true,
  74. 'filter_key' => 'a!date_add'
  75. ),
  76. 'date_upd' => array(
  77. 'title' => $this->l('Last modification'),
  78. 'align' => 'left',
  79. 'type' => 'date',
  80. 'havingFilter' => true,
  81. 'filter_key' => 'a!date_upd'
  82. ),
  83. 'date_delivery_expected' => array(
  84. 'title' => $this->l('Delivery (expected)'),
  85. 'align' => 'left',
  86. 'type' => 'date',
  87. 'havingFilter' => true,
  88. 'filter_key' => 'a!date_delivery_expected'
  89. ),
  90. 'id_export' => array(
  91. 'title' => $this->l('Export'),
  92. 'callback' => 'printExportIcons',
  93. 'orderby' => false,
  94. 'search' => false
  95. ),
  96. );
  97. // gets the list of warehouses available
  98. $this->warehouses = Warehouse::getWarehouses(true);
  99. // gets the final list of warehouses
  100. array_unshift($this->warehouses, array('id_warehouse' => -1, 'name' => $this->l('All Warehouses')));
  101. parent::__construct();
  102. }
  103. /**
  104. * AdminController::init() override
  105. * @see AdminController::init()
  106. */
  107. public function init()
  108. {
  109. parent::init();
  110. if (Tools::isSubmit('addsupply_order') ||
  111. Tools::isSubmit('submitAddsupply_order') ||
  112. (Tools::isSubmit('updatesupply_order') && Tools::isSubmit('id_supply_order')))
  113. {
  114. // override table, lang, className and identifier for the current controller
  115. $this->table = 'supply_order';
  116. $this->className = 'SupplyOrder';
  117. $this->identifier = 'id_supply_order';
  118. $this->lang = false;
  119. $this->action = 'new';
  120. $this->display = 'add';
  121. if (Tools::isSubmit('updatesupply_order'))
  122. if ($this->tabAccess['edit'] === '1')
  123. $this->display = 'edit';
  124. else
  125. $this->errors[] = Tools::displayError('You do not have permission to edit this.');
  126. }
  127. if (Tools::isSubmit('update_receipt') && Tools::isSubmit('id_supply_order'))
  128. {
  129. // change the display type in order to add specific actions to
  130. $this->display = 'update_receipt';
  131. // display correct toolBar
  132. $this->initToolbar();
  133. }
  134. }
  135. public function initPageHeaderToolbar()
  136. {
  137. if ($this->display == 'details')
  138. $this->page_header_toolbar_btn['back'] = array(
  139. 'href' => Context::getContext()->link->getAdminLink('AdminSupplyOrders'),
  140. 'desc' => $this->l('Back to list', null, null, false),
  141. 'icon' => 'process-icon-back'
  142. );
  143. elseif (empty($this->display))
  144. {
  145. $this->page_header_toolbar_btn['new_supply_order'] = array(
  146. 'href' => self::$currentIndex.'&addsupply_order&token='.$this->token,
  147. 'desc' => $this->l('Add new supply order', null, null, false),
  148. 'icon' => 'process-icon-new'
  149. );
  150. $this->page_header_toolbar_btn['new_supply_order_template'] = array(
  151. 'href' => self::$currentIndex.'&addsupply_order&mod=template&token='.$this->token,
  152. 'desc' => $this->l('Add new supply order template', null, null, false),
  153. 'icon' => 'process-icon-new'
  154. );
  155. }
  156. parent::initPageHeaderToolbar();
  157. }
  158. /**
  159. * AdminController::renderForm() override
  160. * @see AdminController::renderForm()
  161. */
  162. public function renderForm()
  163. {
  164. if (Tools::isSubmit('addsupply_order') ||
  165. Tools::isSubmit('updatesupply_order') ||
  166. Tools::isSubmit('submitAddsupply_order') ||
  167. Tools::isSubmit('submitUpdatesupply_order'))
  168. {
  169. if (Tools::isSubmit('addsupply_order') || Tools::isSubmit('submitAddsupply_order'))
  170. $this->toolbar_title = $this->l('Stock: Create a new supply order');
  171. if (Tools::isSubmit('updatesupply_order') || Tools::isSubmit('submitUpdatesupply_order'))
  172. $this->toolbar_title = $this->l('Stock: Manage supply orders');
  173. if (Tools::isSubmit('mod') && Tools::getValue('mod') === 'template' || $this->object->is_template)
  174. $this->toolbar_title .= ' ('.$this->l('template').')';
  175. $this->addJqueryUI('ui.datepicker');
  176. //get warehouses list
  177. $warehouses = Warehouse::getWarehouses(true);
  178. // displays warning if there are no warehouses
  179. if (!$warehouses)
  180. $this->displayWarning($this->l('You must have at least one warehouse. See Stock/Warehouses'));
  181. //get currencies list
  182. $currencies = Currency::getCurrencies();
  183. $id_default_currency = Configuration::get('PS_CURRENCY_DEFAULT');
  184. $default_currency = Currency::getCurrency($id_default_currency);
  185. if ($default_currency)
  186. $currencies = array_merge(array($default_currency, '-'), $currencies);
  187. //get suppliers list
  188. $suppliers = array_unique(Supplier::getSuppliers(), SORT_REGULAR);
  189. //get languages list
  190. $languages = Language::getLanguages(true);
  191. $id_default_lang = Configuration::get('PS_LANG_DEFAULT');
  192. $default_lang = Language::getLanguage($id_default_lang);
  193. if ($default_lang)
  194. $languages = array_merge(array($default_lang, '-'), $languages);
  195. $this->fields_form = array(
  196. 'legend' => array(
  197. 'title' => $this->l('Order information'),
  198. 'icon' => 'icon-pencil'
  199. ),
  200. 'input' => array(
  201. array(
  202. 'type' => 'text',
  203. 'label' => $this->l('Reference'),
  204. 'name' => 'reference',
  205. 'required' => true,
  206. 'hint' => $this->l('The reference number for your order.'),
  207. ),
  208. array(
  209. 'type' => 'select',
  210. 'label' => $this->l('Supplier'),
  211. 'name' => 'id_supplier',
  212. 'required' => true,
  213. 'options' => array(
  214. 'query' => $suppliers,
  215. 'id' => 'id_supplier',
  216. 'name' => 'name'
  217. ),
  218. 'hint' => array(
  219. $this->l('Select the supplier you\'ll be purchasing from.'),
  220. $this->l('Warning: All products already added to the order will be removed.')
  221. )
  222. ),
  223. array(
  224. 'type' => 'select',
  225. 'label' => $this->l('Warehouse'),
  226. 'name' => 'id_warehouse',
  227. 'required' => true,
  228. 'options' => array(
  229. 'query' => $warehouses,
  230. 'id' => 'id_warehouse',
  231. 'name' => 'name'
  232. ),
  233. 'hint' => $this->l('Which warehouse will the order be sent to?'),
  234. ),
  235. array(
  236. 'type' => 'select',
  237. 'label' => $this->l('Currency'),
  238. 'name' => 'id_currency',
  239. 'required' => true,
  240. 'options' => array(
  241. 'query' => $currencies,
  242. 'id' => 'id_currency',
  243. 'name' => 'name'
  244. ),
  245. 'hint' => array(
  246. $this->l('The currency of the order.'),
  247. $this->l('Warning: All products already added to the order will be removed.')
  248. )
  249. ),
  250. array(
  251. 'type' => 'select',
  252. 'label' => $this->l('Order Language'),
  253. 'name' => 'id_lang',
  254. 'required' => true,
  255. 'options' => array(
  256. 'query' => $languages,
  257. 'id' => 'id_lang',
  258. 'name' => 'name'
  259. ),
  260. 'hint' => $this->l('The language of the order.')
  261. ),
  262. array(
  263. 'type' => 'text',
  264. 'label' => $this->l('Global discount percentage'),
  265. 'name' => 'discount_rate',
  266. 'required' => false,
  267. 'hint' => $this->l('This is the global discount percentage for the order.'),
  268. ),
  269. array(
  270. 'type' => 'text',
  271. 'label' => $this->l('Automatically load products'),
  272. 'name' => 'load_products',
  273. 'required' => false,
  274. 'hint' => array(
  275. $this->l('This will reset the order.'),
  276. $this->l('If a value specified, each of your current product (from the selected supplier and warehouse) with a quantity lower than or equal to this value will be loaded. This means that PrestaShop will pre-fill this order with the products that are low on quantity.'),
  277. ),
  278. ),
  279. ),
  280. 'submit' => array(
  281. 'title' => $this->l('Save order'),
  282. ),
  283. 'buttons' => array(
  284. 'save-and-stay' => array(
  285. 'title' => $this->l('Save order and stay'),
  286. 'name' => 'submitAddsupply_orderAndStay',
  287. 'type' => 'submit',
  288. 'class' => 'btn btn-default pull-right',
  289. 'icon' => 'process-icon-save'
  290. )
  291. )
  292. );
  293. if (Tools::isSubmit('mod') && Tools::getValue('mod') === 'template' ||
  294. $this->object->is_template)
  295. {
  296. $this->fields_form['input'][] = array(
  297. 'type' => 'hidden',
  298. 'name' => 'is_template'
  299. );
  300. $this->fields_form['input'][] = array(
  301. 'type' => 'hidden',
  302. 'name' => 'date_delivery_expected',
  303. );
  304. }
  305. else
  306. {
  307. $this->fields_form['input'][] = array(
  308. 'type' => 'date',
  309. 'label' => $this->l('Expected delivery date'),
  310. 'name' => 'date_delivery_expected',
  311. 'required' => true,
  312. 'desc' => $this->l('The expected delivery date for this order is...'),
  313. );
  314. }
  315. //specific discount display
  316. if (isset($this->object->discount_rate))
  317. $this->object->discount_rate = Tools::ps_round($this->object->discount_rate, 4);
  318. //specific date display
  319. if (isset($this->object->date_delivery_expected))
  320. {
  321. $date = explode(' ', $this->object->date_delivery_expected);
  322. if ($date)
  323. $this->object->date_delivery_expected = $date[0];
  324. }
  325. $this->displayInformation(
  326. $this->l('If you wish to order products, they have to be available for the specified supplier/warehouse.')
  327. .' '.
  328. $this->l('See Catalog/Products/[Your Product]/Suppliers & Warehouses.')
  329. .'<br />'.
  330. $this->l('Changing the currency or the supplier will reset the order.')
  331. .'<br />'
  332. .'<br />'.
  333. $this->l('Please note that you can only order from one supplier at a time.')
  334. );
  335. return parent::renderForm();
  336. }
  337. }
  338. /**
  339. * AdminController::getList() override
  340. * @see AdminController::getList()
  341. */
  342. public function getList($id_lang, $order_by = null, $order_way = null, $start = 0, $limit = null, $id_lang_shop = false)
  343. {
  344. if (Tools::isSubmit('csv_orders') || Tools::isSubmit('csv_orders_details') || Tools::isSubmit('csv_order_details'))
  345. $limit = false;
  346. // defines button specific for non-template supply orders
  347. if (!$this->is_template_list && $this->display != 'details')
  348. {
  349. // adds export csv buttons
  350. $this->toolbar_btn['export-csv-orders'] = array(
  351. 'short' => 'Export Orders',
  352. 'href' => $this->context->link->getAdminLink('AdminSupplyOrders').'&amp;csv_orders&id_warehouse='.$this->getCurrentWarehouse(),
  353. 'desc' => $this->l('Export Orders (CSV)'),
  354. 'class' => 'process-icon-export'
  355. );
  356. $this->toolbar_btn['export-csv-details'] = array(
  357. 'short' => 'Export Orders Details',
  358. 'href' => $this->context->link->getAdminLink('AdminSupplyOrders').'&amp;csv_orders_details&id_warehouse='.$this->getCurrentWarehouse(),
  359. 'desc' => $this->l('Export Orders Details (CSV)'),
  360. 'class' => 'process-icon-export'
  361. );
  362. unset($this->toolbar_btn['new']);
  363. if ($this->tabAccess['add'] === '1')
  364. {
  365. $this->toolbar_btn['new'] = array(
  366. 'href' => self::$currentIndex.'&amp;add'.$this->table.'&amp;token='.$this->token,
  367. 'desc' => $this->l('Add New')
  368. );
  369. }
  370. }
  371. parent::getList($id_lang, $order_by, $order_way, $start, $limit, $id_lang_shop);
  372. // adds colors depending on the receipt state
  373. if ($order_by == 'quantity_expected')
  374. {
  375. $nb_items = count($this->_list);
  376. for ($i = 0; $i < $nb_items; ++$i)
  377. {
  378. $item = &$this->_list[$i];
  379. if ($item['quantity_received'] == $item['quantity_expected'])
  380. $item['color'] = '#00bb35';
  381. else if ($item['quantity_received'] > $item['quantity_expected'])
  382. $item['color'] = '#fb0008';
  383. }
  384. }
  385. // actions filters on supply orders list
  386. if ($this->table == 'supply_order')
  387. {
  388. $nb_items = count($this->_list);
  389. for ($i = 0; $i < $nb_items; $i++)
  390. {
  391. // if the current state doesn't allow order edit, skip the edit action
  392. if ($this->_list[$i]['editable'] == 0)
  393. $this->addRowActionSkipList('edit', $this->_list[$i]['id_supply_order']);
  394. if ($this->_list[$i]['enclosed'] == 1 && $this->_list[$i]['receipt_state'] == 0)
  395. $this->addRowActionSkipList('changestate', $this->_list[$i]['id_supply_order']);
  396. if (1 != $this->_list[$i]['pending_receipt'])
  397. $this->addRowActionSkipList('updatereceipt', $this->_list[$i]['id_supply_order']);
  398. }
  399. }
  400. }
  401. /**
  402. * AdminController::renderList() override
  403. * @see AdminController::renderList()
  404. */
  405. public function renderList()
  406. {
  407. $this->displayInformation($this->l('This interface allows you to manage supply orders.').'<br />');
  408. $this->displayInformation($this->l('You can create pre-filled order templates, from which you can build actual orders much quicker.').'<br />');
  409. if (count($this->warehouses) <= 1)
  410. $this->displayWarning($this->l('You must choose at least one warehouse before creating supply orders. For more information, see Stock/Warehouses.'));
  411. // assigns warehouses
  412. $this->tpl_list_vars['warehouses'] = $this->warehouses;
  413. $this->tpl_list_vars['current_warehouse'] = $this->getCurrentWarehouse();
  414. $this->tpl_list_vars['filter_status'] = $this->getFilterStatus();
  415. // overrides query
  416. $this->_select = '
  417. s.name AS supplier,
  418. w.name AS warehouse,
  419. stl.name AS state,
  420. st.delivery_note,
  421. st.editable,
  422. st.enclosed,
  423. st.receipt_state,
  424. st.pending_receipt,
  425. st.color AS color,
  426. a.id_supply_order as id_export';
  427. $this->_join = 'LEFT JOIN `'._DB_PREFIX_.'supply_order_state_lang` stl ON
  428. (
  429. a.id_supply_order_state = stl.id_supply_order_state
  430. AND stl.id_lang = '.(int)$this->context->language->id.'
  431. )
  432. LEFT JOIN `'._DB_PREFIX_.'supply_order_state` st ON a.id_supply_order_state = st.id_supply_order_state
  433. LEFT JOIN `'._DB_PREFIX_.'supplier` s ON a.id_supplier = s.id_supplier
  434. LEFT JOIN `'._DB_PREFIX_.'warehouse` w ON (w.id_warehouse = a.id_warehouse)';
  435. $this->_where = ' AND a.is_template = 0';
  436. if ($this->getCurrentWarehouse() != -1)
  437. {
  438. $this->_where .= ' AND a.id_warehouse = '.$this->getCurrentWarehouse();
  439. self::$currentIndex .= '&id_warehouse='.(int)$this->getCurrentWarehouse();
  440. }
  441. if ($this->getFilterStatus() != 0)
  442. {
  443. $this->_where .= ' AND st.enclosed != 1';
  444. self::$currentIndex .= '&filter_status=on';
  445. }
  446. $this->list_id = 'orders';
  447. $first_list = parent::renderList();
  448. if (Tools::isSubmit('csv_orders') || Tools::isSubmit('csv_orders_details') || Tools::isSubmit('csv_order_details'))
  449. {
  450. if (count($this->_list) > 0)
  451. {
  452. $this->renderCSV();
  453. die;
  454. }
  455. else
  456. $this->displayWarning($this->l('There is nothing to export as a CSV file.'));
  457. }
  458. // second list : templates
  459. $second_list = null;
  460. $this->is_template_list = true;
  461. unset($this->tpl_list_vars['warehouses']);
  462. unset($this->tpl_list_vars['current_warehouse']);
  463. unset($this->tpl_list_vars['filter_status']);
  464. // unsets actions
  465. $this->actions = array();
  466. unset($this->toolbar_btn['export-csv-orders']);
  467. unset($this->toolbar_btn['export-csv-details']);
  468. // adds actions
  469. $this->addRowAction('view');
  470. $this->addRowAction('edit');
  471. $this->addRowAction('createsupplyorder');
  472. $this->addRowAction('delete');
  473. // unsets some fields
  474. unset($this->fields_list['state'],
  475. $this->fields_list['date_upd'],
  476. $this->fields_list['id_pdf'],
  477. $this->fields_list['date_delivery_expected'],
  478. $this->fields_list['id_export']);
  479. // $this->fields_list['date_add']['align'] = 'left';
  480. // adds filter, to gets only templates
  481. unset($this->_where);
  482. $this->_where = ' AND a.is_template = 1';
  483. if ($this->getCurrentWarehouse() != -1)
  484. $this->_where .= ' AND a.id_warehouse = '.$this->getCurrentWarehouse();
  485. // re-defines toolbar & buttons
  486. $this->toolbar_title = $this->l('Stock: Supply order templates');
  487. $this->initToolbar();
  488. unset($this->toolbar_btn['new']);
  489. $this->toolbar_btn['new'] = array(
  490. 'href' => self::$currentIndex.'&amp;add'.$this->table.'&mod=template&amp;token='.$this->token,
  491. 'desc' => $this->l('Add new template')
  492. );
  493. $this->list_id = 'templates';
  494. // inits list
  495. $second_list = parent::renderList();
  496. return $first_list.$second_list;
  497. }
  498. /**
  499. * Init the content of change state action
  500. */
  501. public function initChangeStateContent()
  502. {
  503. $id_supply_order = (int)Tools::getValue('id_supply_order', 0);
  504. if ($id_supply_order <= 0)
  505. {
  506. $this->errors[] = Tools::displayError('The specified supply order is not valid');
  507. return parent::initContent();
  508. }
  509. $supply_order = new SupplyOrder($id_supply_order);
  510. $supply_order_state = new SupplyOrderState($supply_order->id_supply_order_state);
  511. if (!Validate::isLoadedObject($supply_order) || !Validate::isLoadedObject($supply_order_state))
  512. {
  513. $this->errors[] = Tools::displayError('The specified supply order is not valid');
  514. return parent::initContent();
  515. }
  516. // change the display type in order to add specific actions to
  517. $this->display = 'update_order_state';
  518. // overrides parent::initContent();
  519. $this->initToolbar();
  520. $this->initPageHeaderToolbar();
  521. // given the current state, loads available states
  522. $states = SupplyOrderState::getSupplyOrderStates($supply_order->id_supply_order_state);
  523. // gets the state that are not allowed
  524. $allowed_states = array();
  525. foreach ($states as &$state)
  526. {
  527. $allowed_states[] = $state['id_supply_order_state'];
  528. $state['allowed'] = 1;
  529. }
  530. $not_allowed_states = SupplyOrderState::getStates($allowed_states);
  531. // generates the final list of states
  532. $index = count($allowed_states);
  533. foreach ($not_allowed_states as &$not_allowed_state)
  534. {
  535. $not_allowed_state['allowed'] = 0;
  536. $states[$index] = $not_allowed_state;
  537. ++$index;
  538. }
  539. // loads languages
  540. $this->getlanguages();
  541. // defines the fields of the form to display
  542. $this->fields_form[0]['form'] = array(
  543. 'legend' => array(
  544. 'title' => $this->l('Supply order status'),
  545. 'icon' => 'icon-pencil'
  546. ),
  547. 'input' => array(),
  548. 'submit' => array(
  549. 'title' => $this->l('Save')
  550. )
  551. );
  552. $this->displayInformation($this->l('Be careful when changing status. Some of those changes cannot be canceled. '));
  553. // sets up the helper
  554. $helper = new HelperForm();
  555. $helper->submit_action = 'submitChangestate';
  556. $helper->currentIndex = self::$currentIndex;
  557. $helper->toolbar_btn = $this->toolbar_btn;
  558. $helper->toolbar_scroll = false;
  559. $helper->token = $this->token;
  560. $helper->id = null; // no display standard hidden field in the form
  561. $helper->languages = $this->_languages;
  562. $helper->default_form_language = $this->default_form_language;
  563. $helper->allow_employee_form_lang = $this->allow_employee_form_lang;
  564. $helper->title = sprintf($this->l('Stock: Change supply order status #%s'), $supply_order->reference);
  565. $helper->override_folder = 'supply_orders_change_state/';
  566. // assigns our content
  567. $helper->tpl_vars['show_change_state_form'] = true;
  568. $helper->tpl_vars['supply_order_state'] = $supply_order_state;
  569. $helper->tpl_vars['supply_order'] = $supply_order;
  570. $helper->tpl_vars['supply_order_states'] = $states;
  571. // generates the form to display
  572. $content = $helper->generateForm($this->fields_form);
  573. $this->context->smarty->assign(array(
  574. 'content' => $content,
  575. 'url_post' => self::$currentIndex.'&token='.$this->token,
  576. 'show_page_header_toolbar' => $this->show_page_header_toolbar,
  577. 'page_header_toolbar_title' => $this->page_header_toolbar_title,
  578. 'page_header_toolbar_btn' => $this->page_header_toolbar_btn
  579. ));
  580. }
  581. /**
  582. * Init the content of change state action
  583. */
  584. public function initUpdateSupplyOrderContent()
  585. {
  586. $this->addJqueryPlugin('autocomplete');
  587. // load supply order
  588. $id_supply_order = (int)Tools::getValue('id_supply_order', null);
  589. if ($id_supply_order != null)
  590. {
  591. $supply_order = new SupplyOrder($id_supply_order);
  592. $currency = new Currency($supply_order->id_currency);
  593. if (Validate::isLoadedObject($supply_order))
  594. {
  595. // load products of this order
  596. $products = $supply_order->getEntries();
  597. $product_ids = array();
  598. if (isset($this->order_products_errors) && is_array($this->order_products_errors))
  599. {
  600. //for each product in error array, check if it is in products array, and remove it to conserve last user values
  601. foreach ($this->order_products_errors as $pe)
  602. foreach ($products as $index_p => $p)
  603. if (($p['id_product'] == $pe['id_product']) && ($p['id_product_attribute'] == $pe['id_product_attribute']))
  604. unset($products[$index_p]);
  605. // then merge arrays
  606. $products = array_merge($this->order_products_errors, $products);
  607. }
  608. foreach ($products as &$item)
  609. {
  610. // calculate md5 checksum on each product for use in tpl
  611. $item['checksum'] = md5(_COOKIE_KEY_.$item['id_product'].'_'.$item['id_product_attribute']);
  612. $item['unit_price_te'] = Tools::ps_round($item['unit_price_te'], 2);
  613. // add id to ids list
  614. $product_ids[] = $item['id_product'].'_'.$item['id_product_attribute'];
  615. }
  616. $this->tpl_form_vars['products_list'] = $products;
  617. $this->tpl_form_vars['product_ids'] = implode($product_ids, '|');
  618. $this->tpl_form_vars['product_ids_to_delete'] = '';
  619. $this->tpl_form_vars['supplier_id'] = $supply_order->id_supplier;
  620. $this->tpl_form_vars['currency'] = $currency;
  621. }
  622. }
  623. $this->tpl_form_vars['content'] = $this->content;
  624. $this->tpl_form_vars['token'] = $this->token;
  625. $this->tpl_form_vars['show_product_management_form'] = true;
  626. // call parent initcontent to render standard form content
  627. parent::initContent();
  628. }
  629. /**
  630. * Inits the content of 'update_receipt' action
  631. * Called in initContent()
  632. * @see AdminSuppliersOrders::initContent()
  633. */
  634. public function initUpdateReceiptContent()
  635. {
  636. $id_supply_order = (int)Tools::getValue('id_supply_order', null);
  637. // if there is no order to fetch
  638. if (null == $id_supply_order)
  639. return parent::initContent();
  640. $supply_order = new SupplyOrder($id_supply_order);
  641. // if it's not a valid order
  642. if (!Validate::isLoadedObject($supply_order))
  643. return parent::initContent();
  644. $this->initPageHeaderToolbar();
  645. // re-defines fields_list
  646. $this->fields_list = array(
  647. 'supplier_reference' => array(
  648. 'title' => $this->l('Supplier reference'),
  649. 'orderby' => false,
  650. 'filter' => false,
  651. 'search' => false,
  652. ),
  653. 'reference' => array(
  654. 'title' => $this->l('Reference'),
  655. 'orderby' => false,
  656. 'filter' => false,
  657. 'search' => false,
  658. ),
  659. 'ean13' => array(
  660. 'title' => $this->l('EAN-13 or JAN barcode'),
  661. 'orderby' => false,
  662. 'filter' => false,
  663. 'search' => false,
  664. ),
  665. 'upc' => array(
  666. 'title' => $this->l('UPC barcode'),
  667. 'orderby' => false,
  668. 'filter' => false,
  669. 'search' => false,
  670. ),
  671. 'name' => array(
  672. 'title' => $this->l('Name'),
  673. 'orderby' => false,
  674. 'filter' => false,
  675. 'search' => false,
  676. ),
  677. 'quantity_received_today' => array(
  678. 'title' => $this->l('Quantity received today?'),
  679. 'type' => 'editable',
  680. 'orderby' => false,
  681. 'filter' => false,
  682. 'search' => false,
  683. 'hint' => $this->l('The quantity of supplies that you received today.'),
  684. ),
  685. 'quantity_received' => array(
  686. 'title' => $this->l('Quantity received'),
  687. 'orderby' => false,
  688. 'filter' => false,
  689. 'search' => false,
  690. 'badge_danger' => true,
  691. 'badge_success' => true,
  692. 'hint' => $this->l('The quantity of supplies that you received so far (today and the days before, if it applies).'),
  693. ),
  694. 'quantity_expected' => array(
  695. 'title' => $this->l('Quantity expected'),
  696. 'orderby' => false,
  697. 'filter' => false,
  698. 'search' => false,
  699. ),
  700. 'quantity_left' => array(
  701. 'title' => $this->l('Quantity left'),
  702. 'orderby' => false,
  703. 'filter' => false,
  704. 'search' => false,
  705. 'hint' => $this->l('The quantity of supplies left to receive for this order.'),
  706. )
  707. );
  708. // attributes override
  709. unset($this->_select, $this->_join, $this->_where, $this->_orderBy, $this->_orderWay, $this->_group, $this->_filterHaving, $this->_filter);
  710. $this->table = 'supply_order_detail';
  711. $this->identifier = 'id_supply_order_detail';
  712. $this->className = 'SupplyOrderDetail';
  713. $this->list_simple_header = false;
  714. $this->list_no_link = true;
  715. $this->colorOnBackground = true;
  716. $this->row_hover = false;
  717. $this->bulk_actions = array('Update' => array('text' => $this->l('Update selected'), 'confirm' => $this->l('Update selected items?')));
  718. $this->addRowAction('details');
  719. // sets toolbar title with order reference
  720. $this->toolbar_title = sprintf($this->l('Receipt of products for supply order #%s'), $supply_order->reference);
  721. $this->lang = false;
  722. $lang_id = (int)$this->context->language->id; //employee lang
  723. // gets values corresponding to fields_list
  724. $this->_select = '
  725. a.id_supply_order_detail as id,
  726. a.quantity_received as quantity_received,
  727. a.quantity_expected as quantity_expected,
  728. IF (a.quantity_expected < a.quantity_received, 0, a.quantity_expected - a.quantity_received) as quantity_left,
  729. IF (a.quantity_expected < a.quantity_received, 0, a.quantity_expected - a.quantity_received) as quantity_received_today,
  730. IF (a.quantity_expected = a.quantity_received, 1, 0) badge_success,
  731. IF (a.quantity_expected > a.quantity_received, 1, 0) badge_danger';
  732. $this->_where = 'AND a.`id_supply_order` = '.(int)$id_supply_order;
  733. $this->_group = 'GROUP BY a.id_supply_order_detail';
  734. // gets the list ordered by price desc, without limit
  735. $this->getList($lang_id, 'quantity_expected', 'DESC', 0, Tools::getValue('supply_order_pagination'), false);
  736. // defines action for POST
  737. $action = '&id_supply_order='.$id_supply_order.'&update_receipt=1';
  738. // unsets some buttons
  739. unset($this->toolbar_btn['export-csv-orders']);
  740. unset($this->toolbar_btn['export-csv-details']);
  741. unset($this->toolbar_btn['new']);
  742. $this->toolbar_btn['back'] = array(
  743. 'desc' => $this->l('Back'),
  744. 'href' => $this->context->link->getAdminLink('AdminSupplyOrders')
  745. );
  746. // renders list
  747. $helper = new HelperList();
  748. $this->setHelperDisplay($helper);
  749. $helper->actions = array('details');
  750. $helper->force_show_bulk_actions = true;
  751. $helper->override_folder = 'supply_orders_receipt_history/';
  752. $helper->toolbar_btn = $this->toolbar_btn;
  753. $helper->list_id = 'supply_order_detail';
  754. $helper->ajax_params = array(
  755. 'display_product_history' => 1,
  756. );
  757. $helper->currentIndex = self::$currentIndex.$action;
  758. // display these global order informations
  759. $this->displayInformation($this->l('This interface allows you to update the quantities of this ongoing order.').'<br />');
  760. $this->displayInformation($this->l('Be careful! Once you update, you cannot go back unless you add new negative stock movements.').'<br />');
  761. $this->displayInformation($this->l('A green line means that you\'ve received exactly the quantity you expected. A red line means that you\'ve received more than expected.').'<br />');
  762. // generates content
  763. $content = $helper->generateList($this->_list, $this->fields_list);
  764. // assigns var
  765. $this->context->smarty->assign(array(
  766. 'content' => $content,
  767. 'show_page_header_toolbar' => $this->show_page_header_toolbar,
  768. 'page_header_toolbar_title' => $this->page_header_toolbar_title,
  769. 'page_header_toolbar_btn' => $this->page_header_toolbar_btn
  770. ));
  771. }
  772. /**
  773. * AdminController::initContent() override
  774. * @see AdminController::initContent()
  775. */
  776. public function initContent()
  777. {
  778. if (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'))
  779. {
  780. $this->warnings[md5('PS_ADVANCED_STOCK_MANAGEMENT')] = $this->l('You need to activate the Advanced Stock Management feature prior to using this feature.');
  781. return false;
  782. }
  783. // Manage the add stock form
  784. if (Tools::isSubmit('changestate'))
  785. $this->initChangeStateContent();
  786. elseif (Tools::isSubmit('update_receipt') && Tools::isSubmit('id_supply_order'))
  787. $this->initUpdateReceiptContent();
  788. elseif (Tools::isSubmit('viewsupply_order') && Tools::isSubmit('id_supply_order'))
  789. {
  790. $this->action = 'view';
  791. $this->display = 'view';
  792. parent::initContent();
  793. }
  794. elseif (Tools::isSubmit('updatesupply_order'))
  795. $this->initUpdateSupplyOrderContent();
  796. else
  797. parent::initContent();
  798. }
  799. /**
  800. * Ths method manage associated products to the order when updating it
  801. */
  802. public function manageOrderProducts()
  803. {
  804. // load supply order
  805. $id_supply_order = (int)Tools::getValue('id_supply_order', null);
  806. $products_already_in_order = array();
  807. if ($id_supply_order != null)
  808. {
  809. $supply_order = new SupplyOrder($id_supply_order);
  810. if (Validate::isLoadedObject($supply_order))
  811. {
  812. // tests if the supplier or currency have changed in the supply order
  813. $new_supplier_id = (int)Tools::getValue('id_supplier');
  814. $new_currency_id = (int)Tools::getValue('id_currency');
  815. if (($new_supplier_id != $supply_order->id_supplier) ||
  816. ($new_currency_id != $supply_order->id_currency))
  817. {
  818. // resets all products in this order
  819. $supply_order->resetProducts();
  820. }
  821. else
  822. {
  823. $products_already_in_order = $supply_order->getEntries();
  824. $currency = new Currency($supply_order->id_ref_currency);
  825. // gets all product ids to manage
  826. $product_ids_str = Tools::getValue('product_ids', null);
  827. $product_ids = explode('|', $product_ids_str);
  828. $product_ids_to_delete_str = Tools::getValue('product_ids_to_delete', null);
  829. $product_ids_to_delete = array_unique(explode('|', $product_ids_to_delete_str));
  830. //delete products that are not managed anymore
  831. foreach ($products_already_in_order as $paio)
  832. {
  833. $product_ok = false;
  834. foreach ($product_ids_to_delete as $id)
  835. {
  836. $id_check = $paio['id_product'].'_'.$paio['id_product_attribute'];
  837. if ($id_check == $id)
  838. $product_ok = true;
  839. }
  840. if ($product_ok === true)
  841. {
  842. $entry = new SupplyOrderDetail($paio['id_supply_order_detail']);
  843. $entry->delete();
  844. }
  845. }
  846. // manage each product
  847. foreach ($product_ids as $id)
  848. {
  849. $errors = array();
  850. // check if a checksum is available for this product and test it
  851. $check = Tools::getValue('input_check_'.$id, '');
  852. $check_valid = md5(_COOKIE_KEY_.$id);
  853. if ($check_valid != $check)
  854. continue;
  855. $pos = strpos($id, '_');
  856. if ($pos === false)
  857. continue;
  858. // Load / Create supply order detail
  859. $entry = new SupplyOrderDetail();
  860. $id_supply_order_detail = (int)Tools::getValue('input_id_'.$id, 0);
  861. if ($id_supply_order_detail > 0)
  862. {
  863. $existing_entry = new SupplyOrderDetail($id_supply_order_detail);
  864. if (Validate::isLoadedObject($supply_order))
  865. $entry = &$existing_entry;
  866. }
  867. // get product informations
  868. $entry->id_product = substr($id, 0, $pos);
  869. $entry->id_product_attribute = substr($id, $pos + 1);
  870. $entry->unit_price_te = (float)str_replace(array(' ', ','), array('', '.'), Tools::getValue('input_unit_price_te_'.$id, 0));
  871. $entry->quantity_expected = (int)str_replace(array(' ', ','), array('', '.'), Tools::getValue('input_quantity_expected_'.$id, 0));
  872. $entry->discount_rate = (float)str_replace(array(' ', ','), array('', '.'), Tools::getValue('input_discount_rate_'.$id, 0));
  873. $entry->tax_rate = (float)str_replace(array(' ', ','), array('', '.'), Tools::getValue('input_tax_rate_'.$id, 0));
  874. $entry->reference = Tools::getValue('input_reference_'.$id, '');
  875. $entry->supplier_reference = Tools::getValue('input_supplier_reference_'.$id, '');
  876. $entry->ean13 = Tools::getValue('input_ean13_'.$id, '');
  877. $entry->upc = Tools::getValue('input_upc_'.$id, '');
  878. //get the product name in the order language
  879. $entry->name = Product::getProductName($entry->id_product, $entry->id_product_attribute, $supply_order->id_lang);
  880. if (empty($entry->name))
  881. $entry->name = '';
  882. if ($entry->supplier_reference == null)
  883. $entry->supplier_reference = '';
  884. $entry->exchange_rate = $currency->conversion_rate;
  885. $entry->id_currency = $currency->id;
  886. $entry->id_supply_order = $supply_order->id;
  887. $errors = $entry->validateController();
  888. //get the product name displayed in the backoffice according to the employee language
  889. $entry->name_displayed = Tools::getValue('input_name_displayed_'.$id, '');
  890. // if there is a problem, handle error for the current product
  891. if (count($errors) > 0)
  892. {
  893. // add the product to error array => display again product line
  894. $this->order_products_errors[] = array(
  895. 'id_product' => $entry->id_product,
  896. 'id_product_attribute' => $entry->id_product_attribute,
  897. 'unit_price_te' => $entry->unit_price_te,
  898. 'quantity_expected' => $entry->quantity_expected,
  899. 'discount_rate' => $entry->discount_rate,
  900. 'tax_rate' => $entry->tax_rate,
  901. 'name' => $entry->name,
  902. 'name_displayed' => $entry->name_displayed,
  903. 'reference' => $entry->reference,
  904. 'supplier_reference' => $entry->supplier_reference,
  905. 'ean13' => $entry->ean13,
  906. 'upc' => $entry->upc,
  907. );
  908. $error_str = '<ul>';
  909. foreach ($errors as $e)
  910. $error_str .= '<li>'.sprintf($this->l('Field: %s'), $e).'</li>';
  911. $error_str .= '</ul>';
  912. $this->errors[] = sprintf(Tools::displayError('Please verify the product information for "%s":'), $entry->name).' '.$error_str;
  913. }
  914. else
  915. $entry->save();
  916. }
  917. }
  918. }
  919. }
  920. }
  921. /**
  922. * AdminController::postProcess() override
  923. * @see AdminController::postProcess()
  924. */
  925. public function postProcess()
  926. {
  927. $this->is_editing_order = false;
  928. // Checks access
  929. if (Tools::isSubmit('submitAddsupply_order') && !($this->tabAccess['add'] === '1'))
  930. $this->errors[] = Tools::displayError('You do not have permission to add a supply order.');
  931. if (Tools::isSubmit('submitBulkUpdatesupply_order_detail') && !($this->tabAccess['edit'] === '1'))
  932. $this->errors[] = Tools::displayError('You do not have permission to edit an order.');
  933. // Trick to use both Supply Order as template and actual orders
  934. if (Tools::isSubmit('is_template'))
  935. $_GET['mod'] = 'template';
  936. // checks if supply order reference is unique
  937. if (Tools::isSubmit('reference'))
  938. {
  939. // gets the reference
  940. $ref = pSQL(Tools::getValue('reference'));
  941. if (Tools::getValue('id_supply_order') != 0 && SupplyOrder::getReferenceById((int)Tools::getValue('id_supply_order')) != $ref)
  942. {
  943. if ((int)SupplyOrder::exists($ref) != 0)
  944. $this->errors[] = Tools::displayError('The reference has to be unique.');
  945. }
  946. else if (Tools::getValue('id_supply_order') == 0 && (int)SupplyOrder::exists($ref) != 0)
  947. $this->errors[] = Tools::displayError('The reference has to be unique.');
  948. }
  949. if ($this->errors)
  950. return;
  951. // Global checks when add / update a supply order
  952. if (Tools::isSubmit('submitAddsupply_order') || Tools::isSubmit('submitAddsupply_orderAndStay'))
  953. {
  954. $this->action = 'save';
  955. $this->is_editing_order = true;
  956. // get supplier ID
  957. $id_supplier = (int)Tools::getValue('id_supplier', 0);
  958. if ($id_supplier <= 0 || !Supplier::supplierExists($id_supplier))
  959. $this->errors[] = Tools::displayError('The selected supplier is not valid.');
  960. // get warehouse id
  961. $id_warehouse = (int)Tools::getValue('id_warehouse', 0);
  962. if ($id_warehouse <= 0 || !Warehouse::exists($id_warehouse))
  963. $this->errors[] = Tools::displayError('The selected warehouse is not valid.');
  964. // get currency id
  965. $id_currency = (int)Tools::getValue('id_currency', 0);
  966. if ($id_currency <= 0 || ( !($result = Currency::getCurrency($id_currency)) || empty($result) ))
  967. $this->errors[] = Tools::displayError('The selected currency is not valid.');
  968. // get delivery date
  969. if (Tools::getValue('mod') != 'template' && strtotime(Tools::getValue('date_delivery_expected')) <= strtotime('-1 day'))
  970. $this->errors[] = Tools::displayError('The specified date cannot be in the past.');
  971. // gets threshold
  972. $quantity_threshold = Tools::getValue('load_products');
  973. if (is_numeric($quantity_threshold))
  974. $quantity_threshold = (int)$quantity_threshold;
  975. else
  976. $quantity_threshold = null;
  977. if (!count($this->errors))
  978. {
  979. // forces date for templates
  980. if (Tools::isSubmit('is_template') && !Tools::getValue('date_delivery_expected'))
  981. $_POST['date_delivery_expected'] = date('Y-m-d h:i:s');
  982. // specify initial state
  983. $_POST['id_supply_order_state'] = 1; //defaut creation state
  984. // specify global reference currency
  985. $_POST['id_ref_currency'] = Currency::getDefaultCurrency()->id;
  986. // specify supplier name
  987. $_POST['supplier_name'] = Supplier::getNameById($id_supplier);
  988. //specific discount check
  989. $_POST['discount_rate'] = (float)str_replace(array(' ', ','), array('', '.'), Tools::getValue('discount_rate', 0));
  990. }
  991. // manage each associated product
  992. $this->manageOrderProducts();
  993. // if the threshold is defined and we are saving the order
  994. if (Tools::isSubmit('submitAddsupply_order') && Validate::isInt($quantity_threshold))
  995. $this->loadProducts((int)$quantity_threshold);
  996. }
  997. // Manage state change
  998. if (Tools::isSubmit('submitChangestate')
  999. && Tools::isSubmit('id_supply_order')
  1000. && Tools::isSubmit('id_supply_order_state'))
  1001. {
  1002. if ($this->tabAccess['edit'] != '1')
  1003. $this->errors[] = Tools::displayError('You do not have permission to change the order status.');
  1004. // get state ID
  1005. $id_state = (int)Tools::getValue('id_supply_order_state', 0);
  1006. if ($id_state <= 0)
  1007. $this->errors[] = Tools::displayError('The selected supply order status is not valid.');
  1008. // get supply order ID
  1009. $id_supply_order = (int)Tools::getValue('id_supply_order', 0);
  1010. if ($id_supply_order <= 0)
  1011. $this->errors[] = Tools::displayError('The supply order ID is not valid.');
  1012. if (!count($this->errors))
  1013. {
  1014. // try to load supply order
  1015. $supply_order = new SupplyOrder($id_supply_order);
  1016. if (Validate::isLoadedObject($supply_order))
  1017. {
  1018. // get valid available possible states for this order
  1019. $states = SupplyOrderState::getSupplyOrderStates($supply_order->id_supply_order_state);
  1020. foreach ($states as $state)
  1021. {
  1022. // if state is valid, change it in the order
  1023. if ($id_state == $state['id_supply_order_state'])
  1024. {
  1025. $new_state = new SupplyOrderState($id_state);
  1026. $old_state = new SupplyOrderState($supply_order->id_supply_order_state);
  1027. // special case of validate state - check if there are products in the order and the required state is not an enclosed state
  1028. if ($supply_order->isEditable() && !$supply_order->hasEntries() && !$new_state->enclosed)
  1029. $this->errors[] = Tools::displayError('It is not possible to change the status of this order because you did not order any products.');
  1030. if (!count($this->errors))
  1031. {
  1032. $supply_order->id_supply_order_state = $state['id_supply_order_state'];
  1033. if ($supply_order->save())
  1034. {
  1035. // if pending_receipt,
  1036. // or if the order is being canceled,
  1037. // synchronizes StockAvailable
  1038. if (($new_state->pending_receipt && !$new_state->receipt_state) ||
  1039. ($old_state->receipt_state && $new_state->enclosed && !$new_state->receipt_state))
  1040. {
  1041. $supply_order_details = $supply_order->getEntries();
  1042. $products_done = array();
  1043. foreach ($supply_order_details as $supply_order_detail)
  1044. {
  1045. if (!in_array($supply_order_detail['id_product'], $products_done))
  1046. {
  1047. StockAvailable::synchronize($supply_order_detail['id_product']);
  1048. $products_done[] = $supply_order_detail['id_product'];
  1049. }
  1050. }
  1051. }
  1052. $token = Tools::getValue('token') ? Tools::getValue('token') : $this->token;
  1053. $redirect = self::$currentIndex.'&token='.$token;
  1054. $this->redirect_after = $redirect.'&conf=5';
  1055. }
  1056. }
  1057. }
  1058. }
  1059. }
  1060. else
  1061. $this->errors[] = Tools::displayError('The selected supplier is not valid.');
  1062. }
  1063. }
  1064. // updates receipt
  1065. if (Tools::isSubmit('submitBulkUpdatesupply_order_detail') && Tools::isSubmit('id_supply_order'))
  1066. $this->postProcessUpdateReceipt();
  1067. // use template to create a supply order
  1068. if (Tools::isSubmit('create_supply_order') && Tools::isSubmit('id_supply_order'))
  1069. $this->postProcessCopyFromTemplate();
  1070. if ((!count($this->errors) && $this->is_editing_order) || !$this->is_editing_order)
  1071. parent::postProcess();
  1072. }
  1073. /**
  1074. * Exports CSV
  1075. */
  1076. protected function renderCSV()
  1077. {
  1078. // exports orders
  1079. if (Tools::isSubmit('csv_orders'))
  1080. {
  1081. $ids = array();
  1082. foreach ($this->_list as $entry)
  1083. $ids[] = $entry['id_supply_order'];
  1084. if (count($ids) <= 0)
  1085. return;
  1086. $id_lang = Context::getContext()->language->id;
  1087. $orders = new PrestaShopCollection('SupplyOrder', $id_lang);
  1088. $orders->where('is_template', '=', false);
  1089. $orders->where('id_supply_order', 'in', $ids);
  1090. $id_warehouse = $this->getCurrentWarehouse();
  1091. if ($id_warehouse != -1)
  1092. $orders->where('id_warehouse', '=', $id_warehouse);
  1093. $orders->getAll();
  1094. $csv = new CSV($orders, $this->l('supply_orders'));
  1095. $csv->export();
  1096. }
  1097. // exports details for all orders
  1098. else if (Tools::isSubmit('csv_orders_details'))
  1099. {
  1100. // header
  1101. header('Content-type: text/csv');
  1102. header('Content-Type: application/force-download; charset=UTF-8');
  1103. header('Cache-Control: no-store, no-cache');
  1104. header('Content-disposition: attachment; filename="'.$this->l('supply_orders_details').'.csv"');
  1105. // echoes details
  1106. $ids = array();
  1107. foreach ($this->_list as $entry)
  1108. $ids[] = $entry['id_supply_order'];
  1109. if (count($ids) <= 0)
  1110. return;
  1111. // for each supply order
  1112. $keys = array('id_product', 'id_product_attribute', 'reference', 'supplier_reference', 'ean13', 'upc', 'name',
  1113. 'unit_price_te', 'quantity_expected', 'quantity_received', 'price_te', 'discount_rate', 'discount_value_te',
  1114. 'price_with_discount_te', 'tax_rate', 'tax_value', 'price_ti', 'tax_value_with_order_discount',
  1115. 'price_with_order_discount_te', 'id_supply_order');
  1116. echo sprintf("%s\n", implode(';', array_map(array('CSVCore', 'wrap'), $keys)));
  1117. // overrides keys (in order to add FORMAT calls)
  1118. $keys = array('sod.id_product', 'sod.id_product_attribute', 'sod.reference', 'sod.supplier_reference', 'sod.ean13',
  1119. 'sod.upc', 'sod.name',
  1120. 'FORMAT(sod.unit_price_te, 2)', 'sod.quantity_expected', 'sod.quantity_received', 'FORMAT(sod.price_te, 2)',
  1121. 'FORMAT(sod.discount_rate, 2)', 'FORMAT(sod.discount_value_te, 2)',
  1122. 'FORMAT(sod.price_with_discount_te, 2)', 'FORMAT(sod.tax_rate, 2)', 'FORMAT(sod.tax_value, 2)',
  1123. 'FORMAT(sod.price_ti, 2)', 'FORMAT(sod.tax_value_with_order_discount, 2)',
  1124. 'FORMAT(sod.price_with_order_discount_te, 2)', 'sod.id_supply_order');
  1125. foreach ($ids as $id)
  1126. {
  1127. $query = new DbQuery();
  1128. $query->select(implode(', ', $keys));
  1129. $query->from('supply_order_detail', 'sod');
  1130. $query->leftJoin('supply_order', 'so', 'so.id_supply_order = sod.id_supply_order');
  1131. $id_warehouse = $this->getCurrentWarehouse();
  1132. if ($id_warehouse != -1)
  1133. $query->where('so.id_warehouse = '.(int)$id_warehouse);
  1134. $query->where('sod.id_supply_order = '.(int)$id);
  1135. $query->orderBy('sod.id_supply_order_detail DESC');
  1136. $resource = Db::getInstance()->query($query);
  1137. // gets details
  1138. while ($row = Db::getInstance()->nextRow($resource))
  1139. echo sprintf("%s\n", implode(';', array_map(array('CSVCore', 'wrap'), $row)));
  1140. }
  1141. }
  1142. // exports details for the given order
  1143. else if (Tools::isSubmit('csv_order_details') && Tools::getValue('id_supply_order'))
  1144. {
  1145. $supply_order = new SupplyOrder((int)Tools::getValue('id_supply_order'));
  1146. if (Validate::isLoadedObject($supply_order))
  1147. {
  1148. $details = $supply_order->getEntriesCollection();
  1149. $details->getAll();
  1150. $csv = new CSV($details, $this->l('supply_order').'_'.$supply_order->reference.'_details');
  1151. $csv->export();
  1152. }
  1153. }
  1154. }
  1155. /**
  1156. * Helper function for AdminSupplyOrdersController::postProcess()
  1157. *
  1158. * @see AdminSupplyOrdersController::postProcess()
  1159. */
  1160. protected function postProcessUpdateReceipt()
  1161. {
  1162. // gets all box selected
  1163. $rows = Tools::getValue('supply_order_detailBox');
  1164. if (!$rows)
  1165. {
  1166. $this->errors[] = Tools::displayError('You did not select any products to update.');
  1167. return;
  1168. }
  1169. // final array with id_supply_order_detail and value to update
  1170. $to_update = array();
  1171. // gets quantity for each id_order_detail
  1172. foreach ($rows as $row)
  1173. {
  1174. if (Tools::getValue('quantity_received_today_'.$row))
  1175. $to_update[$row] = (int)Tools::getValue('quantity_received_today_'.$row);
  1176. }
  1177. // checks if there is something to update
  1178. if (!count($to_update))
  1179. {
  1180. $this->errors[] = Tools::displayError('You did not select any products to update.');
  1181. return;
  1182. }
  1183. $totaly_received = true;
  1184. foreach ($to_update as $id_supply_order_detail => $quantity)
  1185. {
  1186. $supply_order_detail = new SupplyOrderDetail($id_supply_order_detail);
  1187. $supply_order = new SupplyOrder((int)Tools::getValue('id_supply_order'));
  1188. if (Validate::isLoadedObject($supply_order_detail) && Validate::isLoadedObject($supply_order))
  1189. {
  1190. // checks if quantity is valid
  1191. // It's possible to receive more quantity than expected in case of a shipping error from the supplier
  1192. if (!Validate::isInt($quantity) || $quantity <= 0)
  1193. $this->errors[] = sprintf(Tools::displayError('Quantity (%d) for product #%d is not valid'), (int)$quantity, (int)$id_supply_order_detail);
  1194. else // everything is valid : updates
  1195. {
  1196. if ((int)$quantity < (int)$supply_order_detail->quantity_expected)
  1197. $totaly_received = false;
  1198. // creates the history
  1199. $supplier_receipt_history = new SupplyOrderReceiptHistory();
  1200. $supplier_receipt_history->id_supply_order_detail = (int)$id_supply_order_detail;
  1201. $supplier_receipt_history->id_employee = (int)$this->context->employee->id;
  1202. $supplier_receipt_history->employee_firstname = pSQL($this->context->employee->firstname);
  1203. $supplier_receipt_history->employee_lastname = pSQL($this->context->employee->lastname);
  1204. $supplier_receipt_history->id_supply_order_state = (int)$supply_order->id_supply_order_state;
  1205. $supplier_receipt_history->quantity = (int)$quantity;
  1206. // updates quantity received
  1207. $supply_order_detail->quantity_received += (int)$quantity;
  1208. // if current state is "Pending receipt", then we sets it to "Order received in part"
  1209. if (3 == $supply_order->id_supply_order_state)
  1210. $supply_order->id_supply_order_state = 4;
  1211. // Adds to stock
  1212. $warehouse = new Warehouse($supply_order->id_warehouse);
  1213. if (!Validate::isLoadedObject($warehouse))
  1214. {
  1215. $this->errors[] = Tools::displayError('The warehouse could not be loaded.');
  1216. return;
  1217. }
  1218. $price = $supply_order_detail->unit_price_te;
  1219. // converts the unit price to the warehouse currency if needed
  1220. if ($supply_order->id_currency != $warehouse->id_currency)
  1221. {
  1222. // first, converts the price to the default currency
  1223. $price_converted_to_default_currency = Tools::convertPrice($supply_order_detail->unit_price_te, $supply_order->id_currency, false);
  1224. // then, converts the newly calculated pri-ce from the default currency to the needed currency
  1225. $price = Tools::ps_round(Tools::convertPrice($price_converted_to_default_currency,
  1226. $warehouse->id_currency,
  1227. true),
  1228. 6);
  1229. }
  1230. $manager = StockManagerFactory::getManager();
  1231. $res = $manager->addProduct($supply_order_detail->id_product,
  1232. $supply_order_detail->id_product_attribute,
  1233. $warehouse,
  1234. (int)$quantity,
  1235. Configuration::get('PS_STOCK_MVT_SUPPLY_ORDER'),
  1236. $price,
  1237. true,
  1238. $supply_order->id);
  1239. $location = Warehouse::getProductLocation($supply_order_detail->id_product,
  1240. $supply_order_detail->id_product_attribute,
  1241. $warehouse->id);
  1242. $res = Warehouse::setProductlocation($supply_order_detail->id_product,
  1243. $supply_order_detail->id_product_attribute,
  1244. $warehouse->id,

Large files files are truncated, but you can click here to view the full file