Overview

Packages

  • currencysymbol
  • MAbout
  • Mage
    • Admin
    • Adminhtml
    • AdminNotification
    • Api
    • Api2
    • Authorizenet
    • Backup
    • Bundle
    • Captcha
    • Catalog
    • CatalogIndex
    • CatalogInventory
    • CatalogRule
    • CatalogSearch
    • Centinel
    • Checkout
    • Cms
    • Compiler
    • Connect
    • Contacts
    • Core
    • Cron
    • CurrencySymbol
    • Customer
    • Dataflow
    • Directory
    • DirtectPost
    • Downloadable
    • Eav
    • GiftMessage
    • GoogleAnalytics
    • GoogleBase
    • GoogleCheckout
    • ImportExport
    • Index
    • Install
    • Log
    • Media
    • Newsletter
    • Oauth
    • Page
    • PageCache
    • Paygate
    • Payment
    • Paypal
    • PaypalUk
    • Persistent
    • Poll
    • ProductAlert
    • Rating
    • Reports
    • Review
    • Rss
    • Rule
    • Sales
    • SalesRule
    • Sedfriend
    • Sendfriend
    • Shipping
    • Sitemap
    • Tag
    • Tax
    • Usa
    • Weee
    • Widget
    • Wishlist
    • XmlConnect
  • None
  • Phoenix
    • Moneybookers
  • PHP
  • Zend
    • Date
    • Mime
    • XmlRpc

Classes

  • Mage_CatalogInventory_Block_Adminhtml_Form_Field_Customergroup
  • Mage_CatalogInventory_Block_Adminhtml_Form_Field_Minsaleqty
  • Mage_CatalogInventory_Block_Qtyincrements
  • Mage_CatalogInventory_Block_Stockqty_Abstract
  • Mage_CatalogInventory_Block_Stockqty_Composite
  • Mage_CatalogInventory_Block_Stockqty_Default
  • Mage_CatalogInventory_Block_Stockqty_Type_Configurable
  • Mage_CatalogInventory_Block_Stockqty_Type_Grouped
  • Mage_CatalogInventory_Helper_Data
  • Mage_CatalogInventory_Helper_Minsaleqty
  • Mage_CatalogInventory_Model_Api2_Stock_Item
  • Mage_CatalogInventory_Model_Api2_Stock_Item_Rest
  • Mage_CatalogInventory_Model_Api2_Stock_Item_Rest_Admin_V1
  • Mage_CatalogInventory_Model_Api2_Stock_Item_Validator_Item
  • Mage_CatalogInventory_Model_Indexer_Stock
  • Mage_CatalogInventory_Model_Mysql4_Indexer_Stock
  • Mage_CatalogInventory_Model_Mysql4_Indexer_Stock_Configurable
  • Mage_CatalogInventory_Model_Mysql4_Indexer_Stock_Default
  • Mage_CatalogInventory_Model_Mysql4_Indexer_Stock_Grouped
  • Mage_CatalogInventory_Model_Mysql4_Stock
  • Mage_CatalogInventory_Model_Mysql4_Stock_Item
  • Mage_CatalogInventory_Model_Mysql4_Stock_Item_Collection
  • Mage_CatalogInventory_Model_Mysql4_Stock_Status
  • Mage_CatalogInventory_Model_Observer
  • Mage_CatalogInventory_Model_Resource_Indexer_Stock
  • Mage_CatalogInventory_Model_Resource_Indexer_Stock_Configurable
  • Mage_CatalogInventory_Model_Resource_Indexer_Stock_Default
  • Mage_CatalogInventory_Model_Resource_Indexer_Stock_Grouped
  • Mage_CatalogInventory_Model_Resource_Stock
  • Mage_CatalogInventory_Model_Resource_Stock_Item
  • Mage_CatalogInventory_Model_Resource_Stock_Item_Collection
  • Mage_CatalogInventory_Model_Resource_Stock_Status
  • Mage_CatalogInventory_Model_Source_Backorders
  • Mage_CatalogInventory_Model_Source_Stock
  • Mage_CatalogInventory_Model_Stock
  • Mage_CatalogInventory_Model_Stock_Item
  • Mage_CatalogInventory_Model_Stock_Item_Api
  • Mage_CatalogInventory_Model_Stock_Item_Api_V2
  • Mage_CatalogInventory_Model_Stock_Status
  • Mage_CatalogInventory_Model_System_Config_Backend_Minqty
  • Mage_CatalogInventory_Model_System_Config_Backend_Minsaleqty
  • Mage_CatalogInventory_Model_System_Config_Backend_Qtyincrements

Interfaces

  • Mage_CatalogInventory_Model_Mysql4_Indexer_Stock_Interface
  • Mage_CatalogInventory_Model_Resource_Indexer_Stock_Interface
  • Overview
  • Package
  • Class
  • Tree
  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) 2012 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: /**
 28:  * Catalog inventory module observer
 29:  *
 30:  * @category   Mage
 31:  * @package    Mage_CatalogInventory
 32:  * @author      Magento Core Team <core@magentocommerce.com>
 33:  */
 34: class Mage_CatalogInventory_Model_Observer
 35: {
 36:     /**
 37:      * Product qty's checked
 38:      * data is valid if you check quote item qty and use singleton instance
 39:      *
 40:      * @deprecated after 1.4.2.0-rc1
 41:      * @var array
 42:      */
 43:     protected $_checkedProductsQty = array();
 44: 
 45:     /**
 46:      * Product qty's checked
 47:      * data is valid if you check quote item qty and use singleton instance
 48:      *
 49:      * @var array
 50:      */
 51:     protected $_checkedQuoteItems = array();
 52: 
 53:     protected $_itemsForReindex = array();
 54: 
 55:     /**
 56:      * Array, indexed by product's id to contain stockItems of already loaded products
 57:      * Some kind of singleton for product's stock item
 58:      *
 59:      * @var array
 60:      */
 61:     protected $_stockItemsArray = array();
 62: 
 63:     /**
 64:      * Add stock information to product
 65:      *
 66:      * @param   Varien_Event_Observer $observer
 67:      * @return  Mage_CatalogInventory_Model_Observer
 68:      */
 69:     public function addInventoryData($observer)
 70:     {
 71:         $product = $observer->getEvent()->getProduct();
 72:         if ($product instanceof Mage_Catalog_Model_Product) {
 73:             $productId = intval($product->getId());
 74:             if (!isset($this->_stockItemsArray[$productId])) {
 75:                 $this->_stockItemsArray[$productId] = Mage::getModel('cataloginventory/stock_item');
 76:             }
 77:             $productStockItem = $this->_stockItemsArray[$productId];
 78:             $productStockItem->assignProduct($product);
 79:         }
 80:         return $this;
 81:     }
 82: 
 83:     /**
 84:      * Remove stock information from static variable
 85:      *
 86:      * @param   Varien_Event_Observer $observer
 87:      * @return  Mage_CatalogInventory_Model_Observer
 88:      */
 89:     public function removeInventoryData($observer)
 90:     {
 91:         $product = $observer->getEvent()->getProduct();
 92:         if (($product instanceof Mage_Catalog_Model_Product)
 93:             && $product->getId()
 94:             && isset($this->_stockItemsArray[$product->getId()])) {
 95:             unset($this->_stockItemsArray[$product->getId()]);
 96:         }
 97:         return $this;
 98:     }
 99: 
100:     /**
101:      * Add information about producs stock status to collection
102:      * Used in for product collection after load
103:      *
104:      * @param   Varien_Event_Observer $observer
105:      * @return  Mage_CatalogInventory_Model_Observer
106:      */
107:     public function addStockStatusToCollection($observer)
108:     {
109:         $productCollection = $observer->getEvent()->getCollection();
110:         if ($productCollection->hasFlag('require_stock_items')) {
111:             Mage::getModel('cataloginventory/stock')->addItemsToProducts($productCollection);
112:         } else {
113:             Mage::getModel('cataloginventory/stock_status')->addStockStatusToProducts($productCollection);
114:         }
115:         return $this;
116:     }
117: 
118:     /**
119:      * Add Stock items to product collection
120:      *
121:      * @param   Varien_Event_Observer $observer
122:      * @return  Mage_CatalogInventory_Model_Observer
123:      */
124:     public function addInventoryDataToCollection($observer)
125:     {
126:         $productCollection = $observer->getEvent()->getProductCollection();
127:         Mage::getModel('cataloginventory/stock')->addItemsToProducts($productCollection);
128:         return $this;
129:     }
130: 
131:     /**
132:      * Saving product inventory data. Product qty calculated dynamically.
133:      *
134:      * @param   Varien_Event_Observer $observer
135:      * @return  Mage_CatalogInventory_Model_Observer
136:      */
137:     public function saveInventoryData($observer)
138:     {
139:         $product = $observer->getEvent()->getProduct();
140: 
141:         if (is_null($product->getStockData())) {
142:             if ($product->getIsChangedWebsites() || $product->dataHasChangedFor('status')) {
143:                 Mage::getSingleton('cataloginventory/stock_status')
144:                     ->updateStatus($product->getId());
145:             }
146:             return $this;
147:         }
148: 
149:         $item = $product->getStockItem();
150:         if (!$item) {
151:             $item = Mage::getModel('cataloginventory/stock_item');
152:         }
153:         $this->_prepareItemForSave($item, $product);
154:         $item->save();
155:         return $this;
156:     }
157: 
158:     /**
159:      * Copy product inventory data (used for product duplicate functionality)
160:      *
161:      * @param   Varien_Event_Observer $observer
162:      * @return  Mage_CatalogInventory_Model_Observer
163:      */
164:     public function copyInventoryData($observer)
165:     {
166:         /** @var Mage_Catalog_Model_Product $currentProduct */
167:         $currentProduct = $observer->getEvent()->getCurrentProduct();
168:         /** @var Mage_Catalog_Model_Product $newProduct */
169:         $newProduct = $observer->getEvent()->getNewProduct();
170: 
171:         $newProduct->unsStockItem();
172:         $stockData = array(
173:             'use_config_min_qty'        => 1,
174:             'use_config_min_sale_qty'   => 1,
175:             'use_config_max_sale_qty'   => 1,
176:             'use_config_backorders'     => 1,
177:             'use_config_notify_stock_qty'=> 1
178:         );
179:         if ($currentStockItem = $currentProduct->getStockItem()) {
180:             $stockData += array(
181:                 'use_config_enable_qty_inc'  => $currentStockItem->getData('use_config_enable_qty_inc'),
182:                 'enable_qty_increments'             => $currentStockItem->getData('enable_qty_increments'),
183:                 'use_config_qty_increments'         => $currentStockItem->getData('use_config_qty_increments'),
184:                 'qty_increments'                    => $currentStockItem->getData('qty_increments'),
185:             );
186:         }
187:         $newProduct->setStockData($stockData);
188: 
189:         return $this;
190:     }
191: 
192:     /**
193:      * Prepare stock item data for save
194:      *
195:      * @param Mage_CatalogInventory_Model_Stock_Item $item
196:      * @param Mage_Catalog_Model_Product $product
197:      * @return Mage_CatalogInventory_Model_Observer
198:      */
199:     protected function _prepareItemForSave($item, $product)
200:     {
201:         $item->addData($product->getStockData())
202:             ->setProduct($product)
203:             ->setProductId($product->getId())
204:             ->setStockId($item->getStockId());
205:         if (!is_null($product->getData('stock_data/min_qty'))
206:             && is_null($product->getData('stock_data/use_config_min_qty'))) {
207:             $item->setData('use_config_min_qty', false);
208:         }
209:         if (!is_null($product->getData('stock_data/min_sale_qty'))
210:             && is_null($product->getData('stock_data/use_config_min_sale_qty'))) {
211:             $item->setData('use_config_min_sale_qty', false);
212:         }
213:         if (!is_null($product->getData('stock_data/max_sale_qty'))
214:             && is_null($product->getData('stock_data/use_config_max_sale_qty'))) {
215:             $item->setData('use_config_max_sale_qty', false);
216:         }
217:         if (!is_null($product->getData('stock_data/backorders'))
218:             && is_null($product->getData('stock_data/use_config_backorders'))) {
219:             $item->setData('use_config_backorders', false);
220:         }
221:         if (!is_null($product->getData('stock_data/notify_stock_qty'))
222:             && is_null($product->getData('stock_data/use_config_notify_stock_qty'))) {
223:             $item->setData('use_config_notify_stock_qty', false);
224:         }
225:         $originalQty = $product->getData('stock_data/original_inventory_qty');
226:         if (strlen($originalQty)>0) {
227:             $item->setQtyCorrection($item->getQty()-$originalQty);
228:         }
229:         if (!is_null($product->getData('stock_data/enable_qty_increments'))
230:             && is_null($product->getData('stock_data/use_config_enable_qty_inc'))) {
231:             $item->setData('use_config_enable_qty_inc', false);
232:         }
233:         if (!is_null($product->getData('stock_data/qty_increments'))
234:             && is_null($product->getData('stock_data/use_config_qty_increments'))) {
235:             $item->setData('use_config_qty_increments', false);
236:         }
237:         return $this;
238: 
239:     }
240: 
241:     /**
242:      * Removes error statuses from quote and item, set by this observer
243:      *
244:      * @param Mage_Sales_Model_Quote_Item $item
245:      * @param int $code
246:      * @return Mage_CatalogInventory_Model_Observer
247:      */
248:     protected function _removeErrorsFromQuoteAndItem($item, $code)
249:     {
250:         if ($item->getHasError()) {
251:             $params = array(
252:                 'origin' => 'cataloginventory',
253:                 'code' => $code
254:             );
255:             $item->removeErrorInfosByParams($params);
256:         }
257: 
258:         $quote = $item->getQuote();
259:         $quoteItems = $quote->getItemsCollection();
260:         $canRemoveErrorFromQuote = true;
261: 
262:         foreach ($quoteItems as $quoteItem) {
263:             if ($quoteItem->getItemId() == $item->getItemId()) {
264:                 continue;
265:             }
266: 
267:             $errorInfos = $quoteItem->getErrorInfos();
268:             foreach ($errorInfos as $errorInfo) {
269:                 if ($errorInfo['code'] == $code) {
270:                     $canRemoveErrorFromQuote = false;
271:                     break;
272:                 }
273:             }
274: 
275:             if (!$canRemoveErrorFromQuote) {
276:                 break;
277:             }
278:         }
279: 
280:         if ($quote->getHasError() && $canRemoveErrorFromQuote) {
281:             $params = array(
282:                 'origin' => 'cataloginventory',
283:                 'code' => $code
284:             );
285:             $quote->removeErrorInfosByParams(null, $params);
286:         }
287: 
288:         return $this;
289:     }
290: 
291:     /**
292:      * Check product inventory data when quote item quantity declaring
293:      *
294:      * @param  Varien_Event_Observer $observer
295:      * @return Mage_CatalogInventory_Model_Observer
296:      */
297:     public function checkQuoteItemQty($observer)
298:     {
299:         $quoteItem = $observer->getEvent()->getItem();
300:         /* @var $quoteItem Mage_Sales_Model_Quote_Item */
301:         if (!$quoteItem || !$quoteItem->getProductId() || !$quoteItem->getQuote()
302:             || $quoteItem->getQuote()->getIsSuperMode()) {
303:             return $this;
304:         }
305: 
306:         /**
307:          * Get Qty
308:          */
309:         $qty = $quoteItem->getQty();
310: 
311:         /**
312:          * Check item for options
313:          */
314:         if (($options = $quoteItem->getQtyOptions()) && $qty > 0) {
315:             $qty = $quoteItem->getProduct()->getTypeInstance(true)->prepareQuoteItemQty($qty, $quoteItem->getProduct());
316:             $quoteItem->setData('qty', $qty);
317: 
318:             $stockItem = $quoteItem->getProduct()->getStockItem();
319:             if ($stockItem) {
320:                 $result = $stockItem->checkQtyIncrements($qty);
321:                 if ($result->getHasError()) {
322:                     $quoteItem->addErrorInfo(
323:                         'cataloginventory',
324:                         Mage_CatalogInventory_Helper_Data::ERROR_QTY_INCREMENTS,
325:                         $result->getMessage()
326:                     );
327: 
328:                     $quoteItem->getQuote()->addErrorInfo(
329:                         $result->getQuoteMessageIndex(),
330:                         'cataloginventory',
331:                         Mage_CatalogInventory_Helper_Data::ERROR_QTY_INCREMENTS,
332:                         $result->getQuoteMessage()
333:                     );
334:                 } else {
335:                     // Delete error from item and its quote, if it was set due to qty problems
336:                     $this->_removeErrorsFromQuoteAndItem(
337:                         $quoteItem,
338:                         Mage_CatalogInventory_Helper_Data::ERROR_QTY_INCREMENTS
339:                     );
340:                 }
341:             }
342: 
343:             foreach ($options as $option) {
344:                 $optionValue = $option->getValue();
345:                 /* @var $option Mage_Sales_Model_Quote_Item_Option */
346:                 $optionQty = $qty * $optionValue;
347:                 $increaseOptionQty = ($quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty) * $optionValue;
348: 
349:                 $stockItem = $option->getProduct()->getStockItem();
350: 
351:                 if ($quoteItem->getProductType() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) {
352:                     $stockItem->setProductName($quoteItem->getName());
353:                 }
354: 
355:                 /* @var $stockItem Mage_CatalogInventory_Model_Stock_Item */
356:                 if (!$stockItem instanceof Mage_CatalogInventory_Model_Stock_Item) {
357:                     Mage::throwException(
358:                         Mage::helper('cataloginventory')->__('The stock item for Product in option is not valid.')
359:                     );
360:                 }
361: 
362:                 /**
363:                  * define that stock item is child for composite product
364:                  */
365:                 $stockItem->setIsChildItem(true);
366:                 /**
367:                  * don't check qty increments value for option product
368:                  */
369:                 $stockItem->setSuppressCheckQtyIncrements(true);
370: 
371:                 $qtyForCheck = $this->_getQuoteItemQtyForCheck(
372:                     $option->getProduct()->getId(),
373:                     $quoteItem->getId(),
374:                     $increaseOptionQty
375:                 );
376: 
377:                 $result = $stockItem->checkQuoteItemQty($optionQty, $qtyForCheck, $optionValue);
378: 
379:                 if (!is_null($result->getItemIsQtyDecimal())) {
380:                     $option->setIsQtyDecimal($result->getItemIsQtyDecimal());
381:                 }
382: 
383:                 if ($result->getHasQtyOptionUpdate()) {
384:                     $option->setHasQtyOptionUpdate(true);
385:                     $quoteItem->updateQtyOption($option, $result->getOrigQty());
386:                     $option->setValue($result->getOrigQty());
387:                     /**
388:                      * if option's qty was updates we also need to update quote item qty
389:                      */
390:                     $quoteItem->setData('qty', intval($qty));
391:                 }
392:                 if (!is_null($result->getMessage())) {
393:                     $option->setMessage($result->getMessage());
394:                     $quoteItem->setMessage($result->getMessage());
395:                 }
396:                 if (!is_null($result->getItemBackorders())) {
397:                     $option->setBackorders($result->getItemBackorders());
398:                 }
399: 
400:                 if ($result->getHasError()) {
401:                     $option->setHasError(true);
402: 
403:                     $quoteItem->addErrorInfo(
404:                         'cataloginventory',
405:                         Mage_CatalogInventory_Helper_Data::ERROR_QTY,
406:                         $result->getQuoteMessage()
407:                     );
408: 
409:                     $quoteItem->getQuote()->addErrorInfo(
410:                         $result->getQuoteMessageIndex(),
411:                         'cataloginventory',
412:                         Mage_CatalogInventory_Helper_Data::ERROR_QTY,
413:                         $result->getQuoteMessage()
414:                     );
415:                 } else {
416:                     // Delete error from item and its quote, if it was set due to qty lack
417:                     $this->_removeErrorsFromQuoteAndItem($quoteItem, Mage_CatalogInventory_Helper_Data::ERROR_QTY);
418:                 }
419: 
420:                 $stockItem->unsIsChildItem();
421:             }
422:         } else {
423:             $stockItem = $quoteItem->getProduct()->getStockItem();
424:             /* @var $stockItem Mage_CatalogInventory_Model_Stock_Item */
425:             if (!$stockItem instanceof Mage_CatalogInventory_Model_Stock_Item) {
426:                 Mage::throwException(Mage::helper('cataloginventory')->__('The stock item for Product is not valid.'));
427:             }
428: 
429:             /**
430:              * When we work with subitem (as subproduct of bundle or configurable product)
431:              */
432:             if ($quoteItem->getParentItem()) {
433:                 $rowQty = $quoteItem->getParentItem()->getQty() * $qty;
434:                 /**
435:                  * we are using 0 because original qty was processed
436:                  */
437:                 $qtyForCheck = $this->_getQuoteItemQtyForCheck(
438:                     $quoteItem->getProduct()->getId(),
439:                     $quoteItem->getId(),
440:                     0
441:                 );
442:             } else {
443:                 $increaseQty = $quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty;
444:                 $rowQty = $qty;
445:                 $qtyForCheck = $this->_getQuoteItemQtyForCheck(
446:                     $quoteItem->getProduct()->getId(),
447:                     $quoteItem->getId(),
448:                     $increaseQty
449:                 );
450:             }
451: 
452:             $productTypeCustomOption = $quoteItem->getProduct()->getCustomOption('product_type');
453:             if (!is_null($productTypeCustomOption)) {
454:                 // Check if product related to current item is a part of grouped product
455:                 if ($productTypeCustomOption->getValue() == Mage_Catalog_Model_Product_Type_Grouped::TYPE_CODE) {
456:                     $stockItem->setIsChildItem(true);
457:                 }
458:             }
459: 
460:             $result = $stockItem->checkQuoteItemQty($rowQty, $qtyForCheck, $qty);
461: 
462:             if ($stockItem->hasIsChildItem()) {
463:                 $stockItem->unsIsChildItem();
464:             }
465: 
466:             if (!is_null($result->getItemIsQtyDecimal())) {
467:                 $quoteItem->setIsQtyDecimal($result->getItemIsQtyDecimal());
468:                 if ($quoteItem->getParentItem()) {
469:                     $quoteItem->getParentItem()->setIsQtyDecimal($result->getItemIsQtyDecimal());
470:                 }
471:             }
472: 
473:             /**
474:              * Just base (parent) item qty can be changed
475:              * qty of child products are declared just during add process
476:              * exception for updating also managed by product type
477:              */
478:             if ($result->getHasQtyOptionUpdate()
479:                 && (!$quoteItem->getParentItem()
480:                     || $quoteItem->getParentItem()->getProduct()->getTypeInstance(true)
481:                         ->getForceChildItemQtyChanges($quoteItem->getParentItem()->getProduct())
482:                 )
483:             ) {
484:                 $quoteItem->setData('qty', $result->getOrigQty());
485:             }
486: 
487:             if (!is_null($result->getItemUseOldQty())) {
488:                 $quoteItem->setUseOldQty($result->getItemUseOldQty());
489:             }
490:             if (!is_null($result->getMessage())) {
491:                 $quoteItem->setMessage($result->getMessage());
492:                 if ($quoteItem->getParentItem()) {
493:                     $quoteItem->getParentItem()->setMessage($result->getMessage());
494:                 }
495:             }
496: 
497:             if (!is_null($result->getItemBackorders())) {
498:                 $quoteItem->setBackorders($result->getItemBackorders());
499:             }
500: 
501:             if ($result->getHasError()) {
502:                 $quoteItem->addErrorInfo(
503:                     'cataloginventory',
504:                     Mage_CatalogInventory_Helper_Data::ERROR_QTY,
505:                     $result->getMessage()
506:                 );
507: 
508:                 $quoteItem->getQuote()->addErrorInfo(
509:                     $result->getQuoteMessageIndex(),
510:                     'cataloginventory',
511:                     Mage_CatalogInventory_Helper_Data::ERROR_QTY,
512:                     $result->getQuoteMessage()
513:                 );
514:             } else {
515:                 // Delete error from item and its quote, if it was set due to qty lack
516:                 $this->_removeErrorsFromQuoteAndItem($quoteItem, Mage_CatalogInventory_Helper_Data::ERROR_QTY);
517:             }
518:         }
519: 
520:         return $this;
521:     }
522: 
523:     /**
524:      * Get product qty includes information from all quote items
525:      * Need be used only in sungleton mode
526:      *
527:      * @deprecated after 1.4.2.0-rc1
528:      * @param int $productId
529:      * @param float $itemQty
530:      */
531:     protected function _getProductQtyForCheck($productId, $itemQty)
532:     {
533:         $qty = $itemQty;
534:         if (isset($this->_checkedProductsQty[$productId])) {
535:             $qty += $this->_checkedProductsQty[$productId];
536:         }
537:         $this->_checkedProductsQty[$productId] = $qty;
538:         return $qty;
539:     }
540: 
541:     /**
542:      * Get product qty includes information from all quote items
543:      * Need be used only in sungleton mode
544:      *
545:      * @param int   $productId
546:      * @param int   $quoteItemId
547:      * @param float $itemQty
548:      * @return int
549:      */
550:     protected function _getQuoteItemQtyForCheck($productId, $quoteItemId, $itemQty)
551:     {
552:         $qty = $itemQty;
553:         if (isset($this->_checkedQuoteItems[$productId]['qty']) &&
554:             !in_array($quoteItemId, $this->_checkedQuoteItems[$productId]['items'])) {
555:                 $qty += $this->_checkedQuoteItems[$productId]['qty'];
556:         }
557: 
558:         $this->_checkedQuoteItems[$productId]['qty'] = $qty;
559:         $this->_checkedQuoteItems[$productId]['items'][] = $quoteItemId;
560: 
561:         return $qty;
562:     }
563: 
564:     /**
565:      * Subtract qtys of quote item products after multishipping checkout
566:      *
567:      * @param Varien_Event_Observer $observer
568:      * @return Mage_CatalogInventory_Model_Observer
569:      */
570:     public function checkoutAllSubmitAfter(Varien_Event_Observer $observer)
571:     {
572:         $quote = $observer->getEvent()->getQuote();
573:         if (!$quote->getInventoryProcessed()) {
574:             $this->subtractQuoteInventory($observer);
575:             $this->reindexQuoteInventory($observer);
576:         }
577:         return $this;
578:     }
579: 
580:     /**
581:      * Subtract quote items qtys from stock items related with quote items products.
582:      *
583:      * Used before order placing to make order save/place transaction smaller
584:      * Also called after every successful order placement to ensure subtraction of inventory
585:      *
586:      * @param Varien_Event_Observer $observer
587:      */
588:     public function subtractQuoteInventory(Varien_Event_Observer $observer)
589:     {
590:         $quote = $observer->getEvent()->getQuote();
591: 
592:         // Maybe we've already processed this quote in some event during order placement
593:         // e.g. call in event 'sales_model_service_quote_submit_before' and later in 'checkout_submit_all_after'
594:         if ($quote->getInventoryProcessed()) {
595:             return;
596:         }
597:         $items = $this->_getProductsQty($quote->getAllItems());
598: 
599:         /**
600:          * Remember items
601:          */
602:         $this->_itemsForReindex = Mage::getSingleton('cataloginventory/stock')->registerProductsSale($items);
603: 
604:         $quote->setInventoryProcessed(true);
605:         return $this;
606:     }
607: 
608:     /**
609:      * Revert quote items inventory data (cover not success order place case)
610:      * @param $observer
611:      */
612:     public function revertQuoteInventory($observer)
613:     {
614:         $quote = $observer->getEvent()->getQuote();
615:         $items = $this->_getProductsQty($quote->getAllItems());
616:         Mage::getSingleton('cataloginventory/stock')->revertProductsSale($items);
617: 
618:         // Clear flag, so if order placement retried again with success - it will be processed
619:         $quote->setInventoryProcessed(false);
620:     }
621: 
622:     /**
623:      * Adds stock item qty to $items (creates new entry or increments existing one)
624:      * $items is array with following structure:
625:      * array(
626:      *  $productId  => array(
627:      *      'qty'   => $qty,
628:      *      'item'  => $stockItems|null
629:      *  )
630:      * )
631:      *
632:      * @param Mage_Sales_Model_Quote_Item $quoteItem
633:      * @param array &$items
634:      */
635:     protected function _addItemToQtyArray($quoteItem, &$items)
636:     {
637:         $productId = $quoteItem->getProductId();
638:         if (!$productId)
639:             return;
640:         if (isset($items[$productId])) {
641:             $items[$productId]['qty'] += $quoteItem->getTotalQty();
642:         } else {
643:             $stockItem = null;
644:             if ($quoteItem->getProduct()) {
645:                 $stockItem = $quoteItem->getProduct()->getStockItem();
646:             }
647:             $items[$productId] = array(
648:                 'item' => $stockItem,
649:                 'qty'  => $quoteItem->getTotalQty()
650:             );
651:         }
652:     }
653: 
654:     /**
655:      * Prepare array with information about used product qty and product stock item
656:      * result is:
657:      * array(
658:      *  $productId  => array(
659:      *      'qty'   => $qty,
660:      *      'item'  => $stockItems|null
661:      *  )
662:      * )
663:      * @param array $relatedItems
664:      * @return array
665:      */
666:     protected function _getProductsQty($relatedItems)
667:     {
668:         $items = array();
669:         foreach ($relatedItems as $item) {
670:             $productId  = $item->getProductId();
671:             if (!$productId) {
672:                 continue;
673:             }
674:             $children = $item->getChildrenItems();
675:             if ($children) {
676:                 foreach ($children as $childItem) {
677:                     $this->_addItemToQtyArray($childItem, $items);
678:                 }
679:             } else {
680:                 $this->_addItemToQtyArray($item, $items);
681:             }
682:         }
683:         return $items;
684:     }
685: 
686:     /**
687:      * Refresh stock index for specific stock items after succesful order placement
688:      *
689:      * @param $observer
690:      */
691:     public function reindexQuoteInventory($observer)
692:     {
693:         // Reindex quote ids
694:         $quote = $observer->getEvent()->getQuote();
695:         $productIds = array();
696:         foreach ($quote->getAllItems() as $item) {
697:             $productIds[$item->getProductId()] = $item->getProductId();
698:             $children   = $item->getChildrenItems();
699:             if ($children) {
700:                 foreach ($children as $childItem) {
701:                     $productIds[$childItem->getProductId()] = $childItem->getProductId();
702:                 }
703:             }
704:         }
705: 
706:         if( count($productIds)) {
707:             Mage::getResourceSingleton('cataloginventory/indexer_stock')->reindexProducts($productIds);
708:         }
709: 
710:         // Reindex previously remembered items
711:         $productIds = array();
712:         foreach ($this->_itemsForReindex as $item) {
713:             $item->save();
714:             $productIds[] = $item->getProductId();
715:         }
716:         Mage::getResourceSingleton('catalog/product_indexer_price')->reindexProductIds($productIds);
717: 
718:         $this->_itemsForReindex = array(); // Clear list of remembered items - we don't need it anymore
719: 
720:         return $this;
721:     }
722: 
723:     /**
724:      * Return creditmemo items qty to stock
725:      *
726:      * @param Varien_Event_Observer $observer
727:      */
728:     public function refundOrderInventory($observer)
729:     {
730:         /* @var $creditmemo Mage_Sales_Model_Order_Creditmemo */
731:         $creditmemo = $observer->getEvent()->getCreditmemo();
732:         $items = array();
733:         foreach ($creditmemo->getAllItems() as $item) {
734:             /* @var $item Mage_Sales_Model_Order_Creditmemo_Item */
735:             $return = false;
736:             if ($item->hasBackToStock()) {
737:                 if ($item->getBackToStock() && $item->getQty()) {
738:                     $return = true;
739:                 }
740:             } elseif (Mage::helper('cataloginventory')->isAutoReturnEnabled()) {
741:                 $return = true;
742:             }
743:             if ($return) {
744:                 $parentOrderId = $item->getOrderItem()->getParentItemId();
745:                 /* @var $parentItem Mage_Sales_Model_Order_Creditmemo_Item */
746:                 $parentItem = $parentOrderId ? $creditmemo->getItemByOrderId($parentOrderId) : false;
747:                 $qty = $parentItem ? ($parentItem->getQty() * $item->getQty()) : $item->getQty();
748:                 if (isset($items[$item->getProductId()])) {
749:                     $items[$item->getProductId()]['qty'] += $qty;
750:                 } else {
751:                     $items[$item->getProductId()] = array(
752:                         'qty' => $qty,
753:                         'item'=> null,
754:                     );
755:                 }
756:             }
757:         }
758:         Mage::getSingleton('cataloginventory/stock')->revertProductsSale($items);
759:     }
760: 
761:     /**
762:      * Cancel order item
763:      *
764:      * @param   Varien_Event_Observer $observer
765:      * @return  Mage_CatalogInventory_Model_Observer
766:      */
767:     public function cancelOrderItem($observer)
768:     {
769:         $item = $observer->getEvent()->getItem();
770: 
771:         $children = $item->getChildrenItems();
772:         $qty = $item->getQtyOrdered() - max($item->getQtyShipped(), $item->getQtyInvoiced()) - $item->getQtyCanceled();
773: 
774:         if ($item->getId() && ($productId = $item->getProductId()) && empty($children) && $qty) {
775:             Mage::getSingleton('cataloginventory/stock')->backItemQty($productId, $qty);
776:         }
777: 
778:         return $this;
779:     }
780: 
781:     /**
782:      * Update items stock status and low stock date.
783:      *
784:      * @param Varien_Event_Observer $observer
785:      * @return  Mage_CatalogInventory_Model_Observer
786:      */
787:     public function updateItemsStockUponConfigChange($observer)
788:     {
789:         Mage::getResourceSingleton('cataloginventory/stock')->updateSetOutOfStock();
790:         Mage::getResourceSingleton('cataloginventory/stock')->updateSetInStock();
791:         Mage::getResourceSingleton('cataloginventory/stock')->updateLowStockDate();
792:         return $this;
793:     }
794: 
795:     /**
796:      * Update Only product status observer
797:      *
798:      * @param Varien_Event_Observer $observer
799:      * @return Mage_CatalogInventory_Model_Observer
800:      */
801:     public function productStatusUpdate(Varien_Event_Observer $observer)
802:     {
803:         $productId = $observer->getEvent()->getProductId();
804:         Mage::getSingleton('cataloginventory/stock_status')
805:             ->updateStatus($productId);
806:         return $this;
807:     }
808: 
809:     /**
810:      * Catalog Product website update
811:      *
812:      * @param Varien_Event_Observer $observer
813:      * @return Mage_CatalogInventory_Model_Observer
814:      */
815:     public function catalogProductWebsiteUpdate(Varien_Event_Observer $observer)
816:     {
817:         $websiteIds = $observer->getEvent()->getWebsiteIds();
818:         $productIds = $observer->getEvent()->getProductIds();
819: 
820:         foreach ($websiteIds as $websiteId) {
821:             foreach ($productIds as $productId) {
822:                 Mage::getSingleton('cataloginventory/stock_status')
823:                     ->updateStatus($productId, null, $websiteId);
824:             }
825:         }
826: 
827:         return $this;
828:     }
829: 
830:     /**
831:      * Add stock status to prepare index select
832:      *
833:      * @param Varien_Event_Observer $observer
834:      * @return Mage_CatalogInventory_Model_Observer
835:      */
836:     public function addStockStatusToPrepareIndexSelect(Varien_Event_Observer $observer)
837:     {
838:         $website    = $observer->getEvent()->getWebsite();
839:         $select     = $observer->getEvent()->getSelect();
840: 
841:         Mage::getSingleton('cataloginventory/stock_status')
842:             ->addStockStatusToSelect($select, $website);
843: 
844:         return $this;
845:     }
846: 
847:     /**
848:      * Add stock status limitation to catalog product price index select object
849:      *
850:      * @param Varien_Event_Observer $observer
851:      * @return Mage_CatalogInventory_Model_Observer
852:      */
853:     public function prepareCatalogProductIndexSelect(Varien_Event_Observer $observer)
854:     {
855:         $select     = $observer->getEvent()->getSelect();
856:         $entity     = $observer->getEvent()->getEntityField();
857:         $website    = $observer->getEvent()->getWebsiteField();
858: 
859:         Mage::getSingleton('cataloginventory/stock_status')
860:             ->prepareCatalogProductIndexSelect($select, $entity, $website);
861: 
862:         return $this;
863:     }
864: 
865:     /**
866:      * Lock DB rows for order products
867:      *
868:      * We need do it for resolving problems with inventory on placing
869:      * some orders in one time
870:      * @deprecated after 1.4
871:      * @param   Varien_Event_Observer $observer
872:      * @return  Mage_CatalogInventory_Model_Observer
873:      */
874:     public function lockOrderInventoryData($observer)
875:     {
876:         $order = $observer->getEvent()->getOrder();
877:         $productIds = array();
878: 
879:         /**
880:          * Do lock only for new order
881:          */
882:         if ($order->getId()) {
883:             return $this;
884:         }
885: 
886:         if ($order) {
887:             foreach ($order->getAllItems() as $item) {
888:                 $productIds[] = $item->getProductId();
889:             }
890:         }
891: 
892:         if (!empty($productIds)) {
893:             Mage::getSingleton('cataloginventory/stock')->lockProductItems($productIds);
894:         }
895: 
896:         return $this;
897:     }
898: 
899:     /**
900:      * Register saving order item
901:      *
902:      * @deprecated after 1.4
903:      * @param   Varien_Event_Observer $observer
904:      * @return  Mage_CatalogInventory_Model_Observer
905:      */
906:     public function createOrderItem($observer)
907:     {
908:         $item = $observer->getEvent()->getItem();
909:         /**
910:          * Before creating order item need subtract ordered qty from product stock
911:          */
912: 
913:         $children = $item->getChildrenItems();
914: 
915:         if (!$item->getId() && empty($children)) {
916:             Mage::getSingleton('cataloginventory/stock')->registerItemSale($item);
917:         }
918: 
919:         return $this;
920:     }
921: 
922:     /**
923:      * Back refunded item qty to stock
924:      *
925:      * @deprecated after 1.4
926:      * @param   Varien_Event_Observer $observer
927:      * @return  Mage_CatalogInventory_Model_Observer
928:      */
929:     public function refundOrderItem($observer)
930:     {
931:         $item = $observer->getEvent()->getCreditmemoItem();
932:         if ($item->getId() && $item->getBackToStock() && ($productId = $item->getProductId())
933:             && ($qty = $item->getQty())
934:         ) {
935:             Mage::getSingleton('cataloginventory/stock')->backItemQty($productId, $qty);
936:         }
937:         return $this;
938:     }
939: 
940:     /**
941:      * Reindex all events of product-massAction type
942:      *
943:      * @param Varien_Event_Observer $observer
944:      */
945:     public function reindexProductsMassAction($observer)
946:     {
947:         Mage::getSingleton('index/indexer')->indexEvents(
948:             Mage_Catalog_Model_Product::ENTITY, Mage_Index_Model_Event::TYPE_MASS_ACTION
949:         );
950:     }
951: }
952: 
Magento 1.7.0.2 API documentation generated by ApiGen 2.8.0