protected function setUp() { $this->objectManagerHelper = new ObjectManagerHelper($this); $this->mathDivision = $this->getMock('\\Magento\\Framework\\Math\\Division', ['getExactDivision'], [], '', false); $this->localeFormat = $this->getMockForAbstractClass('\\Magento\\Framework\\Locale\\FormatInterface', ['getNumber']); $this->localeFormat->expects($this->any())->method('getNumber')->willReturn($this->qty); $this->object = $this->objectManagerHelper->getObject('Magento\\Framework\\Object'); $this->objectFactory = $this->getMock('\\Magento\\Framework\\Object\\Factory', ['create'], [], '', false); $this->objectFactory->expects($this->any())->method('create')->willReturn($this->object); $this->product = $this->getMock('Magento\\Catalog\\Model\\Product', ['load', 'isComposite', '__wakeup', 'isSaleable'], [], '', false); $this->productFactory = $this->getMock('Magento\\Catalog\\Model\\ProductFactory', ['create'], [], '', false); $this->productFactory->expects($this->any())->method('create')->willReturn($this->product); $this->stockStateProvider = $this->objectManagerHelper->getObject('Magento\\CatalogInventory\\Model\\StockStateProvider', ['mathDivision' => $this->mathDivision, 'localeFormat' => $this->localeFormat, 'objectFactory' => $this->objectFactory, 'productFactory' => $this->productFactory, 'qtyCheckApplicable' => $this->qtyCheckApplicable]); }
/** * Advanced func to add product to quote - processing mode can be specified there. * Returns error message if product type instance can't prepare product. * * @param mixed $product * @param null|float|\Magento\Framework\Object $request * @param null|string $processMode * @return \Magento\Quote\Model\Quote\Item|string * @throws \Magento\Framework\Exception\LocalizedException * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ public function addProduct(\Magento\Catalog\Model\Product $product, $request = null, $processMode = \Magento\Catalog\Model\Product\Type\AbstractType::PROCESS_MODE_FULL) { if ($request === null) { $request = 1; } if (is_numeric($request)) { $request = $this->objectFactory->create(['qty' => $request]); } if (!$request instanceof \Magento\Framework\Object) { throw new \Magento\Framework\Exception\LocalizedException(__('We found an invalid request for adding product to quote.')); } $cartCandidates = $product->getTypeInstance()->prepareForCartAdvanced($request, $product, $processMode); /** * Error message */ if (is_string($cartCandidates) || $cartCandidates instanceof \Magento\Framework\Phrase) { return strval($cartCandidates); } /** * If prepare process return one object */ if (!is_array($cartCandidates)) { $cartCandidates = [$cartCandidates]; } $parentItem = null; $errors = []; $item = null; $items = []; foreach ($cartCandidates as $candidate) { // Child items can be sticked together only within their parent $stickWithinParent = $candidate->getParentProductId() ? $parentItem : null; $candidate->setStickWithinParent($stickWithinParent); $item = $this->getItemByProduct($candidate); if (!$item) { $item = $this->itemProcessor->init($candidate, $request); // Add only item that is not in quote already $this->addItem($item); } $items[] = $item; /** * As parent item we should always use the item of first added product */ if (!$parentItem) { $parentItem = $item; } if ($parentItem && $candidate->getParentProductId() && !$item->getParentItem()) { $item->setParentItem($parentItem); } $this->itemProcessor->prepare($item, $request, $candidate); // collect errors instead of throwing first one if ($item->getHasError()) { $message = $item->getMessage(); if (!in_array($message, $errors)) { // filter duplicate messages $errors[] = $message; } } } if (!empty($errors)) { throw new \Magento\Framework\Exception\LocalizedException(__(implode("\n", $errors))); } $this->_eventManager->dispatch('sales_quote_product_add_after', ['items' => $items]); return $item; }
/** * Get totals as object * * @return \Magento\Framework\Object */ public function getTotals() { return $this->_factory->create($this->_totals); }
/** * Update quantity of order quote items * * @param array $items * @return $this * @throws \Exception|\Magento\Framework\Model\Exception */ public function updateQuoteItems($items) { if (!is_array($items)) { return $this; } try { foreach ($items as $itemId => $info) { if (!empty($info['configured'])) { $item = $this->getQuote()->updateItem($itemId, $this->objectFactory->create($info)); $info['qty'] = (double) $item->getQty(); } else { $item = $this->getQuote()->getItemById($itemId); if (!$item) { continue; } $info['qty'] = (double) $info['qty']; } $this->quoteItemUpdater->update($item, $info); if ($item && !empty($info['action'])) { $this->moveQuoteItem($item, $info['action'], $item->getQty()); } } } catch (\Magento\Framework\Model\Exception $e) { $this->recollectCart(); throw $e; } catch (\Exception $e) { $this->_logger->logException($e); } $this->recollectCart(); return $this; }
/** * @param StockItemInterface $stockItem * @param int|float $qty * @param int|float $summaryQty * @param int|float $origQty * @return \Magento\Framework\Object * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function checkQuoteItemQty(StockItemInterface $stockItem, $qty, $summaryQty, $origQty = 0) { $result = $this->objectFactory->create(); $result->setHasError(false); $qty = $this->getNumber($qty); /** * Check quantity type */ $result->setItemIsQtyDecimal($stockItem->getIsQtyDecimal()); if (!$stockItem->getIsQtyDecimal()) { $result->setHasQtyOptionUpdate(true); $qty = intval($qty); /** * Adding stock data to quote item */ $result->setItemQty($qty); $qty = $this->getNumber($qty); $origQty = intval($origQty); $result->setOrigQty($origQty); } if ($stockItem->getMinSaleQty() && $qty < $stockItem->getMinSaleQty()) { $result->setHasError(true)->setMessage(__('The fewest you may purchase is %1.', $stockItem->getMinSaleQty() * 1))->setErrorCode('qty_min')->setQuoteMessage(__('Please correct the quantity for some products.'))->setQuoteMessageIndex('qty'); return $result; } if ($stockItem->getMaxSaleQty() && $qty > $stockItem->getMaxSaleQty()) { $result->setHasError(true)->setMessage(__('The most you may purchase is %1.', $stockItem->getMaxSaleQty() * 1))->setErrorCode('qty_max')->setQuoteMessage(__('Please correct the quantity for some products.'))->setQuoteMessageIndex('qty'); return $result; } $result->addData($this->checkQtyIncrements($stockItem, $qty)->getData()); if ($result->getHasError()) { return $result; } if (!$stockItem->getManageStock()) { return $result; } if (!$stockItem->getIsInStock()) { $result->setHasError(true)->setMessage(__('This product is out of stock.'))->setQuoteMessage(__('Some of the products are out of stock.'))->setQuoteMessageIndex('stock'); $result->setItemUseOldQty(true); return $result; } if (!$this->checkQty($stockItem, $summaryQty) || !$this->checkQty($stockItem, $qty)) { $message = __('We don\'t have as many "%1" as you requested.', $stockItem->getProductName()); $result->setHasError(true)->setMessage($message)->setQuoteMessage($message)->setQuoteMessageIndex('qty'); return $result; } else { if ($stockItem->getQty() - $summaryQty < 0) { if ($stockItem->getProductName()) { if ($stockItem->getIsChildItem()) { $backOrderQty = $stockItem->getQty() > 0 ? ($summaryQty - $stockItem->getQty()) * 1 : $qty * 1; if ($backOrderQty > $qty) { $backOrderQty = $qty; } $result->setItemBackorders($backOrderQty); } else { $orderedItems = (int) $stockItem->getOrderedItems(); // Available item qty in stock excluding item qty in other quotes $qtyAvailable = ($stockItem->getQty() - ($summaryQty - $qty)) * 1; if ($qtyAvailable > 0) { $backOrderQty = $qty * 1 - $qtyAvailable; } else { $backOrderQty = $qty * 1; } if ($backOrderQty > 0) { $result->setItemBackorders($backOrderQty); } $stockItem->setOrderedItems($orderedItems + $qty); } if ($stockItem->getBackorders() == \Magento\CatalogInventory\Model\Stock::BACKORDERS_YES_NOTIFY) { if (!$stockItem->getIsChildItem()) { $result->setMessage(__('We don\'t have as many "%1" as you requested, but we\'ll back order the remaining %2.', $stockItem->getProductName(), $backOrderQty * 1)); } else { $result->setMessage(__('We don\'t have "%1" in the requested quantity, so we\'ll back order the remaining %2.', $stockItem->getProductName(), $backOrderQty * 1)); } } elseif ($stockItem->getShowDefaultNotificationMessage()) { $result->setMessage(__('We don\'t have as many "%1" as you requested.', $stockItem->getProductName())); } } } else { if (!$stockItem->getIsChildItem()) { $stockItem->setOrderedItems($qty + (int) $stockItem->getOrderedItems()); } } } return $result; }