3

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)
    }
  }
}
  • 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. – Freddy Freddy May 9 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 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 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 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() ? – G Strato May 13 at 6:42
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......){}
| improve this answer | |
  • It won't help. Magento later do order of its own by price. See my answer. – G Strato May 14 at 9:15
1
+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().

| improve this answer | |
  • 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 at 21:44

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.