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: * Stock model
29: *
30: * @method Mage_CatalogInventory_Model_Resource_Stock _getResource()
31: * @method Mage_CatalogInventory_Model_Resource_Stock getResource()
32: * @method string getStockName()
33: * @method Mage_CatalogInventory_Model_Stock setStockName(string $value)
34: *
35: * @category Mage
36: * @package Mage_CatalogInventory
37: * @author Magento Core Team <core@magentocommerce.com>
38: */
39: class Mage_CatalogInventory_Model_Stock extends Mage_Core_Model_Abstract
40: {
41: const BACKORDERS_NO = 0;
42: const BACKORDERS_YES_NONOTIFY = 1;
43: const BACKORDERS_YES_NOTIFY = 2;
44:
45: /* deprecated */
46: const BACKORDERS_BELOW = 1;
47: const BACKORDERS_YES = 2;
48:
49: const STOCK_OUT_OF_STOCK = 0;
50: const STOCK_IN_STOCK = 1;
51:
52: const DEFAULT_STOCK_ID = 1;
53:
54: protected function _construct()
55: {
56: $this->_init('cataloginventory/stock');
57: }
58:
59: /**
60: * Retrieve stock identifier
61: *
62: * @return int
63: */
64: public function getId()
65: {
66: return self::DEFAULT_STOCK_ID;
67: }
68:
69: /**
70: * Add stock item objects to products
71: *
72: * @param collection $products
73: * @return Mage_CatalogInventory_Model_Stock
74: */
75: public function addItemsToProducts($productCollection)
76: {
77: $items = $this->getItemCollection()
78: ->addProductsFilter($productCollection)
79: ->joinStockStatus($productCollection->getStoreId())
80: ->load();
81: $stockItems = array();
82: foreach ($items as $item) {
83: $stockItems[$item->getProductId()] = $item;
84: }
85: foreach ($productCollection as $product) {
86: if (isset($stockItems[$product->getId()])) {
87: $stockItems[$product->getId()]->assignProduct($product);
88: }
89: }
90: return $this;
91: }
92:
93: /**
94: * Retrieve items collection object with stock filter
95: *
96: * @return unknown
97: */
98: public function getItemCollection()
99: {
100: return Mage::getResourceModel('cataloginventory/stock_item_collection')
101: ->addStockFilter($this->getId());
102: }
103:
104: /**
105: * Prepare array($productId=>$qty) based on array($productId => array('qty'=>$qty, 'item'=>$stockItem))
106: *
107: * @param array $items
108: */
109: protected function _prepareProductQtys($items)
110: {
111: $qtys = array();
112: foreach ($items as $productId => $item) {
113: if (empty($item['item'])) {
114: $stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($productId);
115: } else {
116: $stockItem = $item['item'];
117: }
118: $canSubtractQty = $stockItem->getId() && $stockItem->canSubtractQty();
119: if ($canSubtractQty && Mage::helper('catalogInventory')->isQty($stockItem->getTypeId())) {
120: $qtys[$productId] = $item['qty'];
121: }
122: }
123: return $qtys;
124: }
125:
126: /**
127: * Subtract product qtys from stock.
128: * Return array of items that require full save
129: *
130: * @param array $items
131: * @return array
132: */
133: public function registerProductsSale($items)
134: {
135: $qtys = $this->_prepareProductQtys($items);
136: $item = Mage::getModel('cataloginventory/stock_item');
137: $this->_getResource()->beginTransaction();
138: $stockInfo = $this->_getResource()->getProductsStock($this, array_keys($qtys), true);
139: $fullSaveItems = array();
140: foreach ($stockInfo as $itemInfo) {
141: $item->setData($itemInfo);
142: if (!$item->checkQty($qtys[$item->getProductId()])) {
143: $this->_getResource()->commit();
144: Mage::throwException(Mage::helper('cataloginventory')->__('Not all products are available in the requested quantity'));
145: }
146: $item->subtractQty($qtys[$item->getProductId()]);
147: if (!$item->verifyStock() || $item->verifyNotification()) {
148: $fullSaveItems[] = clone $item;
149: }
150: }
151: $this->_getResource()->correctItemsQty($this, $qtys, '-');
152: $this->_getResource()->commit();
153: return $fullSaveItems;
154: }
155:
156: /**
157: *
158: * @param unknown_type $items
159: */
160: public function revertProductsSale($items)
161: {
162: $qtys = $this->_prepareProductQtys($items);
163: $this->_getResource()->correctItemsQty($this, $qtys, '+');
164: return $this;
165: }
166:
167: /**
168: * Subtract ordered qty for product
169: *
170: * @param Varien_Object $item
171: * @return Mage_CatalogInventory_Model_Stock
172: */
173: public function registerItemSale(Varien_Object $item)
174: {
175: $productId = $item->getProductId();
176: if ($productId) {
177: $stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($productId);
178: if (Mage::helper('catalogInventory')->isQty($stockItem->getTypeId())) {
179: if ($item->getStoreId()) {
180: $stockItem->setStoreId($item->getStoreId());
181: }
182: if ($stockItem->checkQty($item->getQtyOrdered()) || Mage::app()->getStore()->isAdmin()) {
183: $stockItem->subtractQty($item->getQtyOrdered());
184: $stockItem->save();
185: }
186: }
187: }
188: else {
189: Mage::throwException(Mage::helper('cataloginventory')->__('Cannot specify product identifier for the order item.'));
190: }
191: return $this;
192: }
193:
194: /**
195: * Get back to stock (when order is canceled or whatever else)
196: *
197: * @param int $productId
198: * @param numeric $qty
199: * @return Mage_CatalogInventory_Model_Stock
200: */
201: public function backItemQty($productId, $qty)
202: {
203: $stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($productId);
204: if ($stockItem->getId() && Mage::helper('catalogInventory')->isQty($stockItem->getTypeId())) {
205: $stockItem->addQty($qty);
206: if ($stockItem->getCanBackInStock() && $stockItem->getQty() > $stockItem->getMinQty()) {
207: $stockItem->setIsInStock(true)
208: ->setStockStatusChangedAutomaticallyFlag(true);
209: }
210: $stockItem->save();
211: }
212: return $this;
213: }
214:
215: /**
216: * Lock stock items for product ids array
217: *
218: * @param array $productIds
219: * @return Mage_CatalogInventory_Model_Stock
220: */
221: public function lockProductItems($productIds)
222: {
223: $this->_getResource()->lockProductItems($this, $productIds);
224: return $this;
225: }
226:
227: /**
228: * Adds filtering for collection to return only in stock products
229: *
230: * @param Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Link_Product_Collection $collection
231: * @return Mage_CatalogInventory_Model_Stock $this
232: */
233: public function addInStockFilterToCollection($collection)
234: {
235: $this->getResource()->setInStockFilterToCollection($collection);
236: return $this;
237: }
238: }
239: