1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46:
47: class Mage_CatalogInventory_Model_Stock_Status extends Mage_Core_Model_Abstract
48: {
49: const STATUS_OUT_OF_STOCK = 0;
50: const STATUS_IN_STOCK = 1;
51:
52: 53: 54: 55: 56:
57: protected $_productTypes;
58:
59: 60: 61: 62: 63:
64: protected $_websites;
65:
66: 67: 68: 69:
70: protected function _construct()
71: {
72: $this->_init('cataloginventory/stock_status');
73: }
74:
75: 76: 77: 78: 79: 80:
81: public function getProductTypeInstances()
82: {
83: if (is_null($this->_productTypes)) {
84: $this->_productTypes = array();
85: $productEmulator = new Varien_Object();
86:
87: foreach (array_keys(Mage_Catalog_Model_Product_Type::getTypes()) as $typeId) {
88: $productEmulator->setTypeId($typeId);
89: $this->_productTypes[$typeId] = Mage::getSingleton('catalog/product_type')
90: ->factory($productEmulator);
91: }
92: }
93: return $this->_productTypes;
94: }
95:
96: 97: 98: 99: 100: 101:
102: public function getProductTypeInstance($productType)
103: {
104: $types = $this->getProductTypeInstances();
105: if (isset($types[$productType])) {
106: return $types[$productType];
107: }
108: return false;
109: }
110:
111: 112: 113: 114: 115:
116: public function getWebsites($websiteId = null)
117: {
118: if (is_null($this->_websites)) {
119: $this->_websites = $this->getResource()->getWebsiteStores();
120: }
121:
122: $websites = $this->_websites;
123: if (!is_null($websiteId) && isset($this->_websites[$websiteId])) {
124: $websites = array($websiteId => $this->_websites[$websiteId]);
125: }
126:
127: return $websites;
128: }
129:
130: 131: 132: 133: 134: 135:
136: public function getWebsiteDefaultStoreId($websiteId)
137: {
138: $websites = $this->getWebsites();
139: if (isset($websites[$websiteId])) {
140: return $websites[$websiteId];
141: }
142: return 0;
143: }
144:
145: 146: 147: 148: 149:
150: public function getProductStatusModel()
151: {
152: return Mage::getSingleton('catalog/product_status');
153: }
154:
155: 156: 157: 158: 159:
160: public function getStockItemModel()
161: {
162: return Mage::getModel('cataloginventory/stock_item');
163: }
164:
165: 166: 167: 168: 169:
170: public function getProductStatusEnabled()
171: {
172: return Mage_Catalog_Model_Product_Status::STATUS_ENABLED;
173: }
174:
175: 176: 177: 178: 179: 180:
181: public function changeItemStatus(Mage_CatalogInventory_Model_Stock_Item $item)
182: {
183: $productId = $item->getProductId();
184: if (!$productType = $item->getProductTypeId()) {
185: $productType = $this->getProductType($productId);
186: }
187:
188: $status = (int)$item->getIsInStock();
189: $qty = (int)$item->getQty();
190:
191: $this->_processChildren($productId, $productType, $qty, $status, $item->getStockId());
192: $this->_processParents($productId, $item->getStockId());
193:
194: return $this;
195: }
196:
197: 198: 199: 200: 201: 202: 203: 204:
205: public function assignProduct(Mage_Catalog_Model_Product $product, $stockId = 1, $stockStatus = null)
206: {
207: if (is_null($stockStatus)) {
208: $websiteId = $product->getStore()->getWebsiteId();
209: $status = $this->getProductStatus($product->getId(), $websiteId, $stockId);
210: $stockStatus = isset($status[$product->getId()]) ? $status[$product->getId()] : null;
211: }
212:
213: $product->setIsSalable($stockStatus);
214:
215: return $this;
216: }
217:
218: 219: 220: 221: 222: 223:
224: public function rebuild($websiteId = null)
225: {
226: $lastProductId = 0;
227: while (true) {
228: $productCollection = $this->getResource()->getProductCollection($lastProductId);
229: if (!$productCollection) {
230: break;
231: }
232:
233: foreach ($productCollection as $productId => $productType) {
234: $lastProductId = $productId;
235: $this->updateStatus($productId, $productType, $websiteId);
236: }
237: }
238:
239: return $this;
240: }
241:
242: 243: 244: 245: 246: 247: 248: 249:
250: public function updateStatus($productId, $productType = null, $websiteId = null)
251: {
252: if (is_null($productType)) {
253: $productType = $this->getProductType($productId);
254: }
255:
256: $item = $this->getStockItemModel()->loadByProduct($productId);
257:
258: $status = self::STATUS_IN_STOCK;
259: $qty = 0;
260: if ($item->getId()) {
261: $status = $item->getIsInStock();
262: $qty = $item->getQty();
263: }
264:
265: $this->_processChildren($productId, $productType, $qty, $status, $item->getStockId(), $websiteId);
266: $this->_processParents($productId, $item->getStockId(), $websiteId);
267:
268: return $this;
269: }
270:
271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281:
282: protected function _processChildren($productId, $productType, $qty = 0, $status = self::STATUS_IN_STOCK, $stockId = 1, $websiteId = null)
283: {
284: if ($status == self::STATUS_OUT_OF_STOCK) {
285: $this->saveProductStatus($productId, $status, $qty, $stockId, $websiteId);
286: return $this;
287: }
288:
289: $statuses = array();
290: $websites = $this->getWebsites($websiteId);
291:
292: foreach (array_keys($websites) as $websiteId) {
293:
294: $statuses[$websiteId] = $status;
295: }
296:
297: if (!$typeInstance = $this->getProductTypeInstance($productType)) {
298: return $this;
299: }
300:
301: $requiredChildrenIds = $typeInstance->getChildrenIds($productId, true);
302: if ($requiredChildrenIds) {
303: $childrenIds = array();
304: foreach ($requiredChildrenIds as $groupedChildrenIds) {
305: $childrenIds = array_merge($childrenIds, $groupedChildrenIds);
306: }
307: $childrenWebsites = Mage::getSingleton('catalog/product_website')
308: ->getWebsites($childrenIds);
309: foreach ($websites as $websiteId => $storeId) {
310: $childrenStatus = $this->getProductStatusModel()
311: ->getProductStatus($childrenIds, $storeId);
312: $childrenStock = $this->getProductStatus($childrenIds, $websiteId, $stockId);
313:
314: $websiteStatus = $statuses[$websiteId];
315: foreach ($requiredChildrenIds as $groupedChildrenIds) {
316: $optionStatus = false;
317: foreach ($groupedChildrenIds as $childId) {
318: if (isset($childrenStatus[$childId])
319: and isset($childrenWebsites[$childId])
320: and in_array($websiteId, $childrenWebsites[$childId])
321: and $childrenStatus[$childId] == $this->getProductStatusEnabled()
322: and isset($childrenStock[$childId])
323: and $childrenStock[$childId] == self::STATUS_IN_STOCK
324: ) {
325: $optionStatus = true;
326: }
327: }
328: $websiteStatus = $websiteStatus && $optionStatus;
329: }
330: $statuses[$websiteId] = (int)$websiteStatus;
331: }
332: }
333:
334: foreach ($statuses as $websiteId => $websiteStatus) {
335: $this->saveProductStatus($productId, $websiteStatus, $qty, $stockId, $websiteId);
336: }
337:
338: return $this;
339: }
340:
341: 342: 343: 344: 345: 346: 347: 348:
349: protected function _processParents($productId, $stockId = 1, $websiteId = null)
350: {
351: $parentIds = array();
352: foreach ($this->getProductTypeInstances() as $typeInstance) {
353:
354: $parentIds = array_merge($parentIds, $typeInstance->getParentIdsByChild($productId));
355: }
356:
357: if (!$parentIds) {
358: return $this;
359: }
360:
361: $productTypes = $this->getProductsType($parentIds);
362: $item = $this->getStockItemModel();
363:
364: foreach ($parentIds as $parentId) {
365: $parentType = isset($productTypes[$parentId]) ? $productTypes[$parentId] : null;
366: $item->setData(array('stock_id' => $stockId))
367: ->setOrigData()
368: ->loadByProduct($parentId);
369: $status = self::STATUS_IN_STOCK;
370: $qty = 0;
371: if ($item->getId()) {
372: $status = $item->getIsInStock();
373: $qty = $item->getQty();
374: }
375:
376: $this->_processChildren($parentId, $parentType, $qty, $status, $item->getStockId(), $websiteId);
377: }
378:
379: return $this;
380: }
381:
382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392:
393: public function saveProductStatus($productId, $status, $qty = 0, $stockId = 1, $websiteId = null)
394: {
395: $this->getResource()->saveProductStatus($this, $productId, $status, $qty, $stockId, $websiteId);
396: return $this;
397: }
398:
399: 400: 401: 402: 403: 404: 405: 406:
407: public function getProductStatus($productIds, $websiteId, $stockId = 1)
408: {
409: return $this->getResource()->getProductStatus($productIds, $websiteId, $stockId);
410: }
411:
412: 413: 414: 415: 416: 417: 418: 419:
420: public function getProductData($productIds, $websiteId, $stockId = 1)
421: {
422: return $this->getResource()->getProductData($productIds, $websiteId, $stockId);
423: }
424:
425: 426: 427: 428: 429: 430:
431: public function getProductType($productId)
432: {
433: $types = $this->getResource()->getProductsType($productId);
434: if (isset($types[$productId])) {
435: return $types[$productId];
436: }
437: return false;
438: }
439:
440: 441: 442: 443: 444: 445: 446:
447: public function getProductsType($productIds)
448: {
449: return $this->getResource()->getProductsType($productIds);
450: }
451:
452: 453: 454: 455: 456: 457: 458: 459:
460: public function addStockStatusToProducts($productCollection, $websiteId = null, $stockId = null)
461: {
462: if ($stockId === null) {
463: $stockId = Mage_CatalogInventory_Model_Stock::DEFAULT_STOCK_ID;
464: }
465: if ($websiteId === null) {
466: $websiteId = Mage::app()->getStore()->getWebsiteId();
467: if ((int)$websiteId == 0 && $productCollection->getStoreId()) {
468: $websiteId = Mage::app()->getStore($productCollection->getStoreId())->getWebsiteId();
469: }
470: }
471: $productIds = array();
472: foreach ($productCollection as $product) {
473: $productIds[] = $product->getId();
474: }
475:
476: if (!empty($productIds)) {
477: $stockStatuses = $this->_getResource()->getProductStatus($productIds, $websiteId, $stockId);
478: foreach ($stockStatuses as $productId => $status) {
479: if ($product = $productCollection->getItemById($productId)) {
480: $product->setIsSalable($status);
481: }
482: }
483: }
484:
485:
486: foreach ($productCollection as $product) {
487: $object = new Varien_Object(array('is_in_stock' => $product->getData('is_salable')));
488: $product->setStockItem($object);
489: }
490:
491: return $this;
492: }
493:
494: 495: 496: 497: 498: 499: 500:
501: public function addStockStatusToSelect(Varien_Db_Select $select, Mage_Core_Model_Website $website)
502: {
503: $this->_getResource()->addStockStatusToSelect($select, $website);
504: return $this;
505: }
506:
507: 508: 509: 510: 511: 512: 513: 514:
515: public function prepareCatalogProductIndexSelect(Varien_Db_Select $select, $entityField, $websiteField)
516: {
517: if (Mage::helper('cataloginventory')->isShowOutOfStock()) {
518: return $this;
519: }
520:
521: $this->_getResource()->prepareCatalogProductIndexSelect($select, $entityField, $websiteField);
522:
523: return $this;
524: }
525:
526: 527: 528: 529: 530: 531:
532: public function addIsInStockFilterToCollection($collection)
533: {
534: $this->_getResource()->addIsInStockFilterToCollection($collection);
535: return $this;
536: }
537: }
538: