Magento2 | PWA | GraphQL

Magento2 Create Custom Shipping Method Based On a Percentage of Cart Price


In this post, we will check how to create custom shipping method based on a percentage of cart price.




You can find complete module on Github.

Step 1: Create a new module

Create folder inside app/code/Magelearn/PercentageShipping

Add registration.php file in it:

<?php
use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'Magelearn_PercentageShipping',
    __DIR__
);
Add composer.json file in it:
{
    "name": "magelearn/module-percentageshipping",
    "description": "Shipping method based on a percentage of cart price.",
    "type": "magento2-module",
    "license": "OSL-3.0",
    "authors": [
        {
            "email": "info@mage2gen.com",
            "name": "Mage2Gen"
        },
        {
            "email": "vijaymrami@gmail.com",
            "name": "vijay rami"
        }
    ],
    "minimum-stability": "dev",
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "Magelearn\\PercentageShipping\\": ""
        }
    }
}
Add etc/module.xml file in it:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Magelearn_PercentageShipping" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Store"/>
            <module name="Magento_Sales"/>
            <module name="Magento_Quote"/>
            <module name="Magento_SalesRule"/>
        </sequence>
    </module>
</config>

Step 2: Add the module configuration

Create etc/adminhtml/system.xml file.

The system.xml source code declares custom shipping module options:
  • Enabled
  • Title
  • Method Name
  • Shipping Cost
  • Ship to Applicable Countries
  • Ship to Specific Countries
  • Show Method if Not Applicable
  • Sort Order
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="carriers" translate="label" type="text" sortOrder="320" showInDefault="1" showInWebsite="1" showInStore="1">
            <group id="percentageshipping" translate="label" type="text" sortOrder="900" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Percentage Shipping</label>
                <field id="active" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1">
                    <label>Enabled</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
                <field id="title" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Title</label>
                </field>
                <field id="name" translate="label" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Method Name</label>
                </field>
                <field id="shipping_percentage" translate="label" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="0" >
                    <label>Shipping Percentage</label>
                    <validate>validate-number validate-zero-or-greater</validate>
                </field>
                <field id="sallowspecific" translate="label" type="select" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1">
                    <label>Ship to Applicable Countries</label>
                    <frontend_class>shipping-applicable-country</frontend_class>
                    <source_model>Magento\Shipping\Model\Config\Source\Allspecificcountries</source_model>
                </field>
                <field id="specificcountry" translate="label" type="multiselect" sortOrder="70" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Ship to Specific Countries</label>
                    <source_model>Magento\Directory\Model\Config\Source\Country</source_model>
                    <can_be_empty>1</can_be_empty>
                </field>
                <field id="showmethod" translate="label" type="select" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Show Method if Not Applicable</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                    <frontend_class>shipping-skip-hide</frontend_class>
                </field>
                <field id="sort_order" translate="label" type="text" sortOrder="90" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Sort Order</label>
                </field>
            </group>
        </section>
    </system>
</config>

Create etc/config.xml file.

The config.xml file specifies default values for custom shipping module options and the shipping module model, Magelearn\PercentageShipping\Model\Carrier\PercentageShipping:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
    <default>
        <carriers>
            <percentageshipping>
                <active>0</active>
                <title>Percentage Shipping</title>
                <name>Percentage Shipping</name>
                <shipping_percentage>7</shipping_percentage>
                <sallowspecific>0</sallowspecific>
                <sort_order>15</sort_order>
                <specificerrmsg>This shipping method is not available. To use this shipping method, please contact us.</specificerrmsg>
                <model>Magelearn\PercentageShipping\Model\Carrier\PercentageShipping</model>
            </percentageshipping>
        </carriers>
    </default>
</config>

Step 3: Create the carrier model

Create Model/Carrier/PercentageShipping.php file:
<?php

declare(strict_types=1);

namespace Magelearn\PercentageShipping\Model\Carrier;

use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Shipping\Model\Carrier\AbstractCarrier;
use Magento\Shipping\Model\Carrier\CarrierInterface;
use Magento\Shipping\Model\Rate\Result;

/**
 * Class PercentageShipping
 * @package Magelearn\PercentageShipping\Model\Carrier
 */
class PercentageShipping extends AbstractCarrier implements CarrierInterface
{
    /**
     * @var string
     */
    protected $_code = 'percentageshipping';

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

    /**
     * @var \Magento\Shipping\Model\Rate\ResultFactory
     */
    private $rateResultFactory;

    /**
     * @var \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory
     */
    private $rateMethodFactory;

    /**
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
     * @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory
     * @param \Psr\Log\LoggerInterface $logger
     * @param \Magento\Shipping\Model\Rate\ResultFactory $rateResultFactory
     * @param \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory
     * @param array $data
     */
    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 = []
    ) {
        parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
		$this->rateResultFactory = $rateResultFactory;
        $this->rateMethodFactory = $rateMethodFactory;
    }

    /**
     * Percentage Shipping Rates Collector
     *
     * @param RateRequest $request
     * @return Result
     */
    public function collectRates(RateRequest $request) : Result
    {
        $result = $this->rateResultFactory->create();

        if (!$this->getConfigFlag('active')) {
            return $result;
        }

        $method = $this->rateMethodFactory->create();

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

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

        $shippingPercentage = (float)$this->getConfigData('shipping_percentage') / 100;
        $shippingPercentage = $shippingPercentage > 1 ? 1 : $shippingPercentage;

        $shippingCost = $request->getPackageValue() * $shippingPercentage;

        $method->setPrice($shippingCost);
        $method->setCost($shippingCost);

        $result->append($method);

        return $result;
    }

    /**
     * @return array
     */
    public function getAllowedMethods() : array
    {
        return [$this->_code => $this->getConfigData('name')];
    }
}

After adding above files, just run Magento commands:

php bin/magento set:upg

php bin/magento set:d:c

php bin/magento set:s:d en_US

php bin/magento c:c

php bin/magento c:f

Now, you can see new shipping method configuration will display at Store >> Configuration >> Sales >> Shipping Method

And also new shipping method will be display on checkout page as per the screenshot at above.

0 Comments On "Magento2 Create Custom Shipping Method Based On a Percentage of Cart Price"

Back To Top