0

I have created one attribute for products, if that attribute value is yes than only it will be eligible for free shipping and other products will be excluded from free shipping. so when i add that product in the cart it wont count in free shipping.

2
  • use addto cart event and in that event you get current items quote data check your specific product attribute value and then apply this magento.stackexchange.com/a/250486/82670
    – Msquare
    Feb 23 at 4:09
  • i think it can be possible with freeshipping model itself. so we do not need to check separately for cart and order level.
    – Fena shah
    Feb 23 at 4:27
1

Vendor/Module/etc/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\Shipping\Model\Shipping">
        <plugin disabled="false" name="Vendor_Module_Plugin_Magento_Shipping_Model_Shipping" sortOrder="10" type="Vendor\Module\Plugin\Magento\Shipping\Model\Shipping"/>
    </type>
</config>

Vendor/Module/Plugin/Magento/Shipping/Model/Shipping.php

<?php
namespace Vendor\Module\Plugin\Magento\Shipping\Model;
 
class Shipping
{
    protected $product;
 
    public function __construct(
        \Magento\Catalog\Model\ProductFactory $product
    ) {
        $this->product = $product; 
    }
 
    public function aroundCollectCarrierRates(
        \Magento\Shipping\Model\Shipping $subject,
        \Closure $proceed,
        $carrierCode,
        $request
    ) {
        $noFreeShipping = false;
        $allItems = $request->getAllItems();
         
        foreach ($allItems as $item) {    
            $_product = $this->product->create()->load($item->getProduct()->getId());
        
            if (condition) { //here you can check your attribute value
                $noFreeShipping = true;
                break;
            }
        }
        if ($noFreeShipping && $carrierCode == 'freeshipping') {
            return false;
        }
        $result = $proceed($carrierCode, $request);
        return $result;
    }
}
7
  • Thank you !! This will work but if i add two products in the cart in which one product has attribute value 0 and other has attribute value 1 than this will not work.
    – Fena shah
    Feb 23 at 7:49
  • If you go with an approach like this, i would suggest you add an extension attribute on the quote item instead of loading the products one by one to validate the condition (performance wise this might get costly otherwise). Feb 23 at 8:49
  • you can check in forecah loop
    – Rk Rathod
    Feb 23 at 8:56
  • 1
    @DianaBotean yes good idea, i will try that. Thank you :) keep helping.
    – Fena shah
    Feb 23 at 9:25
  • @RkRathod still not working.
    – Fena shah
    Feb 23 at 9:25
1

The cleanest way to achieve this is to create a new shipping method that could extend the OOTB Magento freeshipping carrier vendor/magento/module-offline-shipping/Model/Carrier/Freeshipping.php (or it could be a completely new carrier with no dependencies to Magento default) and performs the logic by validating the items in the collectRates() method.

Good luck!

2
0

I found the solution:

I Override the offlineshipping model file and deduct the price of the product which i wanted to exclude from the free shipping and set the new Package Value.

Vendor/Module/etc/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">
     <preference for="Magento\OfflineShipping\Model\Carrier\Freeshipping" type="Vendor\Module\Model\Carrier\Freeshipping" />
</config>

Vendor/Magento/Model/Carrier/Freeshipping.php

<?php

namespace Vendor\Magento\Model\Carrier;

use Magento\Quote\Model\Quote\Address\RateRequest;

/**
 * Free shipping model
 *
 * @api
 * @since 100.0.2
 */
class Freeshipping extends \Magento\OfflineShipping\Model\Carrier\Freeshipping
{
    /**
     * @var string
     */
    protected $_code = 'freeshipping';

    /**
     * @var bool
     */
    protected $_isFixed = true;

    /**
     * @var \Magento\Shipping\Model\Rate\ResultFactory
     */
    protected $_rateResultFactory;

    /**
     * @var \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory
     */
    protected $_rateMethodFactory;

    public function __construct(
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory,
        \Psr\Log\LoggerInterface $logger,
        \Magento\Shipping\Model\Rate\ResultFactory $rateResultFactory,
        \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory,
        array $data = []
    ) {
        $this->_rateResultFactory = $rateResultFactory;
        $this->_rateMethodFactory = $rateMethodFactory;
        parent::__construct($scopeConfig, $rateErrorFactory, $logger, $rateResultFactory, $rateMethodFactory, $data);
    }

    public function collectRates(RateRequest $request)
    {
        if (!$this->getConfigFlag('active')) {
            return false;
        }

        /** @var \Magento\Shipping\Model\Rate\Result $result */
        $result = $this->_rateResultFactory->create();

        $this->_updateFreeMethodQuote($request);

        /* check your condition here start */
        foreach ($request->getAllItems() as $item) {
            if(condition){
               $request->setPackageValueWithDiscount($request->getPackageValueWithDiscount() - $item->getRowTotal());
                continue;
            }
        }
        /* check your condition here end*/

        if ($request->getFreeShipping() || $request->getPackageValueWithDiscount() >= $this->getConfigData(
            'free_shipping_subtotal'
        )
        ) {

            /** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */
            $method = $this->_rateMethodFactory->create();

            $method->setCarrier('freeshipping');
            $method->setCarrierTitle($this->getConfigData('title'));

            $method->setMethod('freeshipping');
            $method->setMethodTitle($this->getConfigData('name'));

            $method->setPrice('0.00');
            $method->setCost('0.00');

            $result->append($method);
        } elseif ($this->getConfigData('showmethod')) {
            $error = $this->_rateErrorFactory->create();
            $error->setCarrier($this->_code);
            $error->setCarrierTitle($this->getConfigData('title'));
            $errorMsg = $this->getConfigData('specificerrmsg');
            $error->setErrorMessage(
                $errorMsg ? $errorMsg : __(
                    'Sorry, but we can\'t deliver to the destination country with this shipping module.'
                )
            );
            return $error;
        }
        return $result;
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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