Magento 2: Creating a Custom Shipping Method

In this tutorial, I will cover initializing module configurations and writing an adapter model

Posted on July 4, 2017 in Magento2

Create a New Module as MyShip

moduel.xml file

#app/code/Jeff/MyShip/etc/module.xml

<?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="Jeff_MyShip" setup_version="0.0.1"/>
</config>

registration.php file

#app/code/Jeff/MyShip/registration.php

<?php
    \Magento\Framework\Component\ComponentRegistrar::register(
        \Magento\Framework\Component\ComponentRegistrar::MODULE,
        'Jeff_MyShip',
        __DIR__
    );

Install the new module by typing commands in the console window:


php bin/magento module:enable Jeff_MyShip
php bin/magento setup:upgrade

Create system.xml config file for the new Shipping Method

This will create the shipping configuration parameters near all the other shipping methods


#app/code/Jeff/MyShip/etc/adminhtml/system.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../Backend/etc/system_file.xsd">
    <system>
        <section id="carriers">
            <group id="myship" translate="label" type="text" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>MyShip</label>
                <field id="active" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Enabled</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
                <field id="name" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Method Name</label>
                </field>
                <field id="title" translate="label" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Method Title</label>
                </field>
                <field id="express_enabled" translate="label" type="select" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Enable express</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
                <field id="express_title" translate="label" type="text" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Title express</label>
                </field>
                <field id="express_price" translate="label" type="text" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Price express</label>
                </field>
                <field id="business_enabled" translate="label" type="select" sortOrder="70" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Enable business</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
                <field id="business_title" translate="label" type="text" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Title business</label>
                </field>
                <field id="business_price" translate="label" type="text" sortOrder="90" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Price business</label>
                </field>
                <field id="sallowspecific" translate="label" type="select" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="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="110" showInDefault="1" showInWebsite="1" showInStore="1">
                    <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="specificerrmsg" translate="label" type="textarea" sortOrder="120" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Display Error Message</label>
                </field>
            </group>
        </section>
    </system>
</config>

Create config.xml file to set up some default settings


#app/code/Jeff/MyShip/etc/config.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../Core/etc/config.xsd">
    <default>
        <carriers>
            <myship>
                <model>Jeff\MyShip\Model\Carrier\MyShip</model>
                <active>1</active>
                <name>Myship Shipping</name>
                <title>Myship Shipping</title>
                <express_enabled>1</express_enabled>
                <express_title>Express delivery</express_title>
                <express_price>4</express_price>

                <business_enabled>1</business_enabled>
                <business_title>Business delivery</business_title>
                <business_price>5</business_price>
                <specificerrmsg>This shipping method is currently uavailable. If you wuold like to ship using this shipping method, please contact us.</specificerrmsg>
            </myship>
        </carriers>
    </default>
</config>

After clear cache, you can find our new shipping method is shown up at the backend as following



Adding a model with the business logic for the new shipping method

The new model class will be used for making the shipping method available, calculating the shipping costs, and setting the title in the frontend


#app/code/Jeff/MyShip/Model/Carrier/MyShp.php

<?php
namespace Jeff\MyShip\Model\Carrier;

use Magento\Shipping\Model\Rate\Result;

class MyShip extends \Magento\Shipping\Model\Carrier\AbstractCarrier implements \Magento\Shipping\Model\Carrier\CarrierInterface {
    protected $_code = 'myship';

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

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

    protected $_logger;
    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->_logger = $logger;
        $this->_rateResultFactory = $rateResultFactory;
        $this->_rateMethodFactory = $rateMethodFactory;
        parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
    }

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

        //$message = $this->getConfigFlag('active')? 'yes' : 'no';
        $this->_logger->info($this->getConfigData('business_price'));

        $result = $this->_rateResultFactory->create();

        //check if express method is enabled 
        if($this->getConfigData('express_enabled')) {
            $method = $this->_rateMethodFactory->create();
            $method->setCarrier($this->_code);
            $method->setCarrierTitle($this->getConfigData('name'));
            $method->setMethod('express');
            $method->setMethodTitle($this->getConfigData('express_title'));
            $method->setPrice($this->getConfigData('express_price'));
            $method->setCost($this->getConfigData('express_price'));

            $result->append($method);
        }

        //check if business method is enabled 
        if($this->getConfigData('business_enabled')) {
            $method = $this->_rateMethodFactory->create();
            $method->setCarrier($this->_code);
            $method->setCarrierTitle($this->getConfigData('name'));
            $method->setMethod('business');
            $method->setMethodTitle($this->getConfigData('business_title'));
            $method->setPrice($this->getConfigData('business_price'));
            $method->setCost($this->getConfigData('business_price'));

            $result->append($method);
        }
        
        return $result;
    }

    public function getAllowedMethods() {
        return ['myship' => $this->getConfigData('name')];
    }

    public function isTrackingAvailable() {
        return true;
    }
}

The frontend shipping methods will be like following



I hope my tutorial will help you create you own shipping method easily.


comments powered by Disqus