4

I'm trying to build a custom carrier-class (shipping method) that display shipping methods based on time/date related third party API, I tried to find out a solution to sort the below options but I failed

Has anyone faced such an issue? How does Magento sort these options?

Any help is really appreciated!

Thanks

Shipping carrier - custom class - time related shipping

adding code sample :

    /**
     * {@inheritdoc}
     */
    public function collectRates(RateRequest $request)
    {
        if (!$this->getConfigFlag('active')) {
            return false;
        }
        try {
            // get current quote id
            $quoteId = false;
            $items = $request->getAllItems();
            foreach ($items  as $item) {
                $quoteId = $item->getQuoteId();
                break;
            }
            /**  Quote $quote */
            $quote = $this->quoteFactory->create()->load($quoteId);
            $shippingAddress = $quote->getShippingAddress();
            $lat = (float) $shippingAddress->getData('latitude');
            $lng = (float) $shippingAddress->getData('longitude');
            if (!$lat || !$lng) {
                return false;
            }

            $isIn = $this->descartes->IsIn($lat, $lng);
            if (!$isIn) {
                // @todo handle logging here
                return false;
            }


            $shippingPrice = 10 ;
            $result = $this->_rateResultFactory->create();
            $slotsData = $this->descartes->getAvailableSlots();
            $lockBelow = (int) $this->getConfigData('capacitylock');
            $i = 1;

            foreach ($slotsData as $date => $slots) {
                foreach ($slots as $time => $slot_info) {
                    $capacity = (int) $slot_info['available_capacity'];
                    $id = (int) $slot_info['id'];
                    if ($capacity <= 0) {
                        continue;
                    }
                    switch ($capacity) {

                        case $capacity > $lockBelow:
                            $i = sprintf('%02d', $i);
                            /** @var Method $rate */
                            $rate = $this->_rateMethodFactory->create();
                            $rate->setCarrier($this->_code);
                            $rate->setCarrierTitle($this->getConfigData('title'));
                            $rate->setMethod($id);
                            $rate->setMethodTitle($date . "_" . $time);
                            $rate->setPrice($shippingPrice);
                            $rate->setCost($shippingPrice);
                            $rate->setSortOrder($i);
                            $result->append($rate);
                            break;
                    }
                    $i++;
                }
            }
            return $result;
        } catch (\Exception $e) {
            $this->manager->addErrorMessage($e->getMessage());
            return false;
        }
    }

sample slots API response :

array(2) {
  ["2020-05-13"]=>
  array(7) {
    ["2:00 PM-4:00 PM"]=>
    array(2) {
      ["id"]=>
      int(568)
      ["available_capacity"]=>
      int(-1)
    }
    ["4:00 PM-6:00 PM"]=>
    array(2) {
      ["id"]=>
      int(570)
      ["available_capacity"]=>
      int(24)
    }
    ["6:00 PM-8:00 PM"]=>
    array(2) {
      ["id"]=>
      int(555)
      ["available_capacity"]=>
      int(25)
    }
    ["8:00 PM-10:00 PM"]=>
    array(2) {
      ["id"]=>
      int(566)
      ["available_capacity"]=>
      int(25)
    }
    ["10:00 AM-11:59 AM"]=>
    array(2) {
      ["id"]=>
      int(482)
      ["available_capacity"]=>
      int(25)
    }
    ["10:00 PM-11:59 PM"]=>
    array(2) {
      ["id"]=>
      int(671)
      ["available_capacity"]=>
      int(25)
    }
    ["12:00 PM-2:00 PM"]=>
    array(2) {
      ["id"]=>
      int(678)
      ["available_capacity"]=>
      int(25)
    }
  }
  ["2020-05-14"]=>
  array(7) {
    ["2:00 PM-4:00 PM"]=>
    array(2) {
      ["id"]=>
      int(568)
      ["available_capacity"]=>
      int(25)
    }
    ["4:00 PM-6:00 PM"]=>
    array(2) {
      ["id"]=>
      int(570)
      ["available_capacity"]=>
      int(25)
    }
    ["6:00 PM-8:00 PM"]=>
    array(2) {
      ["id"]=>
      int(555)
      ["available_capacity"]=>
      int(25)
    }
    ["8:00 PM-10:00 PM"]=>
    array(2) {
      ["id"]=>
      int(566)
      ["available_capacity"]=>
      int(25)
    }
    ["10:00 AM-11:59 AM"]=>
    array(2) {
      ["id"]=>
      int(482)
      ["available_capacity"]=>
      int(25)
    }
    ["10:00 PM-11:59 PM"]=>
    array(2) {
      ["id"]=>
      int(671)
      ["available_capacity"]=>
      int(25)
    }
    ["12:00 PM-2:00 PM"]=>
    array(2) {
      ["id"]=>
      int(678)
      ["available_capacity"]=>
      int(25)
    }
  }
}
10
  • Can you show us the code that displays this, it may be that in the query you just have to put an 'order by' or just sort the table that contains this data. May 9, 2020 at 2:49
  • There is no db queries , I'm using an api to get the time slots and the api return them sorted by date and time , I'm just looping throw them one by one and add them as rate object to the result object
    – tawfekov
    May 9, 2020 at 6:26
  • As I remember magento sort the methods by price, but in your scenario all the returned methods have the same price. You should create your own sort option in the custom carrier class by the field you want (probably date).
    – Adam S.
    May 9, 2020 at 11:42
  • @AdamS. what is the method/class should I implement ? can you please name it , is it in the core ?
    – tawfekov
    May 9, 2020 at 18:09
  • 1
    First need to see code how you create those shipping methods. Then I guess I can answer. But I need to see code, part where you set it, I guess it will be collectRates() ? May 13, 2020 at 6:42

2 Answers 2

3
+50

Ok, take a look here:

vendor/magento/module-shipping/Model/Rate/Result.php

There is function sortRatesByPrice(); This foreach puts all in array for sorting:

foreach ($this->_rates as $i => $rate) {
        $tmp[$i] = $rate->getPrice();
    }

If you change this $rate->getPrice() to $rate->getMethodTitle() it will sort by method title, that in your case is date and time. I haven't looked deeper, but you can try to do plugin here or overwrite with preference. Just try and see. I think you will manage how to sort now. That sortRatesByPrice() is called here vendor/magento/module-shipping/Model/Rate/CarrierResult.php, function public function getAllRates().

3
  • I believe this is the right method to write a plugin after it and apply a custom order there , I'll try to work on an example after this weekend
    – tawfekov
    May 17, 2020 at 21:44
  • This approach works i.e. replacing $rate->getPrice() with $rate->getMethodTitle(). It will then sort the rates by method title.
    – phagento
    Nov 2, 2020 at 8:27
  • Hi KestutisK magento.stackexchange.com/questions/327438/… can u advise me Dec 4, 2020 at 13:32
1

I think you can simply sort first the array before your foreach using at least asort()

asort() - sort associative arrays in ascending order:

asort($slotsData)  
foreach ($slotsData......){}
1
  • It won't help. Magento later do order of its own by price. See my answer. May 14, 2020 at 9:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.