Пример #1
0
 /**
  * Initialize item option
  *
  * @param \Magento\Quote\Model\Quote\Item\Option $option
  * @param \Magento\Quote\Model\Quote\Item $quoteItem
  * @param int $qty
  *
  * @return \Magento\Framework\Object
  * @throws \Magento\Framework\Exception\LocalizedException
  */
 public function initialize(\Magento\Quote\Model\Quote\Item\Option $option, \Magento\Quote\Model\Quote\Item $quoteItem, $qty)
 {
     $optionValue = $option->getValue();
     $optionQty = $qty * $optionValue;
     $increaseOptionQty = ($quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty) * $optionValue;
     $qtyForCheck = $this->quoteItemQtyList->getQty($option->getProduct()->getId(), $quoteItem->getId(), $quoteItem->getQuoteId(), $increaseOptionQty);
     $stockItem = $this->getStockItem($option, $quoteItem);
     $result = $this->stockState->checkQuoteItemQty($option->getProduct()->getId(), $optionQty, $qtyForCheck, $optionValue, $option->getProduct()->getStore()->getWebsiteId());
     if ($result->getItemIsQtyDecimal() !== null) {
         $option->setIsQtyDecimal($result->getItemIsQtyDecimal());
     }
     if ($result->getHasQtyOptionUpdate()) {
         $option->setHasQtyOptionUpdate(true);
         $quoteItem->updateQtyOption($option, $result->getOrigQty());
         $option->setValue($result->getOrigQty());
         /**
          * if option's qty was updates we also need to update quote item qty
          */
         $quoteItem->setData('qty', intval($qty));
     }
     if ($result->getMessage() !== null) {
         $option->setMessage($result->getMessage());
         $quoteItem->setMessage($result->getMessage());
     }
     if ($result->getItemBackorders() !== null) {
         $option->setBackorders($result->getItemBackorders());
     }
     $stockItem->unsIsChildItem();
     return $result;
 }
Пример #2
0
 /**
  * Initialize stock item
  *
  * @param \Magento\CatalogInventory\Api\Data\StockItemInterface $stockItem
  * @param \Magento\Quote\Model\Quote\Item $quoteItem
  * @param int $qty
  *
  * @return \Magento\Framework\DataObject
  * @throws \Magento\Framework\Exception\LocalizedException
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  * @SuppressWarnings(PHPMD.NPathComplexity)
  */
 public function initialize(\Magento\CatalogInventory\Api\Data\StockItemInterface $stockItem, \Magento\Quote\Model\Quote\Item $quoteItem, $qty)
 {
     /**
      * When we work with subitem
      */
     if ($quoteItem->getParentItem()) {
         $rowQty = $quoteItem->getParentItem()->getQty() * $qty;
         /**
          * we are using 0 because original qty was processed
          */
         $qtyForCheck = $this->quoteItemQtyList->getQty($quoteItem->getProduct()->getId(), $quoteItem->getId(), $quoteItem->getQuoteId(), 0);
     } else {
         $increaseQty = $quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty;
         $rowQty = $qty;
         $qtyForCheck = $this->quoteItemQtyList->getQty($quoteItem->getProduct()->getId(), $quoteItem->getId(), $quoteItem->getQuoteId(), $increaseQty);
     }
     $productTypeCustomOption = $quoteItem->getProduct()->getCustomOption('product_type');
     if ($productTypeCustomOption !== null) {
         // Check if product related to current item is a part of product that represents product set
         if ($this->typeConfig->isProductSet($productTypeCustomOption->getValue())) {
             $stockItem->setIsChildItem(true);
         }
     }
     $stockItem->setProductName($quoteItem->getProduct()->getName());
     $result = $this->stockState->checkQuoteItemQty($quoteItem->getProduct()->getId(), $rowQty, $qtyForCheck, $qty, $quoteItem->getProduct()->getStore()->getWebsiteId());
     if ($stockItem->hasIsChildItem()) {
         $stockItem->unsIsChildItem();
     }
     if ($result->getItemIsQtyDecimal() !== null) {
         $quoteItem->setIsQtyDecimal($result->getItemIsQtyDecimal());
         if ($quoteItem->getParentItem()) {
             $quoteItem->getParentItem()->setIsQtyDecimal($result->getItemIsQtyDecimal());
         }
     }
     /**
      * Just base (parent) item qty can be changed
      * qty of child products are declared just during add process
      * exception for updating also managed by product type
      */
     if ($result->getHasQtyOptionUpdate() && (!$quoteItem->getParentItem() || $quoteItem->getParentItem()->getProduct()->getTypeInstance()->getForceChildItemQtyChanges($quoteItem->getParentItem()->getProduct()))) {
         $quoteItem->setData('qty', $result->getOrigQty());
     }
     if ($result->getItemUseOldQty() !== null) {
         $quoteItem->setUseOldQty($result->getItemUseOldQty());
     }
     if ($result->getMessage() !== null) {
         $quoteItem->setMessage($result->getMessage());
     }
     if ($result->getItemBackorders() !== null) {
         $quoteItem->setBackorders($result->getItemBackorders());
     }
     return $result;
 }
Пример #3
0
 /**
  * Get items
  *
  * @return Item[]
  */
 public function getItems()
 {
     $items = $this->getParentBlock()->getItems();
     $oldSuperMode = $this->getQuote()->getIsSuperMode();
     $this->getQuote()->setIsSuperMode(false);
     foreach ($items as $item) {
         // To dispatch inventory event sales_quote_item_qty_set_after, set item qty
         $item->setQty($item->getQty());
         if (!$item->getMessage()) {
             //Getting product ids for stock item last quantity validation before grid display
             $stockItemToCheck = [];
             $childItems = $item->getChildren();
             if (count($childItems)) {
                 foreach ($childItems as $childItem) {
                     $stockItemToCheck[] = $childItem->getProduct()->getId();
                 }
             } else {
                 $stockItemToCheck[] = $item->getProduct()->getId();
             }
             foreach ($stockItemToCheck as $productId) {
                 $check = $this->stockState->checkQuoteItemQty($productId, $item->getQty(), $item->getQty(), $item->getQty(), $this->getQuote()->getStore()->getWebsiteId());
                 $item->setMessage($check->getMessage());
                 $item->setHasError($check->getHasError());
             }
         }
         if ($item->getProduct()->getStatus() == ProductStatus::STATUS_DISABLED) {
             $item->setMessage(__('This product is disabled.'));
             $item->setHasError(true);
         }
     }
     $this->getQuote()->setIsSuperMode($oldSuperMode);
     return $items;
 }
Пример #4
0
 public function testInitializeWhenResultNotDecimalGetBackordersMessageHasOptionQtyUpdate()
 {
     $optionValue = 5;
     $qtyForCheck = 50;
     $qty = 10;
     $this->optionMock->expects($this->once())->method('getValue')->will($this->returnValue($optionValue));
     $this->quoteItemMock->expects($this->once())->method('getQtyToAdd')->will($this->returnValue(false));
     $this->optionMock->expects($this->any())->method('getProduct')->will($this->returnValue($this->productMock));
     $this->stockItemMock->expects($this->once())->method('setIsChildItem')->with(true);
     $this->stockItemMock->expects($this->once())->method('setSuppressCheckQtyIncrements')->with(true);
     $this->stockItemMock->expects($this->once())->method('getItemId')->will($this->returnValue(true));
     $this->stockRegistry->expects($this->once())->method('getStockItem')->will($this->returnValue($this->stockItemMock));
     $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($this->productId));
     $this->quoteItemMock->expects($this->any())->method('getId')->will($this->returnValue('quote_item_id'));
     $this->quoteItemMock->expects($this->once())->method('getQuoteId')->will($this->returnValue('quote_id'));
     $this->qtyItemListMock->expects($this->once())->method('getQty')->with($this->productId, 'quote_item_id', 'quote_id', $qty * $optionValue)->will($this->returnValue($qtyForCheck));
     $this->stockState->expects($this->once())->method('checkQuoteItemQty')->with($this->productId, $qty * $optionValue, $qtyForCheck, $optionValue, $this->websiteId)->will($this->returnValue($this->resultMock));
     $this->resultMock->expects($this->once())->method('getItemIsQtyDecimal')->will($this->returnValue(null));
     $this->optionMock->expects($this->never())->method('setIsQtyDecimal');
     $this->resultMock->expects($this->once())->method('getHasQtyOptionUpdate')->will($this->returnValue(null));
     $this->optionMock->expects($this->never())->method('setHasQtyOptionUpdate');
     $this->resultMock->expects($this->once())->method('getMessage')->will($this->returnValue(null));
     $this->resultMock->expects($this->once())->method('getItemBackorders')->will($this->returnValue(null));
     $this->optionMock->expects($this->never())->method('setBackorders');
     $this->stockItemMock->expects($this->once())->method('unsIsChildItem');
     $this->validator->initialize($this->optionMock, $this->quoteItemMock, $qty);
 }
Пример #5
0
 public function testIsSalableNoManageStock()
 {
     $option1 = $this->getRequiredOptionMock(10, 10);
     $option2 = $this->getRequiredOptionMock(20, 10);
     $stockItem = $this->getStockItem(true);
     $this->stockRegistry->method('getStockItem')->willReturn($stockItem);
     $this->stockState->expects($this->at(0))->method('getStockQty')->with(10)->willReturn(10);
     $this->stockState->expects($this->at(1))->method('getStockQty')->with(20)->willReturn(10);
     $optionCollectionMock = $this->getOptionCollectionMock([$option1, $option2]);
     $selectionCollectionMock = $this->getSelectionCollectionMock([$option1, $option2]);
     $product = new \Magento\Framework\Object(['is_salable' => true, '_cache_instance_options_collection' => $optionCollectionMock, 'status' => \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED, '_cache_instance_selections_collection10_20' => $selectionCollectionMock]);
     $this->assertTrue($this->model->isSalable($product));
 }
Пример #6
0
 public function te1stGetStockQtyLeft()
 {
     $productId = 1;
     $minQty = 0;
     $websiteId = 1;
     $stockQty = 2;
     $storeMock = $this->getMockBuilder('Magento\\Store\\Model\\Store')->disableOriginalConstructor()->getMock();
     $storeMock->expects($this->once())->method('getWebsiteId')->willReturn($websiteId);
     $product = $this->getMock('Magento\\Catalog\\Model\\Product', [], [], '', false);
     $product->expects($this->any())->method('getId')->willReturn($productId);
     $product->expects($this->once())->method('getStore')->willReturn($storeMock);
     $this->registryMock->expects($this->once())->method('registry')->with('current_product')->will($this->returnValue($product));
     $stockItemMock = $this->getMockBuilder('Magento\\CatalogInventory\\Api\\Data\\StockItemInterface')->disableOriginalConstructor()->getMock();
     $stockItemMock->expects($this->once())->method('getMinQty')->willReturn($minQty);
     $this->stockRegistryMock->expects($this->once())->method('getStockItem')->with($productId)->willReturn($stockItemMock);
     $this->stockState->expects($this->once())->method('getStockQty')->with($productId, $storeMock)->willReturn($stockQty);
     $this->assertEquals($stockQty, $this->block->getStockQtyLeft());
 }
Пример #7
0
 /**
  * Returns suggested quantities for items.
  * Can be used to automatically fix user entered quantities before updating cart
  * so that cart contains valid qty values
  *
  * The $data is an array of ($quoteItemId => (item info array with 'qty' key), ...)
  *
  * @param   array $data
  * @return  array
  */
 public function suggestItemsQty($data)
 {
     foreach ($data as $itemId => $itemInfo) {
         if (!isset($itemInfo['qty'])) {
             continue;
         }
         $qty = (double) $itemInfo['qty'];
         if ($qty <= 0) {
             continue;
         }
         $quoteItem = $this->getQuote()->getItemById($itemId);
         if (!$quoteItem) {
             continue;
         }
         $product = $quoteItem->getProduct();
         if (!$product) {
             continue;
         }
         $data[$itemId]['before_suggest_qty'] = $qty;
         $data[$itemId]['qty'] = $this->stockState->suggestQty($product->getId(), $qty, $product->getStore()->getWebsiteId());
     }
     return $data;
 }
Пример #8
0
 /**
  * Retrieve product stock qty
  *
  * @param Product $product
  * @return float
  */
 public function getProductStockQty($product)
 {
     return $this->stockState->getStockQty($product->getId(), $product->getStore()->getWebsiteId());
 }
Пример #9
0
 /**
  * Checking if we can sale this bundle
  *
  * @param \Magento\Catalog\Model\Product $product
  * @return bool
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  * @SuppressWarnings(PHPMD.NPathComplexity)
  */
 public function isSalable($product)
 {
     if (!parent::isSalable($product)) {
         return false;
     }
     if ($product->hasData('all_items_salable')) {
         return $product->getData('all_items_salable');
     }
     $optionCollection = $this->getOptionsCollection($product);
     if (!count($optionCollection->getItems())) {
         return false;
     }
     $requiredOptionIds = [];
     foreach ($optionCollection->getItems() as $option) {
         if ($option->getRequired()) {
             $requiredOptionIds[$option->getId()] = 0;
         }
     }
     $selectionCollection = $this->getSelectionsCollection($optionCollection->getAllIds(), $product);
     if (!count($selectionCollection->getItems())) {
         return false;
     }
     $salableSelectionCount = 0;
     foreach ($selectionCollection as $selection) {
         /* @var $selection \Magento\Catalog\Model\Product */
         if ($selection->isSalable()) {
             $selectionEnoughQty = $this->_stockRegistry->getStockItem($selection->getId())->getManageStock() ? $selection->getSelectionQty() <= $this->_stockState->getStockQty($selection->getId()) : $selection->isInStock();
             if (!$selection->hasSelectionQty() || $selection->getSelectionCanChangeQty() || $selectionEnoughQty) {
                 $requiredOptionIds[$selection->getOptionId()] = 1;
                 $salableSelectionCount++;
             }
         }
     }
     $isSalable = array_sum($requiredOptionIds) == count($requiredOptionIds) && $salableSelectionCount;
     $product->setData('all_items_salable', $isSalable);
     return $isSalable;
 }
Пример #10
0
 /**
  * Check product inventory data when quote item quantity declaring
  *
  * @param \Magento\Framework\Event\Observer $observer
  *
  * @return void
  * @throws \Magento\Framework\Exception\LocalizedException
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  * @SuppressWarnings(PHPMD.NPathComplexity)
  * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  */
 public function validate(\Magento\Framework\Event\Observer $observer)
 {
     /* @var $quoteItem \Magento\Quote\Model\Quote\Item */
     $quoteItem = $observer->getEvent()->getItem();
     if (!$quoteItem || !$quoteItem->getProductId() || !$quoteItem->getQuote() || $quoteItem->getQuote()->getIsSuperMode()) {
         return;
     }
     $qty = $quoteItem->getQty();
     /** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
     $stockItem = $this->stockRegistry->getStockItem($quoteItem->getProduct()->getId(), $quoteItem->getProduct()->getStore()->getWebsiteId());
     /* @var $stockItem \Magento\CatalogInventory\Api\Data\StockItemInterface */
     if (!$stockItem instanceof \Magento\CatalogInventory\Api\Data\StockItemInterface) {
         throw new \Magento\Framework\Exception\LocalizedException(__('The stock item for Product is not valid.'));
     }
     $parentStockItem = false;
     /**
      * Check if product in stock. For composite products check base (parent) item stock status
      */
     if ($quoteItem->getParentItem()) {
         $product = $quoteItem->getParentItem()->getProduct();
         $parentStockItem = $this->stockRegistry->getStockItem($product->getId(), $product->getStore()->getWebsiteId());
     }
     if ($stockItem) {
         if (!$stockItem->getIsInStock() || $parentStockItem && !$parentStockItem->getIsInStock()) {
             $quoteItem->addErrorInfo('cataloginventory', \Magento\CatalogInventory\Helper\Data::ERROR_QTY, __('This product is out of stock.'));
             $quoteItem->getQuote()->addErrorInfo('stock', 'cataloginventory', \Magento\CatalogInventory\Helper\Data::ERROR_QTY, __('Some of the products are out of stock.'));
             return;
         } else {
             // Delete error from item and its quote, if it was set due to item out of stock
             $this->_removeErrorsFromQuoteAndItem($quoteItem, \Magento\CatalogInventory\Helper\Data::ERROR_QTY);
         }
     }
     /**
      * Check item for options
      */
     if (($options = $quoteItem->getQtyOptions()) && $qty > 0) {
         $qty = $quoteItem->getProduct()->getTypeInstance()->prepareQuoteItemQty($qty, $quoteItem->getProduct());
         $quoteItem->setData('qty', $qty);
         if ($stockItem) {
             $result = $this->stockState->checkQtyIncrements($quoteItem->getProduct()->getId(), $qty, $quoteItem->getProduct()->getStore()->getWebsiteId());
             if ($result->getHasError()) {
                 $quoteItem->addErrorInfo('cataloginventory', \Magento\CatalogInventory\Helper\Data::ERROR_QTY_INCREMENTS, $result->getMessage());
                 $quoteItem->getQuote()->addErrorInfo($result->getQuoteMessageIndex(), 'cataloginventory', \Magento\CatalogInventory\Helper\Data::ERROR_QTY_INCREMENTS, $result->getQuoteMessage());
             } else {
                 // Delete error from item and its quote, if it was set due to qty problems
                 $this->_removeErrorsFromQuoteAndItem($quoteItem, \Magento\CatalogInventory\Helper\Data::ERROR_QTY_INCREMENTS);
             }
         }
         foreach ($options as $option) {
             $result = $this->optionInitializer->initialize($option, $quoteItem, $qty);
             if ($result->getHasError()) {
                 $option->setHasError(true);
                 $quoteItem->addErrorInfo('cataloginventory', \Magento\CatalogInventory\Helper\Data::ERROR_QTY, $result->getMessage());
                 $quoteItem->getQuote()->addErrorInfo($result->getQuoteMessageIndex(), 'cataloginventory', \Magento\CatalogInventory\Helper\Data::ERROR_QTY, $result->getQuoteMessage());
             } else {
                 // Delete error from item and its quote, if it was set due to qty lack
                 $this->_removeErrorsFromQuoteAndItem($quoteItem, \Magento\CatalogInventory\Helper\Data::ERROR_QTY);
             }
         }
     } else {
         $result = $this->stockItemInitializer->initialize($stockItem, $quoteItem, $qty);
         if ($result->getHasError()) {
             $quoteItem->addErrorInfo('cataloginventory', \Magento\CatalogInventory\Helper\Data::ERROR_QTY, $result->getMessage());
             $quoteItem->getQuote()->addErrorInfo($result->getQuoteMessageIndex(), 'cataloginventory', \Magento\CatalogInventory\Helper\Data::ERROR_QTY, $result->getQuoteMessage());
         } else {
             // Delete error from item and its quote, if it was set due to qty lack
             $this->_removeErrorsFromQuoteAndItem($quoteItem, \Magento\CatalogInventory\Helper\Data::ERROR_QTY);
         }
     }
 }
Пример #11
0
 public function testCheckQuoteItemQty()
 {
     $this->assertEquals($this->objectResult, $this->stockState->checkQuoteItemQty($this->productId, $this->qty, $this->qty, $this->qty, $this->websiteId));
 }