Bhaveshpp

Professional Magento Developr - Healp eachother to grow

Magento 2: create shipping method with tracking

04 Jan 2022 » magento2, php

generate system setting

app/code/Firstflight/Firstship/etc/adminhtml/system.xml

<?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="firstship" translate="label" type="text" sortOrder="900" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>First flight</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="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Title</label>
                </field>
                <field id="name" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Method Name</label>
                </field>
                <field id="account_no" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Account number</label>
                </field>
                <field id="live_api_username" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Live API username</label>
                </field>
                <field id="live_api_password" translate="label" type="obscure" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Live API password</label>
                    <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
                </field>
                <field id="sendbox_mode" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Sendbox mode</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                    <frontend_class>is-sendbox-mode</frontend_class>
                </field>
                <field id="sendbox_api_username" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Sendbox API username</label>
                    <depends>
                        <field id="sendbox_mode">1</field>
                    </depends>
                </field>
                <field id="sendbox_api_password" translate="label" type="obscure" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Sendbox API password</label>
                    <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
                    <depends>
                        <field id="sendbox_mode">1</field>
                    </depends>
                </field>
                <field id="sallowspecific" translate="label" type="select" sortOrder="10" 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="select" sortOrder="10" 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="10" 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="service_type" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Service type</label>
                    <source_model>Firstflight\Firstship\Model\Config\Source\ServiceType</source_model>
                    <frontend_class>service-type</frontend_class>
                </field>
                <field id="shipping_type" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Shipping type</label>
                    <source_model>Firstflight\Firstship\Model\Config\Source\ShippingType</source_model>
                    <frontend_class>shipping-type</frontend_class>
                </field>
                <field id="sort_order" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Sort Order</label>
                </field>
            </group>
        </section>
    </system>
</config>

app/code/Firstflight/Firstship/etc/config.xml

<?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>
            <firstship>
                <active>0</active>
                <title>First Flight</title>
                <name>First Flight Shipping</name>
                <sallowspecific>0</sallowspecific>
                <sort_order>15</sort_order>
                <sendbox_api_password backend_model="Magento\Config\Model\Config\Backend\Encrypted" />
                <live_api_password backend_model="Magento\Config\Model\Config\Backend\Encrypted" />
                <model>Firstflight\Firstship\Model\Carrier</model>
            </firstship>
        </carriers>
    </default>
</config>

Carrier code

app/code/Firstflight/Firstship/Model/Carrier.php


<?php

namespace Firstflight\Firstship\Model;

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

/**
 * Custom shipping model
 */
class Carrier extends AbstractCarrier implements CarrierInterface
{
    /** @var string */
    protected $_methodCode = 'firstflight';
    
    /** @var string */
    protected $_carrierCode = 'firstship';

    /** @var string */
    protected $_code = 'firstship';

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

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

    /** @var \Magento\Framework\Url\EncoderInterface */
    protected $urlEncoder;

    /** @var \Firstflight\Firstship\Helper\Data */
    private $dataHelper;

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

    /**
     * construct
     *
     * @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 \Firstflight\Firstship\Helper\Data $dataHelper
     * @param \Magento\Framework\Url\EncoderInterface $urlEncoder
     * @param \Magento\Framework\UrlInterface $urlBuilder
     * @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,
        \Firstflight\Firstship\Helper\Data $dataHelper,
        \Magento\Framework\Url\EncoderInterface $urlEncoder,
        \Magento\Framework\UrlInterface $urlBuilder,
        array $data = []
    ) {
        parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
        $this->rateResultFactory = $rateResultFactory;
        $this->rateMethodFactory = $rateMethodFactory;
        $this->dataHelper = $dataHelper;
        $this->urlEncoder = $urlEncoder;
        $this->urlBuilder = $urlBuilder;
    }

    /**
     * Custom Shipping 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();

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

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

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

        $data = [
            'dest_country_id' => $request->getDestCountryId(),
            'package_weight' => $request->getPackageWeight(),
            'country_id' => $request->getCountryId()
        ];
        
        $rate = $this->dataHelper->getRateFinder($data);
        $shippingCost = (float)$rate['NetAmount'];

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

        $result->append($method);

        return $result;
    }

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

    /**
     * get tracking info object
     *
     * @param int $trackingNumber
     * @return \Magento\Framework\DataObject
     */
    public function getTrackingInfo($trackingNumber)
    {
        $tracking = new \Magento\Framework\DataObject();
        $tracking->setData([
            'carrier' => $this->_code,
            'carrier_title' => $this->getConfigData('title'),
            'tracking' => $trackingNumber,
            'url' => $this->_getTrackingUrl($trackingNumber)
        ]);
        return $tracking;
    }

    /**
     * get tracking url
     *
     * @param string $trackingNumber
     * @return string
     */
    protected function _getTrackingUrl($trackingNumber)
    {
        $params = [
            '_nosid' => true,
            '_direct' => 'firstflight/tracking/info',
            '_query' => ['hash' => $this->urlEncoder->encode($trackingNumber)]
        ];

        return $this->urlBuilder->getUrl('', $params);
    }
}

Thanks.