1

I want to do following in Magento 2

  • Only one product in an entire cart

  • If the cart is not empty and I add a product to the cart then product in the cart will remove and newly added replace it(a concept like swiggy)

closed as too broad by Jai, Priyank, Manashvi Birla, Manoj Deswal, Murtuza Zabuawala May 29 '18 at 6:46

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

3

This will help you out.

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

Let me know if it doesn't work or if you have query.

  • when this event is call @Aditya Shah – user4536 May 29 '18 at 5:04
  • 1
    The answer you provided is for Magento 1 and the question was asked for Magento 2. – Dinesh Yadav May 29 '18 at 5:05
0

You have to remove all the cart items and then add the new product to the cart.

Create a form

<form
    id="addsingleproduct"
    name="add_single_product"
    action="<?php $block->getUrl('module/product/addsingle') ?>">
    <!-- add your product id in the value -->
    <input type="hidden" name="product" value="10">
    <input type="hidden" name="qty" value="1">
    <input type="submit" value="Add to cart">
</form>

Create a controller to remove and add cart item.

<?php

namespace Venodr\Module\Controller\Product;

use Magento\Framework\Controller\ResultFactory;

class Addsingle extends \Magento\Framework\App\Action\Action
{
    private $checkoutSession;

    private $cart;

    private $productModel;

    private $formKey;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Checkout\Model\Session $checkoutSession,
        \Magento\Checkout\Model\Cart $cart,
        \Magento\Catalog\Model\Product $productModel,
        \Magento\Framework\Data\Form\FormKey $formKey
    ) {
        $this->checkoutSession = $checkoutSession;
        $this->cart = $cart;
        $this->productModel = $productModel;
        $this->formKey = $formKey;
        parent::__construct($context);
    }

    public function execute()
    {
        $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
        try {
            if ($this->checkoutSession->getQuote()) {
                $allItems = $this->checkoutSession->getQuote()->getAllVisibleItems();
                foreach ($allItems as $item) {
                    $itemId = $item->getItemId();
                    $this->cart->removeItem($itemId)->save();
                }
            }

            $post_data = $this->getRequest()->getPostValue();
            $product_id = $post_data['product'];
            $qty = $post_data['qty'];

            $_product = $this->productModel->load($product_id);

            $finalPriceAmt = $_product->getPriceInfo()->getPrice('final_price')->getValue();

            $params = array(
                'form_key' => $this->formKey->getFormKey(),
                'product' => $product_id,
                'qty' => $qty,
                'price' => $finalPriceAmt
            );

            $this->cart->addProduct($_product, $params);
            $this->cart->save();

            $this->messageManager->addSuccess(
                __('Your product has been added to cart succesfully.')
            );
            $resultRedirect->setUrl($this->_redirect->getRefererUrl());
            return $resultRedirect;
        } catch (\Exception $e) {
            $this->messageManager->addError(
                __('Something went wrong. Please try again later.')
            );
            $resultRedirect->setUrl($this->_redirect->getRefererUrl());
            return $resultRedirect;
        }
    }
}
0

You can create a before plugin for public function addProduct($productInfo, $requestInfo = null) for class Cart under the namespace Magento\Checkout\Model;

You can go through https://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html to know about plugins.

In your plugin you can check if the cart is empty or not, for this you can use public function getItemsCount() of \Magento\Checkout\Helper\Cart

If the cart is empty you can continue and if there is something in the cart then you can use public function truncate() of \Magento\Checkout\Model\Cart to empty the cart and then continue.

0

Finally Got the simple solution

event.xml (Tatva\Cart\etc\frontend)

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="controller_action_predispatch_checkout_cart_add">
    <observer name="tatva_cart" instance="Tatva\Cart\Observer\beforeAddToCart" />
</event>

beforeAddToCart.php (Tatva\Cart\Observer)

<?php
namespace Tatva\Cart\Observer;
use Magento\Framework\Event\ObserverInterface;

class beforeAddToCart implements ObserverInterface
{

protected $_cart;

public function __construct(
    \Magento\Checkout\Model\Cart $cart
) 
{
    $this->_cart = $cart;
}

public function execute(\Magento\Framework\Event\Observer $observer)
{
    $this->_cart->truncate();
}
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.