6

I'm utilizing the collectRates function in Magento2, to display custom shipping rates in the checkout.

This is working fine without any problems, while the weight of the products in the cart is 0. As soon as I add any weight to the products, the custom shipping rates are not showing anymore. collectRates is not even being called.

Has anyone had problems with this before? I'm getting no errors in the logs whatsoever.

This is the carrier class:

<?php

namespace Demo\Shipping\Model\Carrier;

use Magento\Quote\Model\Quote\Address\RateResult\Error;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Shipping\Model\Carrier\AbstractCarrierOnline;
use Magento\Shipping\Model\Carrier\CarrierInterface;
use Magento\Shipping\Model\Rate\Result;
use Magento\Shipping\Model\Simplexml\Element;
use Magento\Framework\Xml\Security;

class Demo extends AbstractCarrierOnline implements CarrierInterface
{
    protected $_request;
    protected $_result;
    protected $_localeFormat;
    protected $_code;
    protected $_logger;

    public function __construct(
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory,
        \Psr\Log\LoggerInterface $logger,
        Security $xmlSecurity,
        \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory,
        \Magento\Shipping\Model\Rate\ResultFactory $rateFactory,
        \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory,
        \Magento\Shipping\Model\Tracking\ResultFactory $trackFactory,
        \Magento\Shipping\Model\Tracking\Result\ErrorFactory $trackErrorFactory,
        \Magento\Shipping\Model\Tracking\Result\StatusFactory $trackStatusFactory,
        \Magento\Directory\Model\RegionFactory $regionFactory,
        \Magento\Directory\Model\CountryFactory $countryFactory,
        \Magento\Directory\Model\CurrencyFactory $currencyFactory,
        \Magento\Directory\Helper\Data $directoryData,
        \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
        \Magento\Framework\Locale\FormatInterface $localeFormat,
        \Demo\Shipping\Model\Api\DemoAPI $DemoApi,
        array $data = []
    ) {
        $this->_localeFormat = $localeFormat;
        $this->_DemoApi = $DemoApi;
        $this->_code = 'Demo';
        parent::__construct(
            $scopeConfig,
            $rateErrorFactory,
            $logger,
            $xmlSecurity,
            $xmlElFactory,
            $rateFactory,
            $rateMethodFactory,
            $trackFactory,
            $trackErrorFactory,
            $trackStatusFactory,
            $regionFactory,
            $countryFactory,
            $currencyFactory,
            $directoryData,
            $stockRegistry,
            $data
        );
    }

    protected function _doShipmentRequest(\Magento\Framework\DataObject $request) {}

    public function getAllowedMethods(){
    }

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

        // Getting delivery address street
        $street_address = $request->getDestStreet();

        // Prepare address 1
        $address_line = explode(PHP_EOL, $street_address);
        $address1 = !empty($address_line[0]) ? $address_line[0] : $street_address;
        $address2 = !empty($address_line[1]) ? $address_line[1] : '';

        $zip = $request->getDestPostcode();
        $city = $request->getDestCity();
        $country_code = $request->getDestCountryId();
        $state = $request->getDestRegionCode();

        // Prepare delivery_address for quote
        $delivery_address = array(
            'address_1' => $address1,
            'address_2' => $address2,
            'zip' => $zip,
            'city' => $city,
            'country_code' => $country_code,
            'state' => $state
        );

        // Getting cart items
        $items = $request->getAllItems();

        $price = $request->getPackageValue();
        $weight = $request->getPackageWeight();

        $shipping_rates = $this->_demoApi->quoteRates(
            $delivery_address,
            $items,
            $price,
            $weight
        );
        if ($shipping_rates) {
            foreach ($shipping_rates as $rate) {
                if ($rate['shipping_rate']['require_drop_point']) {
                    $droppoints = $this->_DemoApi->getDroppoints(
                        $rate['shipping_rate']['id'],
                        $address1,
                        $zip,
                        $city,
                        $country_code,
                        $state
                    );
                    if (isset($droppoints) && is_array($droppoints)) {

                        // Get maximum number of droppoints from settings
                        $dp_limit = $this->getDroppointLimit();
                        if ((int)$dp_limit > 0) {
                            $dp_limit = (int)$dp_limit;
                        } else {
                            $dp_limit = 5;
                        }

                        // Loop through droppoints and generate shipping rate for each
                        foreach($droppoints as $index => $droppoint) {
                            if (((int)$index + 1) > $dp_limit)
                                break;

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

                            $method->setCarrier($this->_code);
                            $method->setCarrierTitle($rate['carrier_name']);

                            $method_code = $rate['shipping_rate']['id']."_".$droppoint['drop_point_id'];

                            $method->setMethod($method_code);
                            $method->setMethodTitle(
                                $rate['shipping_rate']['name'].' '.
                                $droppoint['name'].' '.
                                $droppoint['address_1'].' '.
                                $droppoint['country_code'].'-'.
                                $droppoint['zip']
                            );

                            $method->setPrice($rate['price']);
                            $method->setCost($rate['price']);

                            $result->append($method);
                        }
                    }
                } else {
                    $method = $this->_rateMethodFactory->create();

                    $method->setCarrier($this->_code);
                    $method->setCarrierTitle($rate['carrier_name']);

                    $method_code = $rate['shipping_rate']['id'];

                    $method->setMethod($method_code);
                    $method->setMethodTitle($rate['shipping_rate']['name']);

                    $method->setPrice($rate['price']);
                    $method->setCost($rate['price']);

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

    private function getDroppointLimit() {
        return $this->_scopeConfig->getValue(
            'carriers/Demo/droppoint_limit',
            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
        );
    }
}
  • I am also having the same issue. When using Online shipping method using extend the class "AbstractCarrierOnline" for creating shipping labels, If product weight is greater then 0 it does not show any method, even not getting any error/log. – Neeraj Garg Jun 10 at 11:03
7

I have got the solution, this is because we need to define processAdditionalValidation method inside the carrier class and for checking the result you can return true in this function.

 public function processAdditionalValidation(\Magento\Framework\DataObject $request) {
    return true;
 }

Please note processAdditionalValidation is different than proccessAdditionalValidation

  • I had to compare word by word. Seriously, wtf magento? – Vivek Kumar Jun 17 at 6:57
4
+25

Without all the code related to the carrier such as the XML, it's hard to give you a definite answer.

But if your carrier is disappearing when the weight is over 0, then I would suspect you have not set the max_package_weight property in the XML. Or set it to an invalid value like a negative.

If you have tried Neeraj Garg's solution and it worked for you, then this would support this idea. Since the processAdditionalValidation method is responsible for two bits of validation.

  • Calculating if the current weight of the products exceed that of the carrier's max weight
  • Checking if the shipping postcode is missing when it is a mandatory field for the country.

The reason I would assume this is in processAdditionalValidation it pulls the carriers/{carriercode}/max_package_weight value from the store config and casts it into a double data type.

If you cast the max_package_weight property in the XML it will return NULL and when you case NULL into a double you get 0.

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.