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)
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.
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;
}
}
}
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.
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();
}
}