PageRenderTime 110ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/broekn/wordpresstest
PHP | 907 lines | 530 code | 91 blank | 286 comment | 96 complexity | 0cfdb6513add93f40d9ed471cf82975b 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) 2011 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_inc' => $currentStockItem->getData('use_config_enable_qty_inc'),
  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_inc'))) {
  216. $item->setData('use_config_enable_qty_inc', 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. * Removes error statuses from quote and item, set by this observer
  226. *
  227. * @param Mage_Sales_Model_Quote_Item $item
  228. * @param int $code
  229. * @return Mage_CatalogInventory_Model_Observer
  230. */
  231. protected function _removeErrorsFromQuoteAndItem($item, $code)
  232. {
  233. if ($item->getHasError()) {
  234. $params = array(
  235. 'origin' => 'cataloginventory',
  236. 'code' => $code
  237. );
  238. $item->removeErrorInfosByParams($params);
  239. }
  240. $quote = $item->getQuote();
  241. if ($quote->getHasError()) {
  242. $params = array(
  243. 'origin' => 'cataloginventory',
  244. 'code' => $code
  245. );
  246. $quote->removeErrorInfosByParams(null, $params);
  247. }
  248. return $this;
  249. }
  250. /**
  251. * Check product inventory data when quote item quantity declaring
  252. *
  253. * @param Varien_Event_Observer $observer
  254. * @return Mage_CatalogInventory_Model_Observer
  255. */
  256. public function checkQuoteItemQty($observer)
  257. {
  258. $quoteItem = $observer->getEvent()->getItem();
  259. /* @var $quoteItem Mage_Sales_Model_Quote_Item */
  260. if (!$quoteItem || !$quoteItem->getProductId() || !$quoteItem->getQuote()
  261. || $quoteItem->getQuote()->getIsSuperMode()) {
  262. return $this;
  263. }
  264. /**
  265. * Get Qty
  266. */
  267. $qty = $quoteItem->getQty();
  268. /**
  269. * Check item for options
  270. */
  271. if (($options = $quoteItem->getQtyOptions()) && $qty > 0) {
  272. $qty = $quoteItem->getProduct()->getTypeInstance(true)->prepareQuoteItemQty($qty, $quoteItem->getProduct());
  273. $quoteItem->setData('qty', $qty);
  274. $stockItem = $quoteItem->getProduct()->getStockItem();
  275. if ($stockItem) {
  276. $result = $stockItem->checkQtyIncrements($qty);
  277. if ($result->getHasError()) {
  278. $quoteItem->addErrorInfo(
  279. 'cataloginventory',
  280. Mage_CatalogInventory_Helper_Data::ERROR_QTY_INCREMENTS,
  281. $result->getMessage()
  282. );
  283. $quoteItem->getQuote()->addErrorInfo(
  284. $result->getQuoteMessageIndex(),
  285. 'cataloginventory',
  286. Mage_CatalogInventory_Helper_Data::ERROR_QTY_INCREMENTS,
  287. $result->getQuoteMessage()
  288. );
  289. } else {
  290. // Delete error from item and its quote, if it was set due to qty problems
  291. $this->_removeErrorsFromQuoteAndItem(
  292. $quoteItem,
  293. Mage_CatalogInventory_Helper_Data::ERROR_QTY_INCREMENTS
  294. );
  295. }
  296. }
  297. foreach ($options as $option) {
  298. $optionValue = $option->getValue();
  299. /* @var $option Mage_Sales_Model_Quote_Item_Option */
  300. $optionQty = $qty * $optionValue;
  301. $increaseOptionQty = ($quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty) * $optionValue;
  302. $stockItem = $option->getProduct()->getStockItem();
  303. /* @var $stockItem Mage_CatalogInventory_Model_Stock_Item */
  304. if (!$stockItem instanceof Mage_CatalogInventory_Model_Stock_Item) {
  305. Mage::throwException(
  306. Mage::helper('cataloginventory')->__('The stock item for Product in option is not valid.')
  307. );
  308. }
  309. /**
  310. * define that stock item is child for composite product
  311. */
  312. $stockItem->setIsChildItem(true);
  313. /**
  314. * don't check qty increments value for option product
  315. */
  316. $stockItem->setSuppressCheckQtyIncrements(true);
  317. $qtyForCheck = $this->_getQuoteItemQtyForCheck(
  318. $option->getProduct()->getId(),
  319. $quoteItem->getId(),
  320. $increaseOptionQty
  321. );
  322. $result = $stockItem->checkQuoteItemQty($optionQty, $qtyForCheck, $optionValue);
  323. if (!is_null($result->getItemIsQtyDecimal())) {
  324. $option->setIsQtyDecimal($result->getItemIsQtyDecimal());
  325. }
  326. if ($result->getHasQtyOptionUpdate()) {
  327. $option->setHasQtyOptionUpdate(true);
  328. $quoteItem->updateQtyOption($option, $result->getOrigQty());
  329. $option->setValue($result->getOrigQty());
  330. /**
  331. * if option's qty was updates we also need to update quote item qty
  332. */
  333. $quoteItem->setData('qty', intval($qty));
  334. }
  335. if (!is_null($result->getMessage())) {
  336. $option->setMessage($result->getMessage());
  337. }
  338. if (!is_null($result->getItemBackorders())) {
  339. $option->setBackorders($result->getItemBackorders());
  340. }
  341. if ($result->getHasError()) {
  342. $option->setHasError(true);
  343. $quoteItem->addErrorInfo(
  344. 'cataloginventory',
  345. Mage_CatalogInventory_Helper_Data::ERROR_QTY,
  346. $result->getQuoteMessage()
  347. );
  348. $quoteItem->getQuote()->addErrorInfo(
  349. $result->getQuoteMessageIndex(),
  350. 'cataloginventory',
  351. Mage_CatalogInventory_Helper_Data::ERROR_QTY,
  352. $result->getQuoteMessage()
  353. );
  354. } else {
  355. // Delete error from item and its quote, if it was set due to qty lack
  356. $this->_removeErrorsFromQuoteAndItem($quoteItem, Mage_CatalogInventory_Helper_Data::ERROR_QTY);
  357. }
  358. $stockItem->unsIsChildItem();
  359. }
  360. } else {
  361. $stockItem = $quoteItem->getProduct()->getStockItem();
  362. /* @var $stockItem Mage_CatalogInventory_Model_Stock_Item */
  363. if (!$stockItem instanceof Mage_CatalogInventory_Model_Stock_Item) {
  364. Mage::throwException(Mage::helper('cataloginventory')->__('The stock item for Product is not valid.'));
  365. }
  366. /**
  367. * When we work with subitem (as subproduct of bundle or configurable product)
  368. */
  369. if ($quoteItem->getParentItem()) {
  370. $rowQty = $quoteItem->getParentItem()->getQty() * $qty;
  371. /**
  372. * we are using 0 because original qty was processed
  373. */
  374. $qtyForCheck = $this->_getQuoteItemQtyForCheck(
  375. $quoteItem->getProduct()->getId(),
  376. $quoteItem->getId(),
  377. 0
  378. );
  379. } else {
  380. $increaseQty = $quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty;
  381. $rowQty = $qty;
  382. $qtyForCheck = $this->_getQuoteItemQtyForCheck(
  383. $quoteItem->getProduct()->getId(),
  384. $quoteItem->getId(),
  385. $increaseQty
  386. );
  387. }
  388. $productTypeCustomOption = $quoteItem->getProduct()->getCustomOption('product_type');
  389. if (!is_null($productTypeCustomOption)) {
  390. // Check if product related to current item is a part of grouped product
  391. if ($productTypeCustomOption->getValue() == Mage_Catalog_Model_Product_Type_Grouped::TYPE_CODE) {
  392. $stockItem->setIsChildItem(true);
  393. }
  394. }
  395. $result = $stockItem->checkQuoteItemQty($rowQty, $qtyForCheck, $qty);
  396. if ($stockItem->hasIsChildItem()) {
  397. $stockItem->unsIsChildItem();
  398. }
  399. if (!is_null($result->getItemIsQtyDecimal())) {
  400. $quoteItem->setIsQtyDecimal($result->getItemIsQtyDecimal());
  401. if ($quoteItem->getParentItem()) {
  402. $quoteItem->getParentItem()->setIsQtyDecimal($result->getItemIsQtyDecimal());
  403. }
  404. }
  405. /**
  406. * Just base (parent) item qty can be changed
  407. * qty of child products are declared just during add process
  408. * exception for updating also managed by product type
  409. */
  410. if ($result->getHasQtyOptionUpdate()
  411. && (!$quoteItem->getParentItem()
  412. || $quoteItem->getParentItem()->getProduct()->getTypeInstance(true)
  413. ->getForceChildItemQtyChanges($quoteItem->getParentItem()->getProduct())
  414. )
  415. ) {
  416. $quoteItem->setData('qty', $result->getOrigQty());
  417. }
  418. if (!is_null($result->getItemUseOldQty())) {
  419. $quoteItem->setUseOldQty($result->getItemUseOldQty());
  420. }
  421. if (!is_null($result->getMessage())) {
  422. $quoteItem->setMessage($result->getMessage());
  423. if ($quoteItem->getParentItem()) {
  424. $quoteItem->getParentItem()->setMessage($result->getMessage());
  425. }
  426. }
  427. if (!is_null($result->getItemBackorders())) {
  428. $quoteItem->setBackorders($result->getItemBackorders());
  429. }
  430. if ($result->getHasError()) {
  431. $quoteItem->addErrorInfo(
  432. 'cataloginventory',
  433. Mage_CatalogInventory_Helper_Data::ERROR_QTY,
  434. $result->getMessage()
  435. );
  436. $quoteItem->getQuote()->addErrorInfo(
  437. $result->getQuoteMessageIndex(),
  438. 'cataloginventory',
  439. Mage_CatalogInventory_Helper_Data::ERROR_QTY,
  440. $result->getQuoteMessage()
  441. );
  442. } else {
  443. // Delete error from item and its quote, if it was set due to qty lack
  444. $this->_removeErrorsFromQuoteAndItem($quoteItem, Mage_CatalogInventory_Helper_Data::ERROR_QTY);
  445. }
  446. }
  447. return $this;
  448. }
  449. /**
  450. * Get product qty includes information from all quote items
  451. * Need be used only in sungleton mode
  452. *
  453. * @deprecated after 1.4.2.0-rc1
  454. * @param int $productId
  455. * @param float $itemQty
  456. */
  457. protected function _getProductQtyForCheck($productId, $itemQty)
  458. {
  459. $qty = $itemQty;
  460. if (isset($this->_checkedProductsQty[$productId])) {
  461. $qty += $this->_checkedProductsQty[$productId];
  462. }
  463. $this->_checkedProductsQty[$productId] = $qty;
  464. return $qty;
  465. }
  466. /**
  467. * Get product qty includes information from all quote items
  468. * Need be used only in sungleton mode
  469. *
  470. * @param int $productId
  471. * @param int $quoteItemId
  472. * @param float $itemQty
  473. * @return int
  474. */
  475. protected function _getQuoteItemQtyForCheck($productId, $quoteItemId, $itemQty)
  476. {
  477. $qty = $itemQty;
  478. if (isset($this->_checkedQuoteItems[$productId]['qty']) &&
  479. !in_array($quoteItemId, $this->_checkedQuoteItems[$productId]['items'])) {
  480. $qty += $this->_checkedQuoteItems[$productId]['qty'];
  481. }
  482. $this->_checkedQuoteItems[$productId]['qty'] = $qty;
  483. $this->_checkedQuoteItems[$productId]['items'][] = $quoteItemId;
  484. return $qty;
  485. }
  486. /**
  487. * Subtract qtys of quote item products after multishipping checkout
  488. *
  489. * @param Varien_Event_Observer $observer
  490. * @return Mage_CatalogInventory_Model_Observer
  491. */
  492. public function checkoutAllSubmitAfter(Varien_Event_Observer $observer)
  493. {
  494. $quote = $observer->getEvent()->getQuote();
  495. if (!$quote->getInventoryProcessed()) {
  496. $this->subtractQuoteInventory($observer);
  497. $this->reindexQuoteInventory($observer);
  498. }
  499. return $this;
  500. }
  501. /**
  502. * Subtract quote items qtys from stock items related with quote items products.
  503. *
  504. * Used before order placing to make order save/place transaction smaller
  505. * Also called after every successful order placement to ensure subtraction of inventory
  506. *
  507. * @param Varien_Event_Observer $observer
  508. */
  509. public function subtractQuoteInventory(Varien_Event_Observer $observer)
  510. {
  511. $quote = $observer->getEvent()->getQuote();
  512. // Maybe we've already processed this quote in some event during order placement
  513. // e.g. call in event 'sales_model_service_quote_submit_before' and later in 'checkout_submit_all_after'
  514. if ($quote->getInventoryProcessed()) {
  515. return;
  516. }
  517. $items = $this->_getProductsQty($quote->getAllItems());
  518. /**
  519. * Remember items
  520. */
  521. $this->_itemsForReindex = Mage::getSingleton('cataloginventory/stock')->registerProductsSale($items);
  522. $quote->setInventoryProcessed(true);
  523. return $this;
  524. }
  525. /**
  526. * Revert quote items inventory data (cover not success order place case)
  527. * @param $observer
  528. */
  529. public function revertQuoteInventory($observer)
  530. {
  531. $quote = $observer->getEvent()->getQuote();
  532. $items = $this->_getProductsQty($quote->getAllItems());
  533. Mage::getSingleton('cataloginventory/stock')->revertProductsSale($items);
  534. // Clear flag, so if order placement retried again with success - it will be processed
  535. $quote->setInventoryProcessed(false);
  536. }
  537. /**
  538. * Adds stock item qty to $items (creates new entry or increments existing one)
  539. * $items is array with following structure:
  540. * array(
  541. * $productId => array(
  542. * 'qty' => $qty,
  543. * 'item' => $stockItems|null
  544. * )
  545. * )
  546. *
  547. * @param Mage_Sales_Model_Quote_Item $quoteItem
  548. * @param array &$items
  549. */
  550. protected function _addItemToQtyArray($quoteItem, &$items)
  551. {
  552. $productId = $quoteItem->getProductId();
  553. if (!$productId)
  554. return;
  555. if (isset($items[$productId])) {
  556. $items[$productId]['qty'] += $quoteItem->getTotalQty();
  557. } else {
  558. $stockItem = null;
  559. if ($quoteItem->getProduct()) {
  560. $stockItem = $quoteItem->getProduct()->getStockItem();
  561. }
  562. $items[$productId] = array(
  563. 'item' => $stockItem,
  564. 'qty' => $quoteItem->getTotalQty()
  565. );
  566. }
  567. }
  568. /**
  569. * Prepare array with information about used product qty and product stock item
  570. * result is:
  571. * array(
  572. * $productId => array(
  573. * 'qty' => $qty,
  574. * 'item' => $stockItems|null
  575. * )
  576. * )
  577. * @param array $relatedItems
  578. * @return array
  579. */
  580. protected function _getProductsQty($relatedItems)
  581. {
  582. $items = array();
  583. foreach ($relatedItems as $item) {
  584. $productId = $item->getProductId();
  585. if (!$productId) {
  586. continue;
  587. }
  588. $children = $item->getChildrenItems();
  589. if ($children) {
  590. foreach ($children as $childItem) {
  591. $this->_addItemToQtyArray($childItem, $items);
  592. }
  593. } else {
  594. $this->_addItemToQtyArray($item, $items);
  595. }
  596. }
  597. return $items;
  598. }
  599. /**
  600. * Refresh stock index for specific stock items after succesful order placement
  601. *
  602. * @param $observer
  603. */
  604. public function reindexQuoteInventory($observer)
  605. {
  606. // Reindex quote ids
  607. $quote = $observer->getEvent()->getQuote();
  608. $productIds = array();
  609. foreach ($quote->getAllItems() as $item) {
  610. $productIds[$item->getProductId()] = $item->getProductId();
  611. $children = $item->getChildrenItems();
  612. if ($children) {
  613. foreach ($children as $childItem) {
  614. $productIds[$childItem->getProductId()] = $childItem->getProductId();
  615. }
  616. }
  617. }
  618. if( count($productIds)) {
  619. Mage::getResourceSingleton('cataloginventory/indexer_stock')->reindexProducts($productIds);
  620. }
  621. // Reindex previously remembered items
  622. $productIds = array();
  623. foreach ($this->_itemsForReindex as $item) {
  624. $item->save();
  625. $productIds[] = $item->getProductId();
  626. }
  627. Mage::getResourceSingleton('catalog/product_indexer_price')->reindexProductIds($productIds);
  628. $this->_itemsForReindex = array(); // Clear list of remembered items - we don't need it anymore
  629. return $this;
  630. }
  631. /**
  632. * Return creditmemo items qty to stock
  633. *
  634. * @param Varien_Event_Observer $observer
  635. */
  636. public function refundOrderInventory($observer)
  637. {
  638. $creditmemo = $observer->getEvent()->getCreditmemo();
  639. $items = array();
  640. foreach ($creditmemo->getAllItems() as $item) {
  641. $return = false;
  642. if ($item->hasBackToStock()) {
  643. if ($item->getBackToStock() && $item->getQty()) {
  644. $return = true;
  645. }
  646. } elseif (Mage::helper('cataloginventory')->isAutoReturnEnabled()) {
  647. $return = true;
  648. }
  649. if ($return) {
  650. if (isset($items[$item->getProductId()])) {
  651. $items[$item->getProductId()]['qty'] += $item->getQty();
  652. } else {
  653. $items[$item->getProductId()] = array(
  654. 'qty' => $item->getQty(),
  655. 'item'=> null,
  656. );
  657. }
  658. }
  659. }
  660. Mage::getSingleton('cataloginventory/stock')->revertProductsSale($items);
  661. }
  662. /**
  663. * Cancel order item
  664. *
  665. * @param Varien_Event_Observer $observer
  666. * @return Mage_CatalogInventory_Model_Observer
  667. */
  668. public function cancelOrderItem($observer)
  669. {
  670. $item = $observer->getEvent()->getItem();
  671. $children = $item->getChildrenItems();
  672. $qty = $item->getQtyOrdered() - max($item->getQtyShipped(), $item->getQtyInvoiced()) - $item->getQtyCanceled();
  673. if ($item->getId() && ($productId = $item->getProductId()) && empty($children) && $qty) {
  674. Mage::getSingleton('cataloginventory/stock')->backItemQty($productId, $qty);
  675. }
  676. return $this;
  677. }
  678. /**
  679. * Update items stock status and low stock date.
  680. *
  681. * @param Varien_Event_Observer $observer
  682. * @return Mage_CatalogInventory_Model_Observer
  683. */
  684. public function updateItemsStockUponConfigChange($observer)
  685. {
  686. Mage::getResourceSingleton('cataloginventory/stock')->updateSetOutOfStock();
  687. Mage::getResourceSingleton('cataloginventory/stock')->updateSetInStock();
  688. Mage::getResourceSingleton('cataloginventory/stock')->updateLowStockDate();
  689. return $this;
  690. }
  691. /**
  692. * Update Only product status observer
  693. *
  694. * @param Varien_Event_Observer $observer
  695. * @return Mage_CatalogInventory_Model_Observer
  696. */
  697. public function productStatusUpdate(Varien_Event_Observer $observer)
  698. {
  699. $productId = $observer->getEvent()->getProductId();
  700. Mage::getSingleton('cataloginventory/stock_status')
  701. ->updateStatus($productId);
  702. return $this;
  703. }
  704. /**
  705. * Catalog Product website update
  706. *
  707. * @param Varien_Event_Observer $observer
  708. * @return Mage_CatalogInventory_Model_Observer
  709. */
  710. public function catalogProductWebsiteUpdate(Varien_Event_Observer $observer)
  711. {
  712. $websiteIds = $observer->getEvent()->getWebsiteIds();
  713. $productIds = $observer->getEvent()->getProductIds();
  714. foreach ($websiteIds as $websiteId) {
  715. foreach ($productIds as $productId) {
  716. Mage::getSingleton('cataloginventory/stock_status')
  717. ->updateStatus($productId, null, $websiteId);
  718. }
  719. }
  720. return $this;
  721. }
  722. /**
  723. * Add stock status to prepare index select
  724. *
  725. * @param Varien_Event_Observer $observer
  726. * @return Mage_CatalogInventory_Model_Observer
  727. */
  728. public function addStockStatusToPrepareIndexSelect(Varien_Event_Observer $observer)
  729. {
  730. $website = $observer->getEvent()->getWebsite();
  731. $select = $observer->getEvent()->getSelect();
  732. Mage::getSingleton('cataloginventory/stock_status')
  733. ->addStockStatusToSelect($select, $website);
  734. return $this;
  735. }
  736. /**
  737. * Add stock status limitation to catalog product price index select object
  738. *
  739. * @param Varien_Event_Observer $observer
  740. * @return Mage_CatalogInventory_Model_Observer
  741. */
  742. public function prepareCatalogProductIndexSelect(Varien_Event_Observer $observer)
  743. {
  744. $select = $observer->getEvent()->getSelect();
  745. $entity = $observer->getEvent()->getEntityField();
  746. $website = $observer->getEvent()->getWebsiteField();
  747. Mage::getSingleton('cataloginventory/stock_status')
  748. ->prepareCatalogProductIndexSelect($select, $entity, $website);
  749. return $this;
  750. }
  751. /**
  752. * Lock DB rows for order products
  753. *
  754. * We need do it for resolving problems with inventory on placing
  755. * some orders in one time
  756. * @deprecated after 1.4
  757. * @param Varien_Event_Observer $observer
  758. * @return Mage_CatalogInventory_Model_Observer
  759. */
  760. public function lockOrderInventoryData($observer)
  761. {
  762. $order = $observer->getEvent()->getOrder();
  763. $productIds = array();
  764. /**
  765. * Do lock only for new order
  766. */
  767. if ($order->getId()) {
  768. return $this;
  769. }
  770. if ($order) {
  771. foreach ($order->getAllItems() as $item) {
  772. $productIds[] = $item->getProductId();
  773. }
  774. }
  775. if (!empty($productIds)) {
  776. Mage::getSingleton('cataloginventory/stock')->lockProductItems($productIds);
  777. }
  778. return $this;
  779. }
  780. /**
  781. * Register saving order item
  782. *
  783. * @deprecated after 1.4
  784. * @param Varien_Event_Observer $observer
  785. * @return Mage_CatalogInventory_Model_Observer
  786. */
  787. public function createOrderItem($observer)
  788. {
  789. $item = $observer->getEvent()->getItem();
  790. /**
  791. * Before creating order item need subtract ordered qty from product stock
  792. */
  793. $children = $item->getChildrenItems();
  794. if (!$item->getId() && empty($children)) {
  795. Mage::getSingleton('cataloginventory/stock')->registerItemSale($item);
  796. }
  797. return $this;
  798. }
  799. /**
  800. * Back refunded item qty to stock
  801. *
  802. * @deprecated after 1.4
  803. * @param Varien_Event_Observer $observer
  804. * @return Mage_CatalogInventory_Model_Observer
  805. */
  806. public function refundOrderItem($observer)
  807. {
  808. $item = $observer->getEvent()->getCreditmemoItem();
  809. if ($item->getId() && $item->getBackToStock() && ($productId = $item->getProductId())
  810. && ($qty = $item->getQty())
  811. ) {
  812. Mage::getSingleton('cataloginventory/stock')->backItemQty($productId, $qty);
  813. }
  814. return $this;
  815. }
  816. }