PageRenderTime 48ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/stock/SupplyOrder.php

https://bitbucket.org/enurkov/prestashop
PHP | 531 lines | 269 code | 79 blank | 183 comment | 25 complexity | a890083b462cea13df1dea4f4486adb9 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 SupplyOrderCore extends ObjectModel
  30. {
  31. /**
  32. * @var int Supplier
  33. */
  34. public $id_supplier;
  35. /**
  36. * @var string Supplier Name
  37. */
  38. public $supplier_name;
  39. /**
  40. * @var int The language id used on the delivery note
  41. */
  42. public $id_lang;
  43. /**
  44. * @var int Warehouse where products will be delivered
  45. */
  46. public $id_warehouse;
  47. /**
  48. * @var int Current state of the order
  49. */
  50. public $id_supply_order_state;
  51. /**
  52. * @var int Currency used for the order
  53. */
  54. public $id_currency;
  55. /**
  56. * @var int Currency used by default in main global configuration (i.e. by default for all shops)
  57. */
  58. public $id_ref_currency;
  59. /**
  60. * @var string Reference of the order
  61. */
  62. public $reference;
  63. /**
  64. * @var string Date when added
  65. */
  66. public $date_add;
  67. /**
  68. * @var string Date when updated
  69. */
  70. public $date_upd;
  71. /**
  72. * @var string Expected delivery date
  73. */
  74. public $date_delivery_expected;
  75. /**
  76. * @var float Total price without tax
  77. */
  78. public $total_te = 0;
  79. /**
  80. * @var float Total price after discount, without tax
  81. */
  82. public $total_with_discount_te = 0;
  83. /**
  84. * @var float Total price with tax
  85. */
  86. public $total_ti = 0;
  87. /**
  88. * @var float Total tax value
  89. */
  90. public $total_tax = 0;
  91. /**
  92. * @var float Supplier discount rate (for the whole order)
  93. */
  94. public $discount_rate = 0;
  95. /**
  96. * @var float Supplier discount value without tax (for the whole order)
  97. */
  98. public $discount_value_te = 0;
  99. /**
  100. * @var int Tells if this order is a template
  101. */
  102. public $is_template = 0;
  103. /**
  104. * @see ObjectModel::$definition
  105. */
  106. public static $definition = array(
  107. 'table' => 'supply_order',
  108. 'primary' => 'id_supply_order',
  109. 'fields' => array(
  110. 'id_supplier' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
  111. 'supplier_name' => array('type' => self::TYPE_STRING, 'validate' => 'isCatalogName', 'required' => false),
  112. 'id_lang' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
  113. 'id_warehouse' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
  114. 'id_supply_order_state' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
  115. 'id_currency' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
  116. 'id_ref_currency' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
  117. 'reference' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true),
  118. 'date_delivery_expected' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => true),
  119. 'total_te' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
  120. 'total_with_discount_te' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
  121. 'total_ti' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
  122. 'total_tax' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
  123. 'discount_rate' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => false),
  124. 'discount_value_te' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
  125. 'is_template' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
  126. 'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
  127. 'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
  128. ),
  129. );
  130. /**
  131. * @see ObjectModel::$webserviceParameters
  132. */
  133. protected $webserviceParameters = array(
  134. 'fields' => array(
  135. 'id_supplier' => array('xlink_resource' => 'suppliers'),
  136. 'id_lang' => array('xlink_resource' => 'languages'),
  137. 'id_warehouse' => array('xlink_resource' => 'warehouses'),
  138. 'id_supply_order_state' => array('xlink_resource' => 'supply_order_states'),
  139. 'id_currency' => array('xlink_resource' => 'currencies'),
  140. ),
  141. 'hidden_fields' => array(
  142. 'id_ref_currency',
  143. ),
  144. 'associations' => array(
  145. 'supply_order_details' => array(
  146. 'resource' => 'supply_order_detail',
  147. 'fields' => array(
  148. 'id' => array(),
  149. 'id_product' => array(),
  150. 'id_product_attribute' => array(),
  151. 'supplier_reference' => array(),
  152. 'product_name' => array(),
  153. ),
  154. ),
  155. ),
  156. );
  157. /**
  158. * @see ObjectModel::update()
  159. */
  160. public function update($null_values = false)
  161. {
  162. $this->calculatePrices();
  163. $res = parent::update($null_values);
  164. if ($res && !$this->is_template)
  165. $this->addHistory();
  166. return $res;
  167. }
  168. /**
  169. * @see ObjectModel::add()
  170. */
  171. public function add($autodate = true, $null_values = false)
  172. {
  173. $this->calculatePrices();
  174. $res = parent::add($autodate, $null_values);
  175. if ($res && !$this->is_template)
  176. $this->addHistory();
  177. return $res;
  178. }
  179. /**
  180. * Checks all products in this order and calculate prices
  181. * Applies the global discount if necessary
  182. */
  183. protected function calculatePrices()
  184. {
  185. $this->total_te = 0;
  186. $this->total_with_discount_te = 0;
  187. $this->total_tax = 0;
  188. $this->total_ti = 0;
  189. $is_discount = false;
  190. if (is_numeric($this->discount_rate) && (float)$this->discount_rate >= 0)
  191. $is_discount = true;
  192. // gets all product entries in this order
  193. $entries = $this->getEntriesCollection();
  194. foreach ($entries as $entry)
  195. {
  196. // applys global discount rate on each product if possible
  197. if ($is_discount)
  198. $entry->applyGlobalDiscount((float)$this->discount_rate);
  199. // adds new prices to the total
  200. $this->total_te += $entry->price_with_discount_te;
  201. $this->total_with_discount_te += $entry->price_with_order_discount_te;
  202. $this->total_tax += $entry->tax_value_with_order_discount;
  203. $this->total_ti = $this->total_tax + $this->total_with_discount_te;
  204. }
  205. // applies global discount rate if possible
  206. if ($is_discount)
  207. $this->discount_value_te = $this->total_te - $this->total_with_discount_te;
  208. }
  209. /**
  210. * Retrieves the product entries for the current order
  211. *
  212. * @param int $id_lang Optional Id Lang - Uses Context::language::id by default
  213. * @return array
  214. */
  215. public function getEntries($id_lang = null)
  216. {
  217. if ($id_lang == null)
  218. $id_lang = Context::getContext()->language->id;
  219. // build query
  220. $query = new DbQuery();
  221. $query->select('
  222. s.*,
  223. IFNULL(CONCAT(pl.name, \' : \', GROUP_CONCAT(agl.name, \' - \', al.name SEPARATOR \', \')), pl.name) as name_displayed');
  224. $query->from('supply_order_detail', 's');
  225. $query->innerjoin('product_lang', 'pl', 'pl.id_product = s.id_product AND pl.id_lang = '.$id_lang);
  226. $query->leftjoin('product', 'p', 'p.id_product = s.id_product');
  227. $query->leftjoin('product_attribute_combination', 'pac', 'pac.id_product_attribute = s.id_product_attribute');
  228. $query->leftjoin('attribute', 'atr', 'atr.id_attribute = pac.id_attribute');
  229. $query->leftjoin('attribute_lang', 'al', 'al.id_attribute = atr.id_attribute AND al.id_lang = '.$id_lang);
  230. $query->leftjoin('attribute_group_lang', 'agl', 'agl.id_attribute_group = atr.id_attribute_group AND agl.id_lang = '.$id_lang);
  231. $query->where('s.id_supply_order = '.(int)$this->id);
  232. $query->groupBy('s.id_supply_order_detail');
  233. return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query);
  234. }
  235. /**
  236. * Retrieves the details entries (i.e. products) collection for the current order
  237. *
  238. * @return Collection of SupplyOrderDetail
  239. */
  240. public function getEntriesCollection()
  241. {
  242. $details = new Collection('SupplyOrderDetail');
  243. $details->where('id_supply_order', '=', $this->id);
  244. return $details;
  245. }
  246. /**
  247. * Check if the order has entries
  248. *
  249. * @return bool Has/Has not
  250. */
  251. public function hasEntries()
  252. {
  253. $query = new DbQuery();
  254. $query->select('COUNT(*)');
  255. $query->from('supply_order_detail', 's');
  256. $query->where('s.id_supply_order = '.(int)$this->id);
  257. return (Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query) > 0);
  258. }
  259. /**
  260. * Check if the current state allows to edit the current order
  261. *
  262. * @return bool
  263. */
  264. public function isEditable()
  265. {
  266. $query = new DbQuery();
  267. $query->select('s.editable');
  268. $query->from('supply_order_state', 's');
  269. $query->where('s.id_supply_order_state = '.(int)$this->id_supply_order_state);
  270. return (Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query) == 1);
  271. }
  272. /**
  273. * Checks if the current state allows to generate a delivery note for this order
  274. *
  275. * @return bool
  276. */
  277. public function isDeliveryNoteAvailable()
  278. {
  279. $query = new DbQuery();
  280. $query->select('s.delivery_note');
  281. $query->from('supply_order_state', 's');
  282. $query->where('s.id_supply_order_state = '.(int)$this->id_supply_order_state);
  283. return (Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query) == 1);
  284. }
  285. /**
  286. * Checks if the current state allows to add products in stock
  287. *
  288. * @return bool
  289. */
  290. public function isInReceiptState()
  291. {
  292. $query = new DbQuery();
  293. $query->select('s.receipt_state');
  294. $query->from('supply_order_state', 's');
  295. $query->where('s.id_supply_order_state = '.(int)$this->id_supply_order_state);
  296. return (Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query) == 1);
  297. }
  298. /**
  299. * Historizes the order : its id, its state, and the employee responsible for the current action
  300. */
  301. protected function addHistory()
  302. {
  303. $context = Context::getContext();
  304. $history = new SupplyOrderHistory();
  305. $history->id_supply_order = $this->id;
  306. $history->id_state = $this->id_supply_order_state;
  307. $history->id_employee = (int)$context->employee->id;
  308. $history->employee_firstname = pSQL($context->employee->firstname);
  309. $history->employee_lastname = pSQL($context->employee->lastname);
  310. $history->save();
  311. }
  312. /**
  313. * Removes all products from the order
  314. */
  315. public function resetProducts()
  316. {
  317. $products = $this->getEntriesCollection();
  318. foreach ($products as $p)
  319. $p->delete();
  320. }
  321. /**
  322. * For a given $id_warehouse, tells if it has pending supply orders
  323. *
  324. * @param int $id_warehouse
  325. * @return bool
  326. */
  327. public static function warehouseHasPendingOrders($id_warehouse)
  328. {
  329. if (!$id_warehouse)
  330. return false;
  331. $query = new DbQuery();
  332. $query->select('COUNT(so.id_supply_order) as supply_orders');
  333. $query->from('supply_order', 'so');
  334. $query->leftJoin('supply_order_state', 'sos', 'so.id_supply_order_state = sos.id_supply_order_state');
  335. $query->where('sos.enclosed != 1');
  336. $query->where('so.id_warehouse = '.(int)$id_warehouse);
  337. $res = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
  338. return ($res > 0);
  339. }
  340. /**
  341. * For a given $id_supplier, tells if it has pending supply orders
  342. *
  343. * @param int $id_supplier Id Supplier
  344. * @return bool
  345. */
  346. public static function supplierHasPendingOrders($id_supplier)
  347. {
  348. if (!$id_supplier)
  349. return false;
  350. $query = new DbQuery();
  351. $query->select('COUNT(so.id_supply_order) as supply_orders');
  352. $query->from('supply_order', 'so');
  353. $query->leftJoin('supply_order_state', 'sos', 'so.id_supply_order_state = sos.id_supply_order_state');
  354. $query->where('sos.enclosed != 1');
  355. $query->where('so.id_supplier = '.(int)$id_supplier);
  356. $res = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
  357. return ($res > 0);
  358. }
  359. /**
  360. * For a given id or reference, tells if the supply order exists
  361. *
  362. * @param int|string $match Either the reference of the order, or the Id of the order
  363. * @return int SupplyOrder Id
  364. */
  365. public static function exists($match)
  366. {
  367. if (!$match)
  368. return false;
  369. $query = new DbQuery();
  370. $query->select('id_supply_order');
  371. $query->from('supply_order', 'so');
  372. $query->where('so.id_supply_order = '.(int)$match.' OR so.reference = "'.pSQL($match).'"');
  373. $res = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
  374. return ((int)$res);
  375. }
  376. /**
  377. * For a given reference, returns the corresponding supply order
  378. *
  379. * @param string $reference Reference of the order
  380. * @return bool|SupplyOrder
  381. */
  382. public static function getSupplyOrderByReference($reference)
  383. {
  384. if (!$reference)
  385. return false;
  386. $query = new DbQuery();
  387. $query->select('id_supply_order');
  388. $query->from('supply_order', 'so');
  389. $query->where('so.reference = "'.pSQL($reference).'"');
  390. $id = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
  391. if ($id == false)
  392. return false;
  393. return (new SupplyOrder((int)$id));
  394. }
  395. /**
  396. * @see ObjectModel::hydrate()
  397. */
  398. public function hydrate(array $data, $id_lang = null)
  399. {
  400. $this->id_lang = $id_lang;
  401. if (isset($data[$this->def['primary']]))
  402. $this->id = $data[$this->def['primary']];
  403. foreach ($data as $key => $value)
  404. {
  405. if (array_key_exists($key, $this))
  406. {
  407. // formats prices and floats
  408. if ($this->def['fields'][$key]['validate'] == 'isFloat' ||
  409. $this->def['fields'][$key]['validate'] == 'isPrice')
  410. $value = Tools::ps_round($value, 6);
  411. $this->$key = $value;
  412. }
  413. }
  414. }
  415. /**
  416. * Gets the reference of a given order
  417. *
  418. * @param int $id_supply_order
  419. * @return bool|string
  420. */
  421. public static function getReferenceById($id_supply_order)
  422. {
  423. if (!$id_supply_order)
  424. return false;
  425. $query = new DbQuery();
  426. $query->select('so.reference');
  427. $query->from('supply_order', 'so');
  428. $query->where('so.id_supply_order = '.(int)$id_supply_order);
  429. $ref = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
  430. return (pSQL($ref));
  431. }
  432. /*********************************\
  433. *
  434. * Webservices Specific Methods
  435. *
  436. *********************************/
  437. /**
  438. * Webservice : gets the ids supply_order_detail associated to this order
  439. *
  440. * @return array
  441. */
  442. public function getWsSupplyOrderDetails()
  443. {
  444. $query = new DbQuery();
  445. $query->select('sod.id_supply_order_detail as id, sod.id_product,
  446. sod.id_product_attribute,
  447. sod.name as product_name, supplier_reference');
  448. $query->from('supply_order_detail', 'sod');
  449. $query->where('id_supply_order = '.(int)$this->id);
  450. return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query);
  451. }
  452. }