PageRenderTime 91ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/app/code/core/Mage/CatalogInventory/Model/Observer.php

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 835 lines | 477 code | 82 blank | 276 comment | 90 complexity | 7cbcdeed7350afbe824cbaffa001c233 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  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@magentocommerce.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 Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_CatalogInventory
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Catalog inventory module observer
  28. *
  29. * @category Mage
  30. * @package Mage_CatalogInventory
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_CatalogInventory_Model_Observer
  34. {
  35. /**
  36. * Product qty's checked
  37. * data is valid if you check quote item qty and use singleton instance
  38. *
  39. * @deprecated after 1.4.2.0-rc1
  40. * @var array
  41. */
  42. protected $_checkedProductsQty = array();
  43. /**
  44. * Product qty's checked
  45. * data is valid if you check quote item qty and use singleton instance
  46. *
  47. * @var array
  48. */
  49. protected $_checkedQuoteItems = array();
  50. protected $_itemsForReindex = array();
  51. /**
  52. * Array, indexed by product's id to contain stockItems of already loaded products
  53. * Some kind of singleton for product's stock item
  54. *
  55. * @var array
  56. */
  57. protected $_stockItemsArray = array();
  58. /**
  59. * Add stock information to product
  60. *
  61. * @param Varien_Event_Observer $observer
  62. * @return Mage_CatalogInventory_Model_Observer
  63. */
  64. public function addInventoryData($observer)
  65. {
  66. $product = $observer->getEvent()->getProduct();
  67. if ($product instanceof Mage_Catalog_Model_Product) {
  68. $productId = intval($product->getId());
  69. if (!isset($this->_stockItemsArray[$productId])) {
  70. $this->_stockItemsArray[$productId] = Mage::getModel('cataloginventory/stock_item');
  71. }
  72. $productStockItem = $this->_stockItemsArray[$productId];
  73. $productStockItem->assignProduct($product);
  74. }
  75. return $this;
  76. }
  77. /**
  78. * Remove stock information from static variable
  79. *
  80. * @param Varien_Event_Observer $observer
  81. * @return Mage_CatalogInventory_Model_Observer
  82. */
  83. public function removeInventoryData($observer)
  84. {
  85. $product = $observer->getEvent()->getProduct();
  86. if (($product instanceof Mage_Catalog_Model_Product)
  87. && $product->getId()
  88. && isset($this->_stockItemsArray[$product->getId()])) {
  89. unset($this->_stockItemsArray[$product->getId()]);
  90. }
  91. return $this;
  92. }
  93. /**
  94. * Add information about producs stock status to collection
  95. * Used in for product collection after load
  96. *
  97. * @param Varien_Event_Observer $observer
  98. * @return Mage_CatalogInventory_Model_Observer
  99. */
  100. public function addStockStatusToCollection($observer)
  101. {
  102. $productCollection = $observer->getEvent()->getCollection();
  103. if ($productCollection->hasFlag('require_stock_items')) {
  104. Mage::getModel('cataloginventory/stock')->addItemsToProducts($productCollection);
  105. } else {
  106. Mage::getModel('cataloginventory/stock_status')->addStockStatusToProducts($productCollection);
  107. }
  108. return $this;
  109. }
  110. /**
  111. * Add Stock items to product collection
  112. *
  113. * @param Varien_Event_Observer $observer
  114. * @return Mage_CatalogInventory_Model_Observer
  115. */
  116. public function addInventoryDataToCollection($observer)
  117. {
  118. $productCollection = $observer->getEvent()->getProductCollection();
  119. Mage::getModel('cataloginventory/stock')->addItemsToProducts($productCollection);
  120. return $this;
  121. }
  122. /**
  123. * Saving product inventory data. Product qty calculated dynamically.
  124. *
  125. * @param Varien_Event_Observer $observer
  126. * @return Mage_CatalogInventory_Model_Observer
  127. */
  128. public function saveInventoryData($observer)
  129. {
  130. $product = $observer->getEvent()->getProduct();
  131. if (is_null($product->getStockData())) {
  132. if ($product->getIsChangedWebsites() || $product->dataHasChangedFor('status')) {
  133. Mage::getSingleton('cataloginventory/stock_status')
  134. ->updateStatus($product->getId());
  135. }
  136. return $this;
  137. }
  138. $item = $product->getStockItem();
  139. if (!$item) {
  140. $item = Mage::getModel('cataloginventory/stock_item');
  141. }
  142. $this->_prepareItemForSave($item, $product);
  143. $item->save();
  144. return $this;
  145. }
  146. /**
  147. * Copy product inventory data (used for product duplicate functionality)
  148. *
  149. * @param Varien_Event_Observer $observer
  150. * @return Mage_CatalogInventory_Model_Observer
  151. */
  152. public function copyInventoryData($observer)
  153. {
  154. /** @var Mage_Catalog_Model_Product $currentProduct */
  155. $currentProduct = $observer->getEvent()->getCurrentProduct();
  156. /** @var Mage_Catalog_Model_Product $newProduct */
  157. $newProduct = $observer->getEvent()->getNewProduct();
  158. $newProduct->unsStockItem();
  159. $stockData = array(
  160. 'use_config_min_qty' => 1,
  161. 'use_config_min_sale_qty' => 1,
  162. 'use_config_max_sale_qty' => 1,
  163. 'use_config_backorders' => 1,
  164. 'use_config_notify_stock_qty'=> 1
  165. );
  166. if ($currentStockItem = $currentProduct->getStockItem()) {
  167. $stockData += array(
  168. 'use_config_enable_qty_increments' => $currentStockItem->getData('use_config_enable_qty_increments'),
  169. 'enable_qty_increments' => $currentStockItem->getData('enable_qty_increments'),
  170. 'use_config_qty_increments' => $currentStockItem->getData('use_config_qty_increments'),
  171. 'qty_increments' => $currentStockItem->getData('qty_increments'),
  172. );
  173. }
  174. $newProduct->setStockData($stockData);
  175. return $this;
  176. }
  177. /**
  178. * Prepare stock item data for save
  179. *
  180. * @param Mage_CatalogInventory_Model_Stock_Item $item
  181. * @param Mage_Catalog_Model_Product $product
  182. * @return Mage_CatalogInventory_Model_Observer
  183. */
  184. protected function _prepareItemForSave($item, $product)
  185. {
  186. $item->addData($product->getStockData())
  187. ->setProduct($product)
  188. ->setProductId($product->getId())
  189. ->setStockId($item->getStockId());
  190. if (!is_null($product->getData('stock_data/min_qty'))
  191. && is_null($product->getData('stock_data/use_config_min_qty'))) {
  192. $item->setData('use_config_min_qty', false);
  193. }
  194. if (!is_null($product->getData('stock_data/min_sale_qty'))
  195. && is_null($product->getData('stock_data/use_config_min_sale_qty'))) {
  196. $item->setData('use_config_min_sale_qty', false);
  197. }
  198. if (!is_null($product->getData('stock_data/max_sale_qty'))
  199. && is_null($product->getData('stock_data/use_config_max_sale_qty'))) {
  200. $item->setData('use_config_max_sale_qty', false);
  201. }
  202. if (!is_null($product->getData('stock_data/backorders'))
  203. && is_null($product->getData('stock_data/use_config_backorders'))) {
  204. $item->setData('use_config_backorders', false);
  205. }
  206. if (!is_null($product->getData('stock_data/notify_stock_qty'))
  207. && is_null($product->getData('stock_data/use_config_notify_stock_qty'))) {
  208. $item->setData('use_config_notify_stock_qty', false);
  209. }
  210. $originalQty = $product->getData('stock_data/original_inventory_qty');
  211. if (strlen($originalQty)>0) {
  212. $item->setQtyCorrection($item->getQty()-$originalQty);
  213. }
  214. if (!is_null($product->getData('stock_data/enable_qty_increments'))
  215. && is_null($product->getData('stock_data/use_config_enable_qty_increments'))) {
  216. $item->setData('use_config_enable_qty_increments', false);
  217. }
  218. if (!is_null($product->getData('stock_data/qty_increments'))
  219. && is_null($product->getData('stock_data/use_config_qty_increments'))) {
  220. $item->setData('use_config_qty_increments', false);
  221. }
  222. return $this;
  223. }
  224. /**
  225. * Check product inventory data when quote item quantity declaring
  226. *
  227. * @param Varien_Event_Observer $observer
  228. * @return Mage_CatalogInventory_Model_Observer
  229. */
  230. public function checkQuoteItemQty($observer)
  231. {
  232. $quoteItem = $observer->getEvent()->getItem();
  233. /* @var $quoteItem Mage_Sales_Model_Quote_Item */
  234. if (!$quoteItem || !$quoteItem->getProductId() || !$quoteItem->getQuote()
  235. || $quoteItem->getQuote()->getIsSuperMode()) {
  236. return $this;
  237. }
  238. /**
  239. * Get Qty
  240. */
  241. $qty = $quoteItem->getQty();
  242. /**
  243. * Check item for options
  244. */
  245. if (($options = $quoteItem->getQtyOptions()) && $qty > 0) {
  246. $qty = $quoteItem->getProduct()->getTypeInstance(true)->prepareQuoteItemQty($qty, $quoteItem->getProduct());
  247. $quoteItem->setData('qty', $qty);
  248. $stockItem = $quoteItem->getProduct()->getStockItem();
  249. if ($stockItem) {
  250. $result = $stockItem->checkQtyIncrements($qty);
  251. if ($result->getHasError()) {
  252. $quoteItem->setHasError(true)
  253. ->setMessage($result->getMessage());
  254. $quoteItem->getQuote()->setHasError(true)
  255. ->addMessage($result->getQuoteMessage(), $result->getQuoteMessageIndex());
  256. }
  257. }
  258. foreach ($options as $option) {
  259. /* @var $option Mage_Sales_Model_Quote_Item_Option */
  260. $optionQty = $qty * $option->getValue();
  261. $increaseOptionQty = ($quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty) * $option->getValue();
  262. $stockItem = $option->getProduct()->getStockItem();
  263. /* @var $stockItem Mage_CatalogInventory_Model_Stock_Item */
  264. if (!$stockItem instanceof Mage_CatalogInventory_Model_Stock_Item) {
  265. Mage::throwException(Mage::helper('cataloginventory')->__('The stock item for Product in option is not valid.'));
  266. }
  267. $stockItem->setOrderedItems(0);
  268. /**
  269. * define that stock item is child for composite product
  270. */
  271. $stockItem->setIsChildItem(true);
  272. /**
  273. * don't check qty increments value for option product
  274. */
  275. $stockItem->setSuppressCheckQtyIncrements(true);
  276. $qtyForCheck = $this->_getQuoteItemQtyForCheck(
  277. $option->getProduct()->getId(),
  278. $quoteItem->getId(),
  279. $increaseOptionQty
  280. );
  281. $result = $stockItem->checkQuoteItemQty($optionQty, $qtyForCheck, $option->getValue());
  282. if (!is_null($result->getItemIsQtyDecimal())) {
  283. $option->setIsQtyDecimal($result->getItemIsQtyDecimal());
  284. }
  285. if ($result->getHasQtyOptionUpdate()) {
  286. $option->setHasQtyOptionUpdate(true);
  287. $quoteItem->updateQtyOption($option, $result->getOrigQty());
  288. $option->setValue($result->getOrigQty());
  289. /**
  290. * if option's qty was updates we also need to update quote item qty
  291. */
  292. $quoteItem->setData('qty', intval($qty));
  293. }
  294. if (!is_null($result->getMessage())) {
  295. $option->setMessage($result->getMessage());
  296. }
  297. if (!is_null($result->getItemBackorders())) {
  298. $option->setBackorders($result->getItemBackorders());
  299. }
  300. if ($result->getHasError()) {
  301. $option->setHasError(true);
  302. $quoteItem->setHasError(true)
  303. ->setMessage($result->getQuoteMessage());
  304. $quoteItem->getQuote()->setHasError(true)
  305. ->addMessage($result->getQuoteMessage(), $result->getQuoteMessageIndex());
  306. }
  307. $stockItem->unsIsChildItem();
  308. }
  309. }
  310. else {
  311. $stockItem = $quoteItem->getProduct()->getStockItem();
  312. /* @var $stockItem Mage_CatalogInventory_Model_Stock_Item */
  313. if (!$stockItem instanceof Mage_CatalogInventory_Model_Stock_Item) {
  314. Mage::throwException(Mage::helper('cataloginventory')->__('The stock item for Product is not valid.'));
  315. }
  316. /**
  317. * When we work with subitem (as subproduct of bundle or configurable product)
  318. */
  319. if ($quoteItem->getParentItem()) {
  320. $rowQty = $quoteItem->getParentItem()->getQty() * $qty;
  321. /**
  322. * we are using 0 because original qty was processed
  323. */
  324. $qtyForCheck = $this->_getQuoteItemQtyForCheck(
  325. $quoteItem->getProduct()->getId(),
  326. $quoteItem->getId(),
  327. 0
  328. );
  329. }
  330. else {
  331. $increaseQty = $quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty;
  332. $rowQty = $qty;
  333. $qtyForCheck = $this->_getQuoteItemQtyForCheck(
  334. $quoteItem->getProduct()->getId(),
  335. $quoteItem->getId(),
  336. $increaseQty
  337. );
  338. }
  339. $productTypeCustomOption = $quoteItem->getProduct()->getCustomOption('product_type');
  340. if (!is_null($productTypeCustomOption)) {
  341. // Check if product related to current item is a part of grouped product
  342. if ($productTypeCustomOption->getValue() == Mage_Catalog_Model_Product_Type_Grouped::TYPE_CODE) {
  343. $stockItem->setIsChildItem(true);
  344. }
  345. }
  346. $result = $stockItem->checkQuoteItemQty($rowQty, $qtyForCheck, $qty);
  347. if ($stockItem->hasIsChildItem()) {
  348. $stockItem->unsIsChildItem();
  349. }
  350. if (!is_null($result->getItemIsQtyDecimal())) {
  351. $quoteItem->setIsQtyDecimal($result->getItemIsQtyDecimal());
  352. if ($quoteItem->getParentItem()) {
  353. $quoteItem->getParentItem()->setIsQtyDecimal($result->getItemIsQtyDecimal());
  354. }
  355. }
  356. /**
  357. * Just base (parent) item qty can be changed
  358. * qty of child products are declared just during add process
  359. * exception for updating also managed by product type
  360. */
  361. if ($result->getHasQtyOptionUpdate()
  362. && (!$quoteItem->getParentItem()
  363. || $quoteItem->getParentItem()->getProduct()->getTypeInstance(true)
  364. ->getForceChildItemQtyChanges($quoteItem->getParentItem()->getProduct()))
  365. ) {
  366. $quoteItem->setData('qty', $result->getOrigQty());
  367. }
  368. if (!is_null($result->getItemUseOldQty())) {
  369. $quoteItem->setUseOldQty($result->getItemUseOldQty());
  370. }
  371. if (!is_null($result->getMessage())) {
  372. $quoteItem->setMessage($result->getMessage());
  373. if ($quoteItem->getParentItem()) {
  374. $quoteItem->getParentItem()->setMessage($result->getMessage());
  375. }
  376. }
  377. if (!is_null($result->getItemBackorders())) {
  378. $quoteItem->setBackorders($result->getItemBackorders());
  379. }
  380. if ($result->getHasError()) {
  381. $quoteItem->setHasError(true);
  382. $quoteItem->getQuote()->setHasError(true)
  383. ->addMessage($result->getQuoteMessage(), $result->getQuoteMessageIndex());
  384. }
  385. }
  386. return $this;
  387. }
  388. /**
  389. * Get product qty includes information from all quote items
  390. * Need be used only in sungleton mode
  391. *
  392. * @deprecated after 1.4.2.0-rc1
  393. * @param int $productId
  394. * @param float $itemQty
  395. */
  396. protected function _getProductQtyForCheck($productId, $itemQty)
  397. {
  398. $qty = $itemQty;
  399. if (isset($this->_checkedProductsQty[$productId])) {
  400. $qty += $this->_checkedProductsQty[$productId];
  401. }
  402. $this->_checkedProductsQty[$productId] = $qty;
  403. return $qty;
  404. }
  405. /**
  406. * Get product qty includes information from all quote items
  407. * Need be used only in sungleton mode
  408. *
  409. * @param int $productId
  410. * @param int $quoteItemId
  411. * @param float $itemQty
  412. * @return int
  413. */
  414. protected function _getQuoteItemQtyForCheck($productId, $quoteItemId, $itemQty)
  415. {
  416. $qty = $itemQty;
  417. if (isset($this->_checkedQuoteItems[$productId]['qty']) &&
  418. !in_array($quoteItemId, $this->_checkedQuoteItems[$productId]['items'])) {
  419. $qty += $this->_checkedQuoteItems[$productId]['qty'];
  420. }
  421. $this->_checkedQuoteItems[$productId]['qty'] = $qty;
  422. $this->_checkedQuoteItems[$productId]['items'][] = $quoteItemId;
  423. return $qty;
  424. }
  425. /**
  426. * Subtract qtys of quote item products after multishipping checkout
  427. *
  428. * @param Varien_Event_Observer $observer
  429. * @return Mage_CatalogInventory_Model_Observer
  430. */
  431. public function checkoutAllSubmitAfter(Varien_Event_Observer $observer)
  432. {
  433. $quote = $observer->getEvent()->getQuote();
  434. if (!$quote->getInventoryProcessed()) {
  435. $this->subtractQuoteInventory($observer);
  436. $this->reindexQuoteInventory($observer);
  437. }
  438. return $this;
  439. }
  440. /**
  441. * Subtract quote items qtys from stock items related with quote items products.
  442. *
  443. * Used before order placing to make order save/place transaction smaller
  444. * Also called after every successful order placement to ensure subtraction of inventory
  445. *
  446. * @param Varien_Event_Observer $observer
  447. */
  448. public function subtractQuoteInventory(Varien_Event_Observer $observer)
  449. {
  450. $quote = $observer->getEvent()->getQuote();
  451. // Maybe we've already processed this quote in some event during order placement
  452. // e.g. call in event 'sales_model_service_quote_submit_before' and later in 'checkout_submit_all_after'
  453. if ($quote->getInventoryProcessed()) {
  454. return;
  455. }
  456. $items = $this->_getProductsQty($quote->getAllItems());
  457. /**
  458. * Remember items
  459. */
  460. $this->_itemsForReindex = Mage::getSingleton('cataloginventory/stock')->registerProductsSale($items);
  461. $quote->setInventoryProcessed(true);
  462. return $this;
  463. }
  464. /**
  465. * Revert quote items inventory data (cover not success order place case)
  466. * @param $observer
  467. */
  468. public function revertQuoteInventory($observer)
  469. {
  470. $quote = $observer->getEvent()->getQuote();
  471. $items = $this->_getProductsQty($quote->getAllItems());
  472. Mage::getSingleton('cataloginventory/stock')->revertProductsSale($items);
  473. // Clear flag, so if order placement retried again with success - it will be processed
  474. $quote->setInventoryProcessed(false);
  475. }
  476. /**
  477. * Adds stock item qty to $items (creates new entry or increments existing one)
  478. * $items is array with following structure:
  479. * array(
  480. * $productId => array(
  481. * 'qty' => $qty,
  482. * 'item' => $stockItems|null
  483. * )
  484. * )
  485. *
  486. * @param Mage_Sales_Model_Quote_Item $quoteItem
  487. * @param array &$items
  488. */
  489. protected function _addItemToQtyArray($quoteItem, &$items)
  490. {
  491. $productId = $quoteItem->getProductId();
  492. if (!$productId)
  493. return;
  494. if (isset($items[$productId])) {
  495. $items[$productId]['qty'] += $quoteItem->getTotalQty();
  496. } else {
  497. $stockItem = null;
  498. if ($quoteItem->getProduct()) {
  499. $stockItem = $quoteItem->getProduct()->getStockItem();
  500. }
  501. $items[$productId] = array(
  502. 'item' => $stockItem,
  503. 'qty' => $quoteItem->getTotalQty()
  504. );
  505. }
  506. }
  507. /**
  508. * Prepare array with information about used product qty and product stock item
  509. * result is:
  510. * array(
  511. * $productId => array(
  512. * 'qty' => $qty,
  513. * 'item' => $stockItems|null
  514. * )
  515. * )
  516. * @param array $relatedItems
  517. * @return array
  518. */
  519. protected function _getProductsQty($relatedItems)
  520. {
  521. $items = array();
  522. foreach ($relatedItems as $item) {
  523. $productId = $item->getProductId();
  524. if (!$productId) {
  525. continue;
  526. }
  527. $children = $item->getChildrenItems();
  528. if ($children) {
  529. foreach ($children as $childItem) {
  530. $this->_addItemToQtyArray($childItem, $items);
  531. }
  532. } else {
  533. $this->_addItemToQtyArray($item, $items);
  534. }
  535. }
  536. return $items;
  537. }
  538. /**
  539. * Refresh stock index for specific stock items after succesful order placement
  540. *
  541. * @param $observer
  542. */
  543. public function reindexQuoteInventory($observer)
  544. {
  545. // Reindex quote ids
  546. $quote = $observer->getEvent()->getQuote();
  547. $productIds = array();
  548. foreach ($quote->getAllItems() as $item) {
  549. $productIds[$item->getProductId()] = $item->getProductId();
  550. $children = $item->getChildrenItems();
  551. if ($children) {
  552. foreach ($children as $childItem) {
  553. $productIds[$childItem->getProductId()] = $childItem->getProductId();
  554. }
  555. }
  556. }
  557. Mage::getResourceSingleton('cataloginventory/indexer_stock')->reindexProducts($productIds);
  558. // Reindex previously remembered items
  559. $productIds = array();
  560. foreach ($this->_itemsForReindex as $item) {
  561. $item->save();
  562. $productIds[] = $item->getProductId();
  563. }
  564. Mage::getResourceSingleton('catalog/product_indexer_price')->reindexProductIds($productIds);
  565. $this->_itemsForReindex = array(); // Clear list of remembered items - we don't need it anymore
  566. return $this;
  567. }
  568. /**
  569. * Return creditmemo items qty to stock
  570. *
  571. * @param Varien_Event_Observer $observer
  572. */
  573. public function refundOrderInventory($observer)
  574. {
  575. $creditmemo = $observer->getEvent()->getCreditmemo();
  576. $items = array();
  577. foreach ($creditmemo->getAllItems() as $item) {
  578. $return = false;
  579. if ($item->hasBackToStock()) {
  580. if ($item->getBackToStock() && $item->getQty()) {
  581. $return = true;
  582. }
  583. } elseif (Mage::helper('cataloginventory')->isAutoReturnEnabled()) {
  584. $return = true;
  585. }
  586. if ($return) {
  587. if (isset($items[$item->getProductId()])) {
  588. $items[$item->getProductId()]['qty'] += $item->getQty();
  589. } else {
  590. $items[$item->getProductId()] = array(
  591. 'qty' => $item->getQty(),
  592. 'item'=> null,
  593. );
  594. }
  595. }
  596. }
  597. Mage::getSingleton('cataloginventory/stock')->revertProductsSale($items);
  598. }
  599. /**
  600. * Cancel order item
  601. *
  602. * @param Varien_Event_Observer $observer
  603. * @return Mage_CatalogInventory_Model_Observer
  604. */
  605. public function cancelOrderItem($observer)
  606. {
  607. $item = $observer->getEvent()->getItem();
  608. $children = $item->getChildrenItems();
  609. $qty = $item->getQtyOrdered() - max($item->getQtyShipped(), $item->getQtyInvoiced()) - $item->getQtyCanceled();
  610. if ($item->getId() && ($productId = $item->getProductId()) && empty($children) && $qty) {
  611. Mage::getSingleton('cataloginventory/stock')->backItemQty($productId, $qty);
  612. }
  613. return $this;
  614. }
  615. /**
  616. * Update items stock status and low stock date.
  617. *
  618. * @param Varien_Event_Observer $observer
  619. * @return Mage_CatalogInventory_Model_Observer
  620. */
  621. public function updateItemsStockUponConfigChange($observer)
  622. {
  623. Mage::getResourceSingleton('cataloginventory/stock')->updateSetOutOfStock();
  624. Mage::getResourceSingleton('cataloginventory/stock')->updateSetInStock();
  625. Mage::getResourceSingleton('cataloginventory/stock')->updateLowStockDate();
  626. return $this;
  627. }
  628. /**
  629. * Update Only product status observer
  630. *
  631. * @param Varien_Event_Observer $observer
  632. * @return Mage_CatalogInventory_Model_Observer
  633. */
  634. public function productStatusUpdate(Varien_Event_Observer $observer)
  635. {
  636. $productId = $observer->getEvent()->getProductId();
  637. Mage::getSingleton('cataloginventory/stock_status')
  638. ->updateStatus($productId);
  639. return $this;
  640. }
  641. /**
  642. * Catalog Product website update
  643. *
  644. * @param Varien_Event_Observer $observer
  645. * @return Mage_CatalogInventory_Model_Observer
  646. */
  647. public function catalogProductWebsiteUpdate(Varien_Event_Observer $observer)
  648. {
  649. $websiteIds = $observer->getEvent()->getWebsiteIds();
  650. $productIds = $observer->getEvent()->getProductIds();
  651. foreach ($websiteIds as $websiteId) {
  652. foreach ($productIds as $productId) {
  653. Mage::getSingleton('cataloginventory/stock_status')
  654. ->updateStatus($productId, null, $websiteId);
  655. }
  656. }
  657. return $this;
  658. }
  659. /**
  660. * Add stock status to prepare index select
  661. *
  662. * @param Varien_Event_Observer $observer
  663. * @return Mage_CatalogInventory_Model_Observer
  664. */
  665. public function addStockStatusToPrepareIndexSelect(Varien_Event_Observer $observer)
  666. {
  667. $website = $observer->getEvent()->getWebsite();
  668. $select = $observer->getEvent()->getSelect();
  669. Mage::getSingleton('cataloginventory/stock_status')
  670. ->addStockStatusToSelect($select, $website);
  671. return $this;
  672. }
  673. /**
  674. * Add stock status limitation to catalog product price index select object
  675. *
  676. * @param Varien_Event_Observer $observer
  677. * @return Mage_CatalogInventory_Model_Observer
  678. */
  679. public function prepareCatalogProductIndexSelect(Varien_Event_Observer $observer)
  680. {
  681. $select = $observer->getEvent()->getSelect();
  682. $entity = $observer->getEvent()->getEntityField();
  683. $website = $observer->getEvent()->getWebsiteField();
  684. Mage::getSingleton('cataloginventory/stock_status')
  685. ->prepareCatalogProductIndexSelect($select, $entity, $website);
  686. return $this;
  687. }
  688. /**
  689. * Lock DB rows for order products
  690. *
  691. * We need do it for resolving problems with inventory on placing
  692. * some orders in one time
  693. * @deprecated after 1.4
  694. * @param Varien_Event_Observer $observer
  695. * @return Mage_CatalogInventory_Model_Observer
  696. */
  697. public function lockOrderInventoryData($observer)
  698. {
  699. $order = $observer->getEvent()->getOrder();
  700. $productIds = array();
  701. /**
  702. * Do lock only for new order
  703. */
  704. if ($order->getId()) {
  705. return $this;
  706. }
  707. if ($order) {
  708. foreach ($order->getAllItems() as $item) {
  709. $productIds[] = $item->getProductId();
  710. }
  711. }
  712. if (!empty($productIds)) {
  713. Mage::getSingleton('cataloginventory/stock')->lockProductItems($productIds);
  714. }
  715. return $this;
  716. }
  717. /**
  718. * Register saving order item
  719. *
  720. * @deprecated after 1.4
  721. * @param Varien_Event_Observer $observer
  722. * @return Mage_CatalogInventory_Model_Observer
  723. */
  724. public function createOrderItem($observer)
  725. {
  726. $item = $observer->getEvent()->getItem();
  727. /**
  728. * Before creating order item need subtract ordered qty from product stock
  729. */
  730. $children = $item->getChildrenItems();
  731. if (!$item->getId() && empty($children)) {
  732. Mage::getSingleton('cataloginventory/stock')->registerItemSale($item);
  733. }
  734. return $this;
  735. }
  736. /**
  737. * Back refunded item qty to stock
  738. *
  739. * @deprecated after 1.4
  740. * @param Varien_Event_Observer $observer
  741. * @return Mage_CatalogInventory_Model_Observer
  742. */
  743. public function refundOrderItem($observer)
  744. {
  745. $item = $observer->getEvent()->getCreditmemoItem();
  746. if ($item->getId() && $item->getBackToStock() && ($productId = $item->getProductId())
  747. && ($qty = $item->getQty())
  748. ) {
  749. Mage::getSingleton('cataloginventory/stock')->backItemQty($productId, $qty);
  750. }
  751. return $this;
  752. }
  753. }