Magento – Set only last added product in the quote

cartmagento-2.1magento2quotesession

In my website i have bounded the user to only add one product into the cart , however from the session quote object it loads multiple products. How can i restrict quote object to show only last added the product in the checkout. I have tried out my solution in the session.php by overriding it.

Can any one suggest what change i need to make more in the below code to restrict the quote object with lastly added item.

<?php 
namespace Project\Cart\Model;
class Session extends \Magento\Checkout\Model\Session{
const CHECKOUT_STATE_BEGIN = 'begin';

/**
 * Quote instance
 *
 * @var Quote
 */
protected $_quote;

/**
 * Customer Data Object
 *
 * @var CustomerInterface|null
 */
protected $_customer;

/**
 * Whether load only active quote
 *
 * @var bool
 */
protected $_loadInactive = false;

/**
 * Loaded order instance
 *
 * @var \Magento\Sales\Model\Order
 */
protected $_order;

/**
 * @var \Magento\Sales\Model\OrderFactory
 */
protected $_orderFactory;

/**
 * @var \Magento\Customer\Model\Session
 */
protected $_customerSession;

/**
 * @var \Magento\Quote\Api\CartRepositoryInterface
 */
protected $quoteRepository;

/**
 * @var \Magento\Framework\HTTP\PhpEnvironment\RemoteAddress
 */
protected $_remoteAddress;

/**
 * @var \Magento\Framework\Event\ManagerInterface
 */
protected $_eventManager;

/**
 * @var \Magento\Store\Model\StoreManagerInterface
 */
protected $_storeManager;

/**
 * @var \Magento\Customer\Api\CustomerRepositoryInterface
 */
protected $customerRepository;

/**
 * @param QuoteIdMaskFactory
 */
protected $quoteIdMaskFactory;

/**
 * @param bool
 */
protected $isQuoteMasked;

/**
 * @var \Magento\Quote\Model\QuoteFactory
 */
protected $quoteFactory;



public function loadCustomerQuote()
{
    if (!$this->_customerSession->getCustomerId()) {
        return $this;
    }

    $this->_eventManager->dispatch('load_customer_quote_before', ['checkout_session' => $this]);

    try {
        $customerQuote = $this->quoteRepository->getForCustomer($this->_customerSession->getCustomerId());
    } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
        $customerQuote = $this->quoteFactory->create();
    }
    $customerQuote->setStoreId($this->_storeManager->getStore()->getId());
    $allItems = $customerQuote->getAllVisibleItems();
    $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
    //$quoteId = get quote id 
    $quoteItemObj = $objectManager->create('\Magento\Quote\Model\Quote\Item');
    $i=0;
    $cartObj = $objectManager->create('\Magento\Checkout\Model\Cart');

    if(isset($allItems) && count($allItems) > 0) {
        foreach ($allItems as $item) 
        {
            $i++;
            $quoteItem = $quoteItemObj->load($item->getItemId());
            if(count($allItems) != $i) {
                $quoteItem->delete();//delete item
            }
        }
        $cartObj->save();
    }
    if ($customerQuote->getId() && $this->getQuoteId() != $customerQuote->getId()) {
        if($this->getQuoteId() != "") {
            $quote = $this->quoteRepository->get($this->getQuoteId());
            if ($this->_quote) {
                $this->quoteRepository->delete($this->getQuote());
            }
            //$this->quoteRepository->delete($this->getQuoteId());

            //$items = $quote->getAllItems();
            $this->setQuoteId($customerQuote->getId());
            //$quote = $this->quoteRepository->get($quote->getId());
            //$quote->setCustomerId($this->_customerSession->getCustomerId());
            $this->quoteRepository->save($customerQuote);

            // if ($this->_quote) {
                // $this->quoteRepository->delete($this->_quote);
            // }
            $this->_quote = $customerQuote;
        }
    } else {
        $this->getQuote()->getBillingAddress();
        $this->getQuote()->getShippingAddress();
        $this->getQuote()->setCustomer($this->_customerSession->getCustomerDataObject())
            ->setTotalsCollectedFlag(false)
            ->collectTotals();
        $this->quoteRepository->save($this->getQuote());
    }
    return $this;
}
}

Best Answer

Try following way:

app/code/SR/Stackexchange/etc/frontend/di.xml


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Checkout\Model\Cart">
        <plugin name="SR_Stackexchange::add_to_cart" type="SR\Stackexchange\Plugin\Checkout\Model\Cart" sortOrder="1"/>
    </type>
</config>

app/code/SR/Stackexchange/Plugin/Checkout/Model/Cart.php


namespace SR\Stackexchange\Plugin\Checkout\Model;

use Magento\Catalog\Model\Product;

class Cart
{
    /**
     * @var \Magento\Checkout\Model\Session
     */
    protected $checkoutSession;

    /**
     * Cart constructor.
     *
     * @param \Magento\Checkout\Model\Session $checkoutSession
     */
    public function __construct(
        \Magento\Checkout\Model\Session $checkoutSession
    ) {
        $this->checkoutSession = $checkoutSession;
    }

    /**
     * @param \Magento\Checkout\Model\Cart $subject
     * @param \Closure $proceed
     * @param $productInfo
     * @param null $requestInfo
     * @return mixed
     */
    public function aroundAddProduct(
        \Magento\Checkout\Model\Cart $subject,
        \Closure $proceed,
        $productInfo,
        $requestInfo = null
    ) {

        if ($productInfo instanceof Product) {
            $productId = $productInfo->getId();
        } elseif (is_int($productInfo) || is_string($productInfo)) {
            $productId = $productInfo;
        } else {
            return $proceed($productInfo, $requestInfo);
        }

        $isSameProduct = 0;
        $quote = $this->checkoutSession->getQuote();
        $items = $quote->getAllItems();
        foreach ($items as $item) {
            if($productId == $item->getProductId()) {
                $isSameProduct = 1;
                break;
            }
        }

        if($isSameProduct) {
            return $proceed($productInfo, $requestInfo);
        }

        $quote->removeAllItems()->save();
        return $proceed($productInfo, $requestInfo);
    }
}

Now you need to modify when merging quote after login: app/code/SR/Stackexchange/etc/frontend/events.xml


<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="sales_quote_merge_before">
        <observer name="SR_Stackexchange_sales_quote_merge_before" instance="SR\Stackexchange\Observer\SalesQuoteMergeBefore"/>
    </event>
</config>

app/code/SR/Stackexchange/Observer/SalesQuoteMergeBefore.php


namespace SR\Stackexchange\Observer;

use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;

class SalesQuoteMergeBefore implements ObserverInterface
{
    /**
     * Avoid shopping carts merging on customer login
     *
     * @param EventObserver $observer
     */
    public function execute(EventObserver $observer)
    {
        if ($observer->getSource()->hasItems()) {
            $currentQuote = $observer->getSource();
            $productId = 0;
            foreach ($currentQuote->getAllVisibleItems() as $item) {
                $productId = $item->getProductId();
            }

            if (is_object($observer->getQuote()) && $observer->getQuote()->getId()) {
                $oldQuote = $observer->getQuote();
                $hasSameProduct = 0;
                foreach ($oldQuote->getAllVisibleItems() as $item) {
                    if($productId == $item->getProductId()) {
                        $hasSameProduct = 1;
                    }
                }
                if($hasSameProduct == 0) {
                    $observer->getQuote()->removeAllItems();
                }
            }
        }
    }
}

Clear cache.

NB: You can change 'SR/Stackexchange' your own module name

Related Topic