Hi.
In my custom module I am removing cart items first and adding custom options, and adding to the cart again.
When the item stock is 1, it behaves as if there still are 1 as qty and increment the qty to 2, so it gives an error.
On app\code\Magento\CatalogInventory\Model\StockStateProvider.php,
Line 164:
if (!$this->checkQty($stockItem, $summaryQty) || !$this->checkQty($stockItem, $qty)) {
$message = __('We don\'t have as many "%1" as you requested.', $stockItem->getProductName());
Hello @tvgarden
summaryQty means total items for the item into cart.
I don't why you want to remove and add again
I changed a custom module from Magento1 to Magento 2.
Not sure why it had to be this way, but we need to update custom options on cart page, and not on product page.
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Vendor\Module\Observer\Rewrite\Checkout; use Magento\Framework\Event\ObserverInterface; class addItemsUpdateCartObserver implements ObserverInterface { protected $_productIds = array(); protected $_cssProductsListsData = array(); protected $_optionsData = array(); protected $_supAttrData = array(); protected $_bundOptData = array(); protected $_bundQtyData = array(); protected $_downlodData = array(); protected $_qtyData = array(); protected $_allowDelete =true; protected $_errors = array(); protected $_registry; protected $checkoutSession; protected $order; protected $cart; protected $_productloader; private $eventManager; protected $_logger; /** * @param \Magento\Checkout\Model\Session $checkoutSession * @codeCoverageIgnore * @param \Magento\Framework\Registry $registry */ public function __construct( \Magento\Checkout\Model\Session $checkoutSession, \Magento\Checkout\Model\Cart $cart, \Magento\Catalog\Model\ProductFactory $_productloader, \Magento\Framework\Registry $registry, \Magento\Framework\Event\Manager $eventManager, \Psr\Log\LoggerInterface $logger ) { $this->_checkoutSession = $checkoutSession; $this->cart = $cart; $this->_productloader = $_productloader; $this->_registry = $registry; $this->eventManager = $eventManager; $this->_logger = $logger; } /** * @param \Magento\Framework\Event\Observer $observer * @return void * @codeCoverageIgnore */ public function execute(\Magento\Framework\Event\Observer $observer) { $this->eventManager->dispatch('cartextra_checkout_cart_update_items_before', array()); // $hasOptions = false; $data = $this->_checkoutSession->getMyValue(); $cart = $this->cart; //foreach ($data as $itemId => $itemInfo) { /*if (!$this->_cartItemsWithoutOptions($itemInfo)) { $hasOptions = true; // }*/ // } $this->_preprocessUpdateCart($cart, $data); $this->_removeItemsUpdateCart($cart, $data); $this->_addItemsUpdateCart($cart); // if(!$hasOptions) return true; } /* * @param Mage_Checkout_Model_Cart $cart * @param array $data */ protected function _preprocessUpdateCart($cart, $data) { $data = $this->_checkoutSession->getMyValue(); $cart = $this->cart; $this->getProductIds($data ); foreach ($data as $itemId => $itemInfo) { $notGrouped = true; $item = $cart->getQuote()->getItemById($itemId); if (!$this->_cartItemsWithoutOptions($itemInfo)) { if ($item) { try { $this->_qtyData = $this->_setQtyData($this->_qtyData, $itemId, $itemInfo); foreach($item->getProduct()->getOptions() as $_option){ $userValues = $itemInfo['cart_options']; if (isset($userValues[$_option->getId()])) { $userValues[$_option->getId()] = is_array($userValues[$_option->getId()]) ? array_filter($userValues[$_option->getId()]) : $userValues[$_option->getId()]; $_option->groupFactory($_option->getType()) ->setOption($_option) ->setProduct($item->getProduct()) ->setProcessMode("full") ->validateUserValue($userValues); } } $this->_checkQty($item, $itemId, $this->_qtyData); } catch (\Magento\Framework\Exception\LocalizedException $exception) { $this->messageManager->addError($exception->getMessage()); } catch (\Exception $exception) { $this->messageManager->addException($exception, __('We can\'t update the shopping cart.')); } $productId = $item->getProductId(); $this->_cssProductsListsData = $this->_setCssProductListOptions($this->_cssProductsListsData, $item); if( $this->_registry->registry('css_cart_edit')){ $this->_registry->unregister('css_cart_edit'); } } else { $productId = $itemInfo['cart_product_id']; } $this->_optionsData = $this->_setOptionsData($this->_optionsData, $itemInfo, $itemId, 'cart_options'); $this->_supAttrData = $this->_setOptionsData($this->_supAttrData, $itemInfo, $itemId, 'super_attribute'); $this->_bundOptData = $this->_setOptionsData($this->_bundOptData, $itemInfo, $itemId, 'bundle_option'); $this->_bundQtyData = $this->_setOptionsData($this->_bundQtyData, $itemInfo, $itemId, 'bundle_option_qty'); $this->_downlodData = $this->_setOptionsData($this->_downlodData, $itemInfo, $itemId, 'downloadable_links'); } elseif (!empty($itemInfo['qty'])) { if ($item) { if($item->getProductType() != 'grouped') { $this->_qtyData = $this->_setQtyData($this->_qtyData, $itemId, $itemInfo); try { $this->_checkQty($item, $itemId, $this->_qtyData); }catch (\Magento\Framework\Exception\LocalizedException $exception) { $this->messageManager->addError($exception->getMessage()); } catch (\Exception $exception) { $this->messageManager->addException($exception, __('We can\'t update the shopping cart.')); } $productId = $item->getProductId(); $this->_cssProductsListsData = $this->_setCssProductListOptions($this->_cssProductsListsData, $item); } else { $notGrouped = false; } } } if($notGrouped) { $this->_productIds[$itemId] = $productId; } } } /* * @param Mage_Checkout_Model_Cart $cart * @param array $data */ protected function _removeItemsUpdateCart($cart, $data) { if($this->_allowDelete) { foreach ($data as $itemId => $itemInfo) { $item = $cart->getQuote()->getItemById($itemId); if(gettype($item)=="object"){ if($item->getProductType() != 'grouped') { $this->eventManager->dispatch('checkout_cart_remove_items_before', array('item' => $item)); $cart->getQuote()->removeItem($itemId); } } } } else { // Mage::throwException(implode("\n", $this->_errors)); } } /* * @param Mage_Checkout_Model_Cart $cart */ protected function _addItemsUpdateCart($cart) { $data = $this->_checkoutSession->getMyValue(); $cart = $this->cart; $this->getProductIds($data ); foreach ($this->_productIds as $itemId => $productId) { if ($productId) { $product = $this->_productloader->create()->load($productId); if ($product->getId()) { $cssProductsListsListId = empty($this->_cssProductsListsData[$itemId]) ? null : $this->_cssProductsListsData[$itemId]; $product->setIsVendorProductList($cssProductsListsListId); $aRequestOptions = $this->_setRequestOptionsData($this->_optionsData, $itemId); $aRequestSupAttr = $this->_setRequestData($this->_supAttrData, $itemId); $aRequestBunData = $this->_setRequestData($this->_bundOptData, $itemId); $aRequestBundQty = $this->_setRequestData($this->_bundQtyData, $itemId); $aRequestDownlod = $this->_setRequestData($this->_downlodData, $itemId); if (!empty($this->_qtyData[$itemId]) && $this->_allowDelete) { $params = array( 'product' => $productId, 'qty' => $this->_qtyData[$itemId], 'options' => $aRequestOptions, 'super_attribute' => $aRequestSupAttr, 'bundle_option' => $aRequestBunData, 'bundle_option_qty' => $aRequestBundQty, 'links' => $aRequestDownlod, ); if( $this->_registry->registry(‘vendor_cart_options_item')){ $this->_registry->unregister('vendor_cart_options_item'); } $item = $cart->getQuote()->getItemById($itemId); $this->_registry->register(‘vendor_cart_options_item', $item); $this->eventManager->dispatch('vendor_editablecart_product_add', array('product'=>$product, 'cart' => $cart)); $cart->addProduct($product, $params); } } } } } function getProductIds($data){ //$data = $this->_checkoutSession->getQuote()->getAllVisibleItems(); foreach ($data as $itemId => $itemInfo) { $notGrouped = true; $item = $this->cart->getQuote()->getItemById($itemId); if (!$this->_cartItemsWithoutOptions($itemInfo)) { if ($item) { try { $this->_qtyData = $this->_setQtyData($this->_qtyData, $itemId, $itemInfo); foreach($item->getProduct()->getOptions() as $_option){ $userValues = $itemInfo['cart_options']; if (isset($userValues[$_option->getId()])) { $userValues[$_option->getId()] = is_array($userValues[$_option->getId()]) ? array_filter($userValues[$_option->getId()]) : $userValues[$_option->getId()]; $_option->groupFactory($_option->getType()) ->setOption($_option) ->setProduct($item->getProduct()) ->setProcessMode("full") ->validateUserValue($userValues); } }/**/ $this->_checkQty($item, $itemId, $this->_qtyData); } catch (\Magento\Framework\Exception\LocalizedException $exception) { $this->messageManager->addError($exception->getMessage()); } catch (\Exception $exception) { $this->messageManager->addException($exception, __('We can\'t update the shopping cart.')); } $productId = $item->getProductId(); $this->_cssProductsListsData = $this->_setCssProductListOptions($this->_cssProductsListsData, $item); /* if (!Mage::registry('css_cart_edit')) { Mage::register('css_cart_edit', true); }*/ if (! $this->_registry->registry('css_cart_edit')) { $this->_registry->register('css_cart_edit', true); } } else { $productId = $itemInfo['cart_product_id']; // $productId = $itemInfo->getProductId(); } $this->_optionsData = $this->_setOptionsData($this->_optionsData, $itemInfo, $itemId, 'cart_options'); $this->_supAttrData = $this->_setOptionsData($this->_supAttrData, $itemInfo, $itemId, 'super_attribute'); $this->_bundOptData = $this->_setOptionsData($this->_bundOptData, $itemInfo, $itemId, 'bundle_option'); $this->_bundQtyData = $this->_setOptionsData($this->_bundQtyData, $itemInfo, $itemId, 'bundle_option_qty'); $this->_downlodData = $this->_setOptionsData($this->_downlodData, $itemInfo, $itemId, 'downloadable_links'); // $this->_logger->addInfo(print_r($this->_optionsData, true)); } elseif (!empty($itemInfo['qty'])) { if ($item) { if($item->getProductType() != 'grouped') { $this->_qtyData = $this->_setQtyData($this->_qtyData, $itemId, $itemInfo); try { $this->_checkQty($item, $itemId, $this->_qtyData); } catch(Mage_Core_Exception $e) { $this->_errors[] = $e->getMessage(); $this->_allowDelete = false; } $productId = $item->getProductId(); $this->_cssProductsListsData = $this->_setCssProductListOptions($this->_cssProductsListsData, $item); } else { $notGrouped = false; } } } if($notGrouped) { $this->_productIds[$itemId] = $productId; } } } /** * Check if quote items have any options * @param array $itemInfo quote item data * @return bool */ private function _cartItemsWithoutOptions($itemInfo) { return (empty($itemInfo['cart_options']) && empty($itemInfo['super_attribute']) && empty($itemInfo['bundle_option']) && empty($itemInfo['downloadable_links'])); } /** * @param Mage_Sales_Model_Quote_Item $item * @param array $productsListsData array of product lists options * @return array */ private function _setCssProductListOptions($productsListsData, $item) { $cssProductsListsOption = $item->getOptionByCode('cssproductslists'); $productsListsData[$item->getId()] = ($cssProductsListsOption instanceof Mage_Sales_Model_Quote_Item_Option) ? $cssProductsListsOption->getValue() : null; return $productsListsData; } /** * Collect specific type options for quote item * @param array $dataArray array of options * @param array $itemInfo quote item data * @param int $itemId quote item id * @param string $type type of item options * @return array */ private function _setOptionsData($dataArray, $itemInfo, $itemId, $type) { if (!empty($itemInfo[$type])) { $dataArray[$itemId][] = $itemInfo[$type]; } return $dataArray; } /** * Set requested custom options for quote item * @param array $optionsData custom options for quote item * @param int $itemId quote item id * @return array */ private function _setRequestOptionsData($optionsData, $itemId) { $requestOptionsData = array(); if (!empty($optionsData[$itemId])) { foreach ($optionsData[$itemId] as $aData) { if ($aData) { foreach ($aData as $iOptionId => $mValue) { if ($mValue and is_array($mValue) AND isset($mValue[0]) AND $mValue[0] == 0) { unset($mValue[0]); } if ($mValue != array(0 => 0)) { $requestOptionsData[$iOptionId] = $mValue; } } } } } return $requestOptionsData; } /** * Set requested options for quote item * @param array $dataArray specific type options for quote item * @param int $itemId quote item id * @return array */ private function _setRequestData($dataArray, $itemId) { $requestData = array(); if (!empty($dataArray[$itemId])) { foreach ($dataArray[$itemId] as $aData) { if ($aData) { foreach ($aData as $iOptionId => $sValue) { $requestData[$iOptionId] = $sValue; } } } } return $requestData; } /** * Set quantity info for quote item * @param array $qtyData array of items qty * @param int $itemId quote item id * @param array $itemInfo quote item data * @return array */ private function _setQtyData($qtyData, $itemId, $itemInfo) { $qty = isset($itemInfo['qty']) ? (float) $itemInfo['qty'] : false; $qtyData[$itemId] = $qty; return $qtyData; } private function _checkQty($item, $itemId, $qtyData) { $oldQty = $item->getQty(); $item->setQtyToAdd($qtyData[$itemId]); $item->setQty($qtyData[$itemId]); if ($item->getHasError()) { $message = $item->getMessage(); $item->setQtyToAdd($oldQty); $item->setQty($oldQty); } if (!empty($message)) { Mage::throwException($message); } return true; } }
I would like to know how to update $summaryQty from this observer.