Magento 2.1 – Update Configurable Product in Cart

cartconfigurable-productmagento-2.1

I have used this function for many 1.x projects and hoped that it would work in 2.x too but looks like I need to add more stuff to what should be a somewhat simple operation.

For some unknown reason after pushing "Update Shopping Cart" and reloading page item price and subtotal (yes, only those two) doesn't change to new ones. I have different prices for configurable product options so price must be updated. Dropdown option for product after refresh is set to new one and Totals are reloaded to new prices too. DB shows that data saved properly.

After hitting that "Update Shopping Cart" button again, new price shows up. So it is saved but doesn't show after first reload.

Magento: Blank theme, v2.1, cache disabled, developer mode.

Code that I use:

Event:

<event name="checkout_cart_update_items_before">
    <observer name="my_checkout_cart_update" instance="Company\Module\Observer\Cartupdate" /></event>

Function:

protected $_cart;
protected $_configurable;

public function __construct(
    \Magento\Framework\ObjectManagerInterface $objectManager,
    \Magento\Framework\Event\ObserverFactory $observerFactory,
    \Magento\Checkout\Model\Cart $cart,
    \Magento\ConfigurableProduct\Model\Product\Type\Configurable $config
) {
    $this->_objectManager = $objectManager;
    $this->_cart = $cart;
    $this->_observerFactory = $observerFactory;
    $this->_configurable = $config;
}

public function execute(\Magento\Framework\Event\Observer $observer)
{
    $cart = $this->_cart;
    $data = $observer->getEvent()->getInfo()->toArray();

    foreach ($data as $itemId => $itemInfo) 
    {
        $item = $cart->getQuote()->getItemById($itemId);

        if (!$item) 
            continue;

        if (!isset($itemInfo['option']) or empty($itemInfo['option'])) 
            continue;

        if ($item->getProduct()->getTypeId() == 'configurable')
        {
            $options = $item->getOptions();

            $newId = $this->_configurable->getProductByAttributes($itemInfo['option'],$item->getProduct())->getId();

            foreach ($options as $option)
            {
                if ($option->getCode() == 'info_buyRequest')
                {
                    $unserialized = unserialize($option->getValue());
                    $unserialized['super_attribute'] = $itemInfo['option'];
                    $unserialized['selected_configurable_option'] = $newId;
                    $option->setValue(serialize($unserialized));   
                }
                elseif ($option->getCode() == 'attributes')
                {
                    $option->setValue(serialize($itemInfo['option']));
                }
                elseif (substr($option->getCode(), 0,11) == 'product_qty')
                {
                    $option->setProductId($newId);
                    $option->setCode('product_qty_'.$newId);
                }
                elseif (substr($option->getCode(), 0,14) == 'simple_product')
                {
                    $option->setProductId($newId);
                    $option->setValue($newId);
                }
                $option->save();
            }
            $item->setOptions($options)->save();
        }
    }
    $cart->save();
}

Best Answer

Found a way to update cart:

public function execute(\Magento\Framework\Event\Observer $observer)
{
    $cart = $observer->getCart();
    $data = $observer->getEvent()->getInfo()->toArray();

    foreach ($data as $itemId => $itemInfo) 
    {
        $item = $cart->getQuote()->getItemById($itemId);

        if (!$item) 
            continue;

        if (!isset($itemInfo['option']) or empty($itemInfo['option'])) 
            continue;

        if ($item->getProduct()->getTypeId() == 'configurable')
        {
            $params = array(
                'id' => $itemId,
                'qty' => $itemInfo['qty'],
                'product' => $item->getProduct()->getId(),
                'super_attribute' => $itemInfo['option']
            );
            $cart->updateItem($itemId, new \Magento\Framework\DataObject($params));
        }
    }
}
Related Topic