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: /**
 29:  * Catalog Inventory Stock Model
 30:  *
 31:  * @method Mage_CatalogInventory_Model_Resource_Stock_Item _getResource()
 32:  * @method Mage_CatalogInventory_Model_Resource_Stock_Item getResource()
 33:  * @method Mage_CatalogInventory_Model_Stock_Item setProductId(int $value)
 34:  * @method Mage_CatalogInventory_Model_Stock_Item setStockId(int $value)
 35:  * @method float getQty()
 36:  * @method Mage_CatalogInventory_Model_Stock_Item setQty(float $value)
 37:  * @method Mage_CatalogInventory_Model_Stock_Item setMinQty(float $value)
 38:  * @method int getUseConfigMinQty()
 39:  * @method Mage_CatalogInventory_Model_Stock_Item setUseConfigMinQty(int $value)
 40:  * @method int getIsQtyDecimal()
 41:  * @method Mage_CatalogInventory_Model_Stock_Item setIsQtyDecimal(int $value)
 42:  * @method Mage_CatalogInventory_Model_Stock_Item setBackorders(int $value)
 43:  * @method int getUseConfigBackorders()
 44:  * @method Mage_CatalogInventory_Model_Stock_Item setUseConfigBackorders(int $value)
 45:  * @method Mage_CatalogInventory_Model_Stock_Item setMinSaleQty(float $value)
 46:  * @method int getUseConfigMinSaleQty()
 47:  * @method Mage_CatalogInventory_Model_Stock_Item setUseConfigMinSaleQty(int $value)
 48:  * @method Mage_CatalogInventory_Model_Stock_Item setMaxSaleQty(float $value)
 49:  * @method int getUseConfigMaxSaleQty()
 50:  * @method Mage_CatalogInventory_Model_Stock_Item setUseConfigMaxSaleQty(int $value)
 51:  * @method Mage_CatalogInventory_Model_Stock_Item setIsInStock(int $value)
 52:  * @method string getLowStockDate()
 53:  * @method Mage_CatalogInventory_Model_Stock_Item setLowStockDate(string $value)
 54:  * @method Mage_CatalogInventory_Model_Stock_Item setNotifyStockQty(float $value)
 55:  * @method int getUseConfigNotifyStockQty()
 56:  * @method Mage_CatalogInventory_Model_Stock_Item setUseConfigNotifyStockQty(int $value)
 57:  * @method Mage_CatalogInventory_Model_Stock_Item setManageStock(int $value)
 58:  * @method int getUseConfigManageStock()
 59:  * @method Mage_CatalogInventory_Model_Stock_Item setUseConfigManageStock(int $value)
 60:  * @method int getStockStatusChangedAutomatically()
 61:  * @method Mage_CatalogInventory_Model_Stock_Item setStockStatusChangedAutomatically(int $value)
 62:  * @method int getUseConfigQtyIncrements()
 63:  * @method Mage_CatalogInventory_Model_Stock_Item setUseConfigQtyIncrements(int $value)
 64:  * @method Mage_CatalogInventory_Model_Stock_Item setQtyIncrements(float $value)
 65:  * @method int getUseConfigEnableQtyIncrements()
 66:  * @method Mage_CatalogInventory_Model_Stock_Item setUseConfigEnableQtyIncrements(int $value)
 67:  * @method Mage_CatalogInventory_Model_Stock_Item setEnableQtyIncrements(int $value)
 68:  *
 69:  * @category    Mage
 70:  * @package     Mage_CatalogInventory
 71:  * @author      Magento Core Team <core@magentocommerce.com>
 72:  */
 73: class Mage_CatalogInventory_Model_Stock_Item extends Mage_Core_Model_Abstract
 74: {
 75:     const XML_PATH_GLOBAL                = 'cataloginventory/options/';
 76:     const XML_PATH_CAN_SUBTRACT          = 'cataloginventory/options/can_subtract';
 77:     const XML_PATH_CAN_BACK_IN_STOCK     = 'cataloginventory/options/can_back_in_stock';
 78: 
 79:     const XML_PATH_ITEM                  = 'cataloginventory/item_options/';
 80:     const XML_PATH_MIN_QTY               = 'cataloginventory/item_options/min_qty';
 81:     const XML_PATH_MIN_SALE_QTY          = 'cataloginventory/item_options/min_sale_qty';
 82:     const XML_PATH_MAX_SALE_QTY          = 'cataloginventory/item_options/max_sale_qty';
 83:     const XML_PATH_BACKORDERS            = 'cataloginventory/item_options/backorders';
 84:     const XML_PATH_NOTIFY_STOCK_QTY      = 'cataloginventory/item_options/notify_stock_qty';
 85:     const XML_PATH_MANAGE_STOCK          = 'cataloginventory/item_options/manage_stock';
 86:     const XML_PATH_ENABLE_QTY_INCREMENTS = 'cataloginventory/item_options/enable_qty_increments';
 87:     const XML_PATH_QTY_INCREMENTS        = 'cataloginventory/item_options/qty_increments';
 88: 
 89:     const ENTITY                         = 'cataloginventory_stock_item';
 90: 
 91:     /**
 92:      * @var array
 93:      */
 94:     private $_minSaleQtyCache = array();
 95: 
 96:     /**
 97:      * @var float|false
 98:      */
 99:     protected $_qtyIncrements;
100: 
101:     /**
102:      * Prefix of model events names
103:      *
104:      * @var string
105:      */
106:     protected $_eventPrefix = 'cataloginventory_stock_item';
107: 
108:     /**
109:      * Parameter name in event
110:      *
111:      * In observe method you can use $observer->getEvent()->getItem() in this case
112:      *
113:      * @var string
114:      */
115:     protected $_eventObject = 'item';
116: 
117:     /**
118:      * Associated product instance
119:      *
120:      * @var Mage_Catalog_Model_Product
121:      */
122:     protected $_productInstance = null;
123: 
124:     /**
125:      * Customer group id
126:      *
127:      * @var int|null
128:      */
129:     protected $_customerGroupId;
130: 
131:     /**
132:      * Whether index events should be processed immediately
133:      *
134:      * @var bool
135:      */
136:     protected $_processIndexEvents = true;
137: 
138:     /**
139:      * Initialize resource model
140:      *
141:      */
142:     protected function _construct()
143:     {
144:         $this->_init('cataloginventory/stock_item');
145:     }
146: 
147:     /**
148:      * Init mapping array of short fields to
149:      * its full names
150:      *
151:      * @resturn Varien_Object
152:      */
153:     protected function _initOldFieldsMap()
154:     {
155:         $this->_oldFieldsMap = array(
156:             'stock_status_changed_automatically' => 'stock_status_changed_auto',
157:             'use_config_enable_qty_increments'   => 'use_config_enable_qty_inc'
158:         );
159:     }
160: 
161:     /**
162:      * Retrieve stock identifier
163:      *
164:      * @todo multi stock
165:      * @return int
166:      */
167:     public function getStockId()
168:     {
169:         return 1;
170:     }
171: 
172:     /**
173:      * Retrieve Product Id data wrapper
174:      *
175:      * @return int
176:      */
177:     public function getProductId()
178:     {
179:         return $this->_getData('product_id');
180:     }
181: 
182:     /**
183:      * Load item data by product
184:      *
185:      * @param   mixed $product
186:      * @return  Mage_CatalogInventory_Model_Stock_Item
187:      */
188:     public function loadByProduct($product)
189:     {
190:         if ($product instanceof Mage_Catalog_Model_Product) {
191:             $product = $product->getId();
192:         }
193:         $this->_getResource()->loadByProductId($this, $product);
194:         $this->setOrigData();
195:         return $this;
196:     }
197: 
198:     /**
199:      * Subtract quote item quantity
200:      *
201:      * @param   decimal $qty
202:      * @return  Mage_CatalogInventory_Model_Stock_Item
203:      */
204:     public function subtractQty($qty)
205:     {
206:         if ($this->canSubtractQty()) {
207:             $this->setQty($this->getQty()-$qty);
208:         }
209:         return $this;
210:     }
211: 
212:     /**
213:      * Check if is possible subtract value from item qty
214:      *
215:      * @return bool
216:      */
217:     public function canSubtractQty()
218:     {
219:         return $this->getManageStock() && Mage::getStoreConfigFlag(self::XML_PATH_CAN_SUBTRACT);
220:     }
221: 
222:     /**
223:      * Add quantity process
224:      *
225:      * @param float $qty
226:      * @return Mage_CatalogInventory_Model_Stock_Item
227:      */
228:     public function addQty($qty)
229:     {
230:         if (!$this->getManageStock()) {
231:             return $this;
232:         }
233:         $config = Mage::getStoreConfigFlag(self::XML_PATH_CAN_SUBTRACT);
234:         if (!$config) {
235:             return $this;
236:         }
237: 
238:         $this->setQty($this->getQty()+$qty);
239:         return $this;
240:     }
241: 
242:     /**
243:      * Retrieve Store Id (product or current)
244:      *
245:      * @return int
246:      */
247:     public function getStoreId()
248:     {
249:         $storeId = $this->getData('store_id');
250:         if (is_null($storeId)) {
251:             $storeId = Mage::app()->getStore()->getId();
252:             $this->setData('store_id', $storeId);
253:         }
254:         return $storeId;
255:     }
256: 
257:     /**
258:      * Adding stock data to product
259:      *
260:      * @param   Mage_Catalog_Model_Product $product
261:      * @return  Mage_CatalogInventory_Model_Stock_Item
262:      */
263:     public function assignProduct(Mage_Catalog_Model_Product $product)
264:     {
265:         if (!$this->getId() || !$this->getProductId()) {
266:             $this->_getResource()->loadByProductId($this, $product->getId());
267:             $this->setOrigData();
268:         }
269: 
270:         $this->setProduct($product);
271:         $product->setStockItem($this);
272: 
273:         $product->setIsInStock($this->getIsInStock());
274:         Mage::getSingleton('cataloginventory/stock_status')
275:             ->assignProduct($product, $this->getStockId(), $this->getStockStatus());
276:         return $this;
277:     }
278: 
279:     /**
280:      * Retrieve minimal quantity available for item status in stock
281:      *
282:      * @return float
283:      */
284:     public function getMinQty()
285:     {
286:         return (float)($this->getUseConfigMinQty() ? Mage::getStoreConfig(self::XML_PATH_MIN_QTY)
287:             : $this->getData('min_qty'));
288:     }
289: 
290:     /**
291:      * Getter for customer group id
292:      *
293:      * @return int
294:      */
295:     public function getCustomerGroupId()
296:     {
297:         return $this->_customerGroupId;
298:     }
299: 
300:     /**
301:      * Setter for customer group id
302:      *
303:      * @param int Value of customer group id
304:      * @return Mage_CatalogInventory_Model_Stock_Item
305:      */
306:     public function setCustomerGroupId($value)
307:     {
308:         $this->_customerGroupId = $value;
309:         return $this;
310:     }
311: 
312:     /**
313:      * Retrieve Minimum Qty Allowed in Shopping Cart or NULL when there is no limitation
314:      *
315:      * @return float|null
316:      */
317:     public function getMinSaleQty()
318:     {
319:         $customerGroupId = $this->getCustomerGroupId();
320:         if (!$customerGroupId) {
321:             $customerGroupId = Mage::app()->getStore()->isAdmin()
322:                 ? Mage_Customer_Model_Group::CUST_GROUP_ALL
323:                 : Mage::getSingleton('customer/session')->getCustomerGroupId();
324:         }
325: 
326:         if (!isset($this->_minSaleQtyCache[$customerGroupId])) {
327:             $minSaleQty = $this->getUseConfigMinSaleQty()
328:                 ? Mage::helper('cataloginventory/minsaleqty')->getConfigValue($customerGroupId)
329:                 : $this->getData('min_sale_qty');
330: 
331:             $this->_minSaleQtyCache[$customerGroupId] = empty($minSaleQty) ? 0 : (float)$minSaleQty;
332:         }
333: 
334:         return $this->_minSaleQtyCache[$customerGroupId] ? $this->_minSaleQtyCache[$customerGroupId] : null;
335:     }
336: 
337:     /**
338:      * Retrieve Maximum Qty Allowed in Shopping Cart data wrapper
339:      *
340:      * @return float
341:      */
342:     public function getMaxSaleQty()
343:     {
344:         return (float)($this->getUseConfigMaxSaleQty() ? Mage::getStoreConfig(self::XML_PATH_MAX_SALE_QTY)
345:             : $this->getData('max_sale_qty'));
346:     }
347: 
348:     /**
349:      * Retrieve Notify for Quantity Below data wrapper
350:      *
351:      * @return float
352:      */
353:     public function getNotifyStockQty()
354:     {
355:         if ($this->getUseConfigNotifyStockQty()) {
356:             return (float) Mage::getStoreConfig(self::XML_PATH_NOTIFY_STOCK_QTY);
357:         }
358:         return (float) $this->getData('notify_stock_qty');
359:     }
360: 
361:     /**
362:      * Retrieve whether Quantity Increments is enabled
363:      *
364:      * @return bool
365:      */
366:     public function getEnableQtyIncrements()
367:     {
368:         return $this->getUseConfigEnableQtyIncrements()
369:             ? Mage::getStoreConfigFlag(self::XML_PATH_ENABLE_QTY_INCREMENTS)
370:             : (bool)$this->getData('enable_qty_increments');
371:     }
372: 
373:     /**
374:      * Retrieve Quantity Increments data wrapper
375:      *
376:      * @return float|false
377:      */
378:     public function getQtyIncrements()
379:     {
380:         if ($this->_qtyIncrements === null) {
381:             if ($this->getEnableQtyIncrements()) {
382:                 $this->_qtyIncrements = (float)($this->getUseConfigQtyIncrements()
383:                     ? Mage::getStoreConfig(self::XML_PATH_QTY_INCREMENTS)
384:                     : $this->getData('qty_increments'));
385:                 if ($this->_qtyIncrements <= 0) {
386:                     $this->_qtyIncrements = false;
387:                 }
388:             } else {
389:                 $this->_qtyIncrements = false;
390:             }
391:         }
392:         return $this->_qtyIncrements;
393:     }
394: 
395:      /**
396:      * Retrieve Default Quantity Increments data wrapper
397:      *
398:      * @deprecated since 1.7.0.0
399:      * @return int|false
400:      */
401:     public function getDefaultQtyIncrements()
402:     {
403:         return Mage::getStoreConfigFlag(self::XML_PATH_ENABLE_QTY_INCREMENTS)
404:             ? (int)Mage::getStoreConfig(self::XML_PATH_QTY_INCREMENTS)
405:             : false;
406:     }
407: 
408:     /**
409:      * Retrieve backorders status
410:      *
411:      * @return int
412:      */
413:     public function getBackorders()
414:     {
415:         if ($this->getUseConfigBackorders()) {
416:             return (int) Mage::getStoreConfig(self::XML_PATH_BACKORDERS);
417:         }
418:         return $this->getData('backorders');
419:     }
420: 
421:     /**
422:      * Retrieve Manage Stock data wrapper
423:      *
424:      * @return int
425:      */
426:     public function getManageStock()
427:     {
428:         if ($this->getUseConfigManageStock()) {
429:             return (int) Mage::getStoreConfigFlag(self::XML_PATH_MANAGE_STOCK);
430:         }
431:         return $this->getData('manage_stock');
432:     }
433: 
434:     /**
435:      * Retrieve can Back in stock
436:      *
437:      * @return bool
438:      */
439:     public function getCanBackInStock()
440:     {
441:         return Mage::getStoreConfigFlag(self::XML_PATH_CAN_BACK_IN_STOCK);
442:     }
443: 
444:     /**
445:      * Check quantity
446:      *
447:      * @param   decimal $qty
448:      * @exception Mage_Core_Exception
449:      * @return  bool
450:      */
451:     public function checkQty($qty)
452:     {
453:         if (!$this->getManageStock() || Mage::app()->getStore()->isAdmin()) {
454:             return true;
455:         }
456: 
457:         if ($this->getQty() - $this->getMinQty() - $qty < 0) {
458:             switch ($this->getBackorders()) {
459:                 case Mage_CatalogInventory_Model_Stock::BACKORDERS_YES_NONOTIFY:
460:                 case Mage_CatalogInventory_Model_Stock::BACKORDERS_YES_NOTIFY:
461:                     break;
462:                 default:
463:                     return false;
464:                     break;
465:             }
466:         }
467:         return true;
468:     }
469: 
470:     /**
471:      * Returns suggested qty that satisfies qty increments and minQty/maxQty/minSaleQty/maxSaleQty conditions
472:      * or original qty if such value does not exist
473:      *
474:      * @param int|float $qty
475:      * @return int|float
476:      */
477:     public function suggestQty($qty)
478:     {
479:         // We do not manage stock
480:         if ($qty <= 0 || !$this->getManageStock()) {
481:             return $qty;
482:         }
483: 
484:         $qtyIncrements = (int)$this->getQtyIncrements(); // Currently only integer increments supported
485:         if ($qtyIncrements < 2) {
486:             return $qty;
487:         }
488: 
489:         $minQty = max($this->getMinSaleQty(), $qtyIncrements);
490:         $divisibleMin = ceil($minQty / $qtyIncrements) * $qtyIncrements;
491: 
492:         $maxQty = min($this->getQty() - $this->getMinQty(), $this->getMaxSaleQty());
493:         $divisibleMax = floor($maxQty / $qtyIncrements) * $qtyIncrements;
494: 
495:         if ($qty < $minQty || $qty > $maxQty || $divisibleMin > $divisibleMax) {
496:             // Do not perform rounding for qty that does not satisfy min/max conditions to not confuse customer
497:             return $qty;
498:         }
499: 
500:         // Suggest value closest to given qty
501:         $closestDivisibleLeft = floor($qty / $qtyIncrements) * $qtyIncrements;
502:         $closestDivisibleRight = $closestDivisibleLeft + $qtyIncrements;
503:         $acceptableLeft = min(max($divisibleMin, $closestDivisibleLeft), $divisibleMax);
504:         $acceptableRight = max(min($divisibleMax, $closestDivisibleRight), $divisibleMin);
505:         return abs($acceptableLeft - $qty) < abs($acceptableRight - $qty) ? $acceptableLeft : $acceptableRight;
506:     }
507: 
508:     /**
509:      * Checking quote item quantity
510:      *
511:      * Second parameter of this method specifies quantity of this product in whole shopping cart
512:      * which should be checked for stock availability
513:      *
514:      * @param mixed $qty quantity of this item (item qty x parent item qty)
515:      * @param mixed $summaryQty quantity of this product
516:      * @param mixed $origQty original qty of item (not multiplied on parent item qty)
517:      * @return Varien_Object
518:      */
519:     public function checkQuoteItemQty($qty, $summaryQty, $origQty = 0)
520:     {
521:         $result = new Varien_Object();
522:         $result->setHasError(false);
523: 
524:         if (!is_numeric($qty)) {
525:             $qty = Mage::app()->getLocale()->getNumber($qty);
526:         }
527: 
528:         /**
529:          * Check quantity type
530:          */
531:         $result->setItemIsQtyDecimal($this->getIsQtyDecimal());
532: 
533:         if (!$this->getIsQtyDecimal()) {
534:             $result->setHasQtyOptionUpdate(true);
535:             $qty = intval($qty);
536: 
537:             /**
538:               * Adding stock data to quote item
539:               */
540:             $result->setItemQty($qty);
541: 
542:             if (!is_numeric($qty)) {
543:                 $qty = Mage::app()->getLocale()->getNumber($qty);
544:             }
545:             $origQty = intval($origQty);
546:             $result->setOrigQty($origQty);
547:         }
548: 
549:         if ($this->getMinSaleQty() && $qty < $this->getMinSaleQty()) {
550:             $result->setHasError(true)
551:                 ->setMessage(
552:                     Mage::helper('cataloginventory')->__('The minimum quantity allowed for purchase is %s.', $this->getMinSaleQty() * 1)
553:                 )
554:                 ->setErrorCode('qty_min')
555:                 ->setQuoteMessage(Mage::helper('cataloginventory')->__('Some of the products cannot be ordered in requested quantity.'))
556:                 ->setQuoteMessageIndex('qty');
557:             return $result;
558:         }
559: 
560:         if ($this->getMaxSaleQty() && $qty > $this->getMaxSaleQty()) {
561:             $result->setHasError(true)
562:                 ->setMessage(
563:                     Mage::helper('cataloginventory')->__('The maximum quantity allowed for purchase is %s.', $this->getMaxSaleQty() * 1)
564:                 )
565:                 ->setErrorCode('qty_max')
566:                 ->setQuoteMessage(Mage::helper('cataloginventory')->__('Some of the products cannot be ordered in requested quantity.'))
567:                 ->setQuoteMessageIndex('qty');
568:             return $result;
569:         }
570: 
571:         $result->addData($this->checkQtyIncrements($qty)->getData());
572:         if ($result->getHasError()) {
573:             return $result;
574:         }
575: 
576:         if (!$this->getManageStock()) {
577:             return $result;
578:         }
579: 
580:         if (!$this->getIsInStock()) {
581:             $result->setHasError(true)
582:                 ->setMessage(Mage::helper('cataloginventory')->__('This product is currently out of stock.'))
583:                 ->setQuoteMessage(Mage::helper('cataloginventory')->__('Some of the products are currently out of stock'))
584:                 ->setQuoteMessageIndex('stock');
585:             $result->setItemUseOldQty(true);
586:             return $result;
587:         }
588: 
589:         if (!$this->checkQty($summaryQty) || !$this->checkQty($qty)) {
590:             $message = Mage::helper('cataloginventory')->__('The requested quantity for "%s" is not available.', $this->getProductName());
591:             $result->setHasError(true)
592:                 ->setMessage($message)
593:                 ->setQuoteMessage($message)
594:                 ->setQuoteMessageIndex('qty');
595:             return $result;
596:         } else {
597:             if (($this->getQty() - $summaryQty) < 0) {
598:                 if ($this->getProductName()) {
599:                     if ($this->getIsChildItem()) {
600:                         $backorderQty = ($this->getQty() > 0) ? ($summaryQty - $this->getQty()) * 1 : $qty * 1;
601:                         if ($backorderQty > $qty) {
602:                             $backorderQty = $qty;
603:                         }
604: 
605:                         $result->setItemBackorders($backorderQty);
606:                     } else {
607:                         $orderedItems = $this->getOrderedItems();
608:                         $itemsLeft = ($this->getQty() > $orderedItems) ? ($this->getQty() - $orderedItems) * 1 : 0;
609:                         $backorderQty = ($itemsLeft > 0) ? ($qty - $itemsLeft) * 1 : $qty * 1;
610: 
611:                         if ($backorderQty > 0) {
612:                             $result->setItemBackorders($backorderQty);
613:                         }
614:                         $this->setOrderedItems($orderedItems + $qty);
615:                     }
616: 
617:                     if ($this->getBackorders() == Mage_CatalogInventory_Model_Stock::BACKORDERS_YES_NOTIFY) {
618:                         if (!$this->getIsChildItem()) {
619:                             $result->setMessage(
620:                                 Mage::helper('cataloginventory')->__('This product is not available in the requested quantity. %s of the items will be backordered.', ($backorderQty * 1))
621:                             );
622:                         } else {
623:                             $result->setMessage(
624:                                Mage::helper('cataloginventory')->__('"%s" is not available in the requested quantity. %s of the items will be backordered.', $this->getProductName(), ($backorderQty * 1))
625:                             );
626:                         }
627:                     } elseif (Mage::app()->getStore()->isAdmin()) {
628:                         $result->setMessage(
629:                             Mage::helper('cataloginventory')->__('The requested quantity for "%s" is not available.', $this->getProductName())
630:                         );
631:                     }
632:                 }
633:             } else {
634:                 if (!$this->getIsChildItem()) {
635:                     $this->setOrderedItems($qty + (int)$this->getOrderedItems());
636:                 }
637:             }
638:         }
639: 
640:         return $result;
641:     }
642: 
643:     /**
644:      * Check qty increments
645:      *
646:      * @param int|float $qty
647:      * @return Varien_Object
648:      */
649:     public function checkQtyIncrements($qty)
650:     {
651:         $result = new Varien_Object();
652:         if ($this->getSuppressCheckQtyIncrements()) {
653:             return $result;
654:         }
655: 
656:         $qtyIncrements = $this->getQtyIncrements();
657:         if ($qtyIncrements && (Mage::helper('core')->getExactDivision($qty, $qtyIncrements) != 0)) {
658:             $result->setHasError(true)
659:                 ->setQuoteMessage(
660:                     Mage::helper('cataloginventory')->__('Some of the products cannot be ordered in the requested quantity.')
661:                 )
662:                 ->setErrorCode('qty_increments')
663:                 ->setQuoteMessageIndex('qty');
664:             if ($this->getIsChildItem()) {
665:                 $result->setMessage(
666:                     Mage::helper('cataloginventory')->__('%s is available for purchase in increments of %s only.',$this->getProductName(), $qtyIncrements * 1)
667:                 );
668:             } else {
669:                 $result->setMessage(
670:                     Mage::helper('cataloginventory')->__('This product is available for purchase in increments of %s only.', $qtyIncrements * 1)
671:                 );
672:             }
673:         }
674: 
675:         return $result;
676:     }
677: 
678:     /**
679:      * Add join for catalog in stock field to product collection
680:      *
681:      * @param Mage_Catalog_Model_Entity_Product_Collection $productCollection
682:      * @return Mage_CatalogInventory_Model_Stock_Item
683:      */
684:     public function addCatalogInventoryToProductCollection($productCollection)
685:     {
686:         $this->_getResource()->addCatalogInventoryToProductCollection($productCollection);
687:         return $this;
688:     }
689: 
690:     /**
691:      * Add error to Quote Item
692:      *
693:      * @param Mage_Sales_Model_Quote_Item $item
694:      * @param string $itemError
695:      * @param string $quoteError
696:      * @param string $errorIndex
697:      * @return Mage_CatalogInventory_Model_Stock_Item
698:      */
699:     protected function _addQuoteItemError(Mage_Sales_Model_Quote_Item $item, $itemError,
700:         $quoteError, $errorIndex='error'
701:     ) {
702:         $item->setHasError(true);
703:         $item->setMessage($itemError);
704:         $item->setQuoteMessage($quoteError);
705:         $item->setQuoteMessageIndex($errorIndex);
706:         return $this;
707:     }
708: 
709:     /**
710:      * Before save prepare process
711:      *
712:      * @return Mage_CatalogInventory_Model_Stock_Item
713:      */
714:     protected function _beforeSave()
715:     {
716:         // see if quantity is defined for this item type
717:         $typeId = $this->getTypeId();
718:         if ($productTypeId = $this->getProductTypeId()) {
719:             $typeId = $productTypeId;
720:         }
721: 
722:         $isQty = Mage::helper('catalogInventory')->isQty($typeId);
723: 
724:         if ($isQty) {
725:             if (!$this->verifyStock()) {
726:                 $this->setIsInStock(false)
727:                     ->setStockStatusChangedAutomaticallyFlag(true);
728:             }
729: 
730:             // if qty is below notify qty, update the low stock date to today date otherwise set null
731:             $this->setLowStockDate(null);
732:             if ($this->verifyNotification()) {
733:                 $this->setLowStockDate(Mage::app()->getLocale()->date(null, null, null, false)
734:                     ->toString(Varien_Date::DATETIME_INTERNAL_FORMAT)
735:                 );
736:             }
737: 
738:             $this->setStockStatusChangedAutomatically(0);
739:             if ($this->hasStockStatusChangedAutomaticallyFlag()) {
740:                 $this->setStockStatusChangedAutomatically((int)$this->getStockStatusChangedAutomaticallyFlag());
741:             }
742:         } else {
743:             $this->setQty(0);
744:         }
745: 
746:         return $this;
747:     }
748: 
749:     /**
750:      * Chceck if item should be in stock or out of stock based on $qty param of existing item qty
751:      *
752:      * @param float|null $qty
753:      * @return bool true - item in stock | false - item out of stock
754:      */
755:     public function verifyStock($qty = null)
756:     {
757:         if ($qty === null) {
758:             $qty = $this->getQty();
759:         }
760:         if ($this->getBackorders() == Mage_CatalogInventory_Model_Stock::BACKORDERS_NO && $qty <= $this->getMinQty()) {
761:             return false;
762:         }
763:         return true;
764:     }
765: 
766:     /**
767:      * Check if item qty require stock status notification
768:      *
769:      * @param float | null $qty
770:      * @return bool (true - if require, false - if not require)
771:      */
772:     public function verifyNotification($qty = null)
773:     {
774:         if ($qty === null) {
775:             $qty = $this->getQty();
776:         }
777:         return (float)$qty < $this->getNotifyStockQty();
778:     }
779: 
780:     /**
781:      * Reindex CatalogInventory save event
782:      *
783:      * @return Mage_CatalogInventory_Model_Stock_Item
784:      */
785:     protected function _afterSave()
786:     {
787:         parent::_afterSave();
788: 
789:         /** @var $indexer Mage_Index_Model_Indexer */
790:         $indexer = Mage::getSingleton('index/indexer');
791:         if ($this->_processIndexEvents) {
792:             $indexer->processEntityAction($this, self::ENTITY, Mage_Index_Model_Event::TYPE_SAVE);
793:         } else {
794:             $indexer->logEvent($this, self::ENTITY, Mage_Index_Model_Event::TYPE_SAVE);
795:         }
796:         return $this;
797:     }
798: 
799: 
800:     /**
801:      * Retrieve Stock Availability
802:      *
803:      * @return bool|int
804:      */
805:     public function getIsInStock()
806:     {
807:         if (!$this->getManageStock()) {
808:             return true;
809:         }
810:         return $this->_getData('is_in_stock');
811:     }
812: 
813:     /**
814:      * Add product data to stock item
815:      *
816:      * @param Mage_Catalog_Model_Product $product
817:      * @return Mage_CatalogInventory_Model_Stock_Item
818:      */
819:     public function setProduct($product)
820:     {
821:         $this->setProductId($product->getId())
822:             ->setProductName($product->getName())
823:             ->setStoreId($product->getStoreId())
824:             ->setProductName($product->getName())
825:             ->setProductTypeId($product->getTypeId())
826:             ->setProductStatusChanged($product->dataHasChangedFor('status'))
827:             ->setProductChangedWebsites($product->getIsChangedWebsites());
828: 
829:         $this->_productInstance = $product;
830: 
831:         return $this;
832:     }
833: 
834:     /**
835:      * Returns product instance
836:      *
837:      * @return Mage_Catalog_Model_Product|null
838:      */
839:     public function getProduct()
840:     {
841:         return $this->_productInstance ? $this->_productInstance : $this->_getData('product');
842:     }
843: 
844:     /**
845:      * Retrieve stock qty whether product is composite or no
846:      *
847:      * @return float
848:      */
849:     public function getStockQty()
850:     {
851:         if (!$this->hasStockQty()) {
852:             $this->setStockQty(0);  // prevent possible recursive loop
853:             $product = $this->_productInstance;
854:             if (!$product || !$product->isComposite()) {
855:                 $stockQty = $this->getQty();
856:             } else {
857:                 $stockQty = null;
858:                 $productsByGroups = $product->getTypeInstance(true)->getProductsToPurchaseByReqGroups($product);
859:                 foreach ($productsByGroups as $productsInGroup) {
860:                     $qty = 0;
861:                     foreach ($productsInGroup as $childProduct) {
862:                         if ($childProduct->hasStockItem()) {
863:                             $qty += $childProduct->getStockItem()->getStockQty();
864:                         }
865:                     }
866:                     if (is_null($stockQty) || $qty < $stockQty) {
867:                         $stockQty = $qty;
868:                     }
869:                 }
870:             }
871:             $stockQty = (float) $stockQty;
872:             if ($stockQty < 0 || !$this->getManageStock()
873:                 || !$this->getIsInStock() || ($product && !$product->isSaleable())
874:             ) {
875:                 $stockQty = 0;
876:             }
877:             $this->setStockQty($stockQty);
878:         }
879:         return $this->getData('stock_qty');
880:     }
881: 
882:     /**
883:      * Reset model data
884:      * @return Mage_CatalogInventory_Model_Stock_Item
885:      */
886:     public function reset()
887:     {
888:         if ($this->_productInstance) {
889:             $this->_productInstance = null;
890:         }
891:         return $this;
892:     }
893: 
894:     /**
895:      * Set whether index events should be processed immediately
896:      *
897:      * @param bool $process
898:      * @return Mage_CatalogInventory_Model_Stock_Item
899:      */
900:     public function setProcessIndexEvents($process = true)
901:     {
902:         $this->_processIndexEvents = $process;
903:         return $this;
904:     }
905: }
906: 
Magento 1.7.0.2 API documentation generated by ApiGen 2.8.0