3

In my site, I need to add a condition to ,

Display Free Shipping only for order total bigger than 150$. I've added Maximum Order Amount from backend. from Stores>Settings>Configuration>Sales>Shipping Methods->Free shipping

I need to hide Free shipping option if total amount is less than 150$.

This works correctly only if order item total is 150$ without any discounts or deductions. I added 10$ discount onto 150$ item.but it still shows free shipping option.

How can I fix this?

  • Hi @siarhey I try above function but not working, in my conditions i have enabled free shipping the customer purchase above Rupees 1500. This works correctly only if order item total is 1500 without any discounts or deductions. I added 50% discount onto 1500 item.but it still shows free shipping option. – thilip Feb 28 at 14:10
1

Take a look at the Magento\OfflineShipping\Model\Carrier\Freeshipping class located at magento/module-offline-shipping/Model/Carrier/Freeshipping.php:

/**
 * FreeShipping Rates Collector
 *
 * @param RateRequest $request
 * @return \Magento\Shipping\Model\Rate\Result|bool
 */
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);

    if ($request->getFreeShipping() || $request->getBaseSubtotalInclTax() >= $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);
    }

    return $result;
}

as you can see it compares your configuration value (150) with a base subtotal with tax from the shipping rates request. There nothing about discount checked here. For your purpose, it is better to write an after-plugin for this method and make a different validation. Or rewrite this class completely.

Maybe this plugin can help you, but I have no time to test it right now:

Note: here the full plugin code on the GitHub

etc/di.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2018 MageWorx. All rights reserved.
 * See LICENSE.txt for license details.
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <!-- PLUGINS: -->
    <type name="Magento\OfflineShipping\Model\Carrier\Freeshipping">
        <plugin name="mageworx_validate_subtotal_with_discount" type="MageWorx\FreeShippingWithDiscount\Plugin\FreeShipping"/>
    </type>
</config>

MageWorx/FreeShippingWithDiscount/Plugin/FreeShipping.php

<?php
/**
 * Copyright © 2018 MageWorx. All rights reserved.
 * See LICENSE.txt for license details.
 */

namespace MageWorx\FreeShippingWithDiscount\Plugin;

use Magento\OfflineShipping\Model\Carrier\Freeshipping as OriginalFreeShipping;
use Magento\Checkout\Model\Session;

class FreeShipping
{
    /** @var Session|\Magento\Backend\Model\Session\Quote */
    protected $session;

    /**
     * FreeShipping constructor.
     *
     * @param Session                              $checkoutSession
     * @param \Magento\Backend\Model\Session\Quote $backendQuoteSession
     * @param \Magento\Framework\App\State         $state
     * @param \Magento\Customer\Model\Session      $customerSession
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function __construct(
        Session $checkoutSession,
        \Magento\Backend\Model\Session\Quote $backendQuoteSession,
        \Magento\Framework\App\State $state,
        \Magento\Customer\Model\Session $customerSession
    ) {
        if ($state->getAreaCode() == \Magento\Framework\App\Area::AREA_ADMINHTML) {
            $this->session = $backendQuoteSession;
        } else {
            $this->session = $checkoutSession;
        }
    }

    /**
     * @param OriginalFreeShipping $subject
     * @param callable             $proceed
     * @param                      $field
     * @return float
     */
    public function aroundGetConfigData(OriginalFreeShipping $subject, callable $proceed, $field)
    {
        $value = $proceed($field);

        if ($field != 'free_shipping_subtotal') {
            return $value;
        }

        // Add discount to the initial value from config
        // In this case base subtotal with tax should be equal or greater then value including discount
        // Lets
        // Value == 150
        // Subtotal == 140
        // Tax == 14
        // Discount == 28
        // Default condition will check it like:
        // 140 + 14 >= 150 returns true
        // modified condition will check:
        // 140 + 14 >= 150 + 28 returns false
        /** @var \Magento\Quote\Model\Quote $quote */
        $quote = $this->session->getQuote();
        $shippingAddress = $quote->getShippingAddress();
        $baseDiscount = $shippingAddress->getBaseDiscountAmount();
        $value += abs($baseDiscount);

        return $value;
    }
}

Main idea is to add base discount amount to the validation value, like 150 + discount.

PS: we should use abs($baseDiscount) becasue it is usually has a - prefix.

  • @Joey I tested this solution today and for me, it works well. Can you test it on your side? – Siarhey Uchukhlebau Jan 26 '18 at 8:17
  • I'll test and get back to you. Thanks for this. highly appreciate it – Joey Jan 26 '18 at 10:18
  • Works like a charm. Thank you @Siarhey Uchukhlebau. You're a savior – Joey Jan 30 '18 at 7:06

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.