From 5d71c85cc020f9db5753213fce46620f15cb94d1 Mon Sep 17 00:00:00 2001
From: Gundo Sifhufhi <sifhufhisg@gmail.com>
Date: Mon, 9 Jan 2023 13:28:01 +0200
Subject: [PATCH] Change of Admin config fields Change of Parent Class usage
 from `AbstractCarrier` to `AbstractCarrierOnline` Access Store
 ManagerInterface Remove Unnecessary configurations for the Extension

---
 .../Model/Carrier/Customshipping.php          | 1053 +++++++++++------
 .../Customshipping/etc/adminhtml/system.xml   |   80 +-
 uafrica/Customshipping/etc/config.xml         |    2 +-
 3 files changed, 664 insertions(+), 471 deletions(-)

diff --git a/uafrica/Customshipping/Model/Carrier/Customshipping.php b/uafrica/Customshipping/Model/Carrier/Customshipping.php
index ce5e20f..00233a6 100644
--- a/uafrica/Customshipping/Model/Carrier/Customshipping.php
+++ b/uafrica/Customshipping/Model/Carrier/Customshipping.php
@@ -2,242 +2,411 @@
 
 namespace uafrica\Customshipping\Model\Carrier;
 
+use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
+use Magento\CatalogInventory\Api\StockRegistryInterface;
+use Magento\Directory\Helper\Data;
+use Magento\Directory\Model\CountryFactory;
+use Magento\Directory\Model\CurrencyFactory;
+use Magento\Directory\Model\RegionFactory;
 use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\Controller\Result\JsonFactory;
 use Magento\Framework\DataObject;
-use Magento\Shipping\Model\Carrier\AbstractCarrier;
-use Magento\Shipping\Model\Carrier\CarrierInterface;
-use Magento\Shipping\Model\Rate\ResultFactory;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\HTTP\Client\CurlFactory;
+use Magento\Framework\Module\Dir\Reader;
+use Magento\Framework\Xml\Security;
+use Magento\Quote\Model\Quote\Address\RateRequest;
 use Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory;
-use Magento\Quote\Model\Quote\Address\RateResult\Method;
 use Magento\Quote\Model\Quote\Address\RateResult\MethodFactory;
-use Magento\Quote\Model\Quote\Address\RateRequest;
+use Magento\Shipping\Model\Carrier\AbstractCarrier;
+use Magento\Shipping\Model\Carrier\AbstractCarrierOnline;
+use Magento\Shipping\Model\Rate\Result;
+use Magento\Shipping\Model\Rate\ResultFactory;
+use Magento\Shipping\Model\Simplexml\ElementFactory;
+use Magento\Shipping\Model\Tracking\Result\StatusFactory;
+use Magento\Store\Model\StoreManagerInterface;
 use Psr\Log\LoggerInterface;
-use Magento\Framework\Controller\Result\JsonFactory;
-use Magento\Framework\HTTP\Client\CurlFactory;
 
 /**
+ * uAfrica shipping implementation
  * @category   uafrica
  * @package    uafrica_Customshipping
  * @author     info@bob.co.za
  * @website    https://www.bob.co.za
+ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.TooManyFields)
  */
-class Customshipping extends AbstractCarrier implements CarrierInterface
+class Customshipping extends AbstractCarrierOnline implements \Magento\Shipping\Model\Carrier\CarrierInterface
 {
+    /**
+     * Code of the carrier
+     *`
+     * @var string
+     */
+    public const CODE = 'uafrica';
+
     /** Tracking Endpoint */
     const TRACKING = 'https://api.dev.ship.uafrica.com/tracking?channel=localhost&tracking_reference=';
     /*** RATES API Endpoint*/
     const RATES_ENDPOINT = 'https://8390956f-c00b-497d-8742-87b1d6305bd2.mock.pstmn.io/putrates';
 
+
+    /**
+     * Purpose of rate request
+     *
+     * @var string
+     */
+    public const RATE_REQUEST_GENERAL = 'general';
+
+    /**
+     * Purpose of rate request
+     *
+     * @var string
+     */
+    public const RATE_REQUEST_SMARTPOST = 'SMART_POST';
+
     /**
-     * Carrier's code
+     * Code of the carrier
      *
      * @var string
      */
-    protected $_code = 'uafrica';
+    protected $_code = self::CODE;
+
+    /**
+     * Types of rates, order is important
+     *
+     * @var array
+     */
+    protected $_ratesOrder = [
+        'RATED_ACCOUNT_PACKAGE',
+        'PAYOR_ACCOUNT_PACKAGE',
+        'RATED_ACCOUNT_SHIPMENT',
+        'PAYOR_ACCOUNT_SHIPMENT',
+        'RATED_LIST_PACKAGE',
+        'PAYOR_LIST_PACKAGE',
+        'RATED_LIST_SHIPMENT',
+        'PAYOR_LIST_SHIPMENT',
+    ];
+
+    /**
+     * Rate request data
+     *
+     * @var RateRequest|null
+     */
+    protected $_request = null;
 
     /**
-     * Whether this carrier has fixed rates calculation
+     * Rate result data
      *
-     * @var bool
+     * @var Result|null
      */
-    protected $_isFixed = false;
+    protected $_result = null;
 
     /**
-     * @var ResultFactory
+     * Path to wsdl file of rate service
+     *
+     * @var string
      */
-    protected $_rateResultFactory;
+    protected $_rateServiceWsdl;
 
     /**
-     * @var MethodFactory
+     * Path to wsdl file of ship service
+     *
+     * @var string
      */
-    protected $_rateMethodFactory;
+    protected $_shipServiceWsdl = null;
 
     /**
-     * @var \Magento\Framework\Controller\Result\JsonFactory
+     * Path to wsdl file of track service
+     *
+     * @var string
      */
-    protected $jsonFactory;
+    protected $_trackServiceWsdl = null;
+
+    /**
+     * Container types that could be customized for uAfrica carrier
+     *
+     * @var string[]
+     */
+    protected $_customizableContainerTypes = ['YOUR_PACKAGING'];
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface
+     */
+    protected $_storeManager;
+
+    /**
+     * @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory
+     */
+    protected $_productCollectionFactory;
+
+
+    /**
+     * @var DataObject
+     */
+    private $_rawTrackingRequest;
 
     /**
      * @var \Magento\Framework\HTTP\Client\Curl
      */
-    protected $curl;
+    protected \Magento\Framework\HTTP\Client\Curl $curl;
 
 
     /**
      * @param \Magento\Framework\Controller\Result\JsonFactory $jsonFactory
      */
+    protected JsonFactory $jsonFactory;
+
 
     /**
      * @param ScopeConfigInterface $scopeConfig
      * @param ErrorFactory $rateErrorFactory
      * @param LoggerInterface $logger
-     * @param ResultFactory $rateResultFactory
+     * @param Security $xmlSecurity
+     * @param ElementFactory $xmlElFactory
+     * @param ResultFactory $rateFactory
      * @param MethodFactory $rateMethodFactory
+     * @param \Magento\Shipping\Model\Tracking\ResultFactory $trackFactory
+     * @param \Magento\Shipping\Model\Tracking\Result\ErrorFactory $trackErrorFactory
+     * @param StatusFactory $trackStatusFactory
+     * @param RegionFactory $regionFactory
+     * @param CountryFactory $countryFactory
+     * @param CurrencyFactory $currencyFactory
+     * @param Data $directoryData
+     * @param StockRegistryInterface $stockRegistry
+     * @param StoreManagerInterface $storeManager
+     * @param Reader $configReader
+     * @param CollectionFactory $productCollectionFactory
+     * @param JsonFactory $jsonFactory
+     * @param CurlFactory $curlFactory
      * @param array $data
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
-        ScopeConfigInterface $scopeConfig,
-        ErrorFactory $rateErrorFactory,
-        LoggerInterface $logger,
-        ResultFactory $rateResultFactory,
-        MethodFactory $rateMethodFactory,
+        \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\Store\Model\StoreManagerInterface $storeManager,
+        \Magento\Framework\Module\Dir\Reader $configReader,
+        \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
         JsonFactory $jsonFactory,
         CurlFactory $curlFactory,
         array $data = []
+
     ) {
+
+        $this->_storeManager = $storeManager;
+        $this->_productCollectionFactory = $productCollectionFactory;
+        parent::__construct(
+            $scopeConfig,
+            $rateErrorFactory,
+            $logger,
+            $xmlSecurity,
+            $xmlElFactory,
+            $rateFactory,
+            $rateMethodFactory,
+            $trackFactory,
+            $trackErrorFactory,
+            $trackStatusFactory,
+            $regionFactory,
+            $countryFactory,
+            $currencyFactory,
+            $directoryData,
+            $stockRegistry,
+            $data
+        );
         $this->jsonFactory = $jsonFactory;
         $this->curl = $curlFactory->create();
-        $this->_rateResultFactory = $rateResultFactory;
-        $this->_rateMethodFactory = $rateMethodFactory;
-        parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
     }
 
 
     /**
-     *  Allow Admin/User to track shipment from admin panel or frontend  order page i.e popup
-     *  @return bool
+     *  Make request to uAfrica API to get shipping rates
+     * @param $payload
+     * @return array
      */
-    public function isTrackingAvailable(): bool
+    public function getRates($payload): array
     {
-        return true;
+        $response = $this->uRates($payload);
+
+        return $response;
     }
 
     /**
-     * Get allowed shipping methods
+     * Collect and get rate
+     * @param RateRequest $request
+     * @return Result|bool|null
+     */
+    public function collectRates(RateRequest $request)
+    {
+       /*** Make sure that Shipping method is enabled*/
+        if (!$this->isActive()) {
+            return false;
+        }
+
+        /** @var \Magento\Shipping\Model\Rate\Result $result */
+
+        $result = $this->_rateFactory->create();
+
+        $destination = $request->getDestPostcode();
+        $destCountry = $request->getDestCountryId();
+        $destRegion = $request->getDestRegionCode();
+        $destCity = $request->getDestCity();
+        $destStreet = $request->getDestStreet();
+        $destStreet1 = $destStreet;
+        $destStreet2 = $destStreet;
+
+        //Get all the origin data from the request
+        $origin = $this->getConfigData('origin_postcode');
+        $originCountry = $this->getConfigData('origin_country_id');
+        $originRegion = $this->getConfigData('origin_region_id');
+        $originCity = $this->getConfigData('origin_city');
+        $originStreet = $this->getConfigData('origin_street');
+        //URL to get the rates from
+        $url = $this->getConfigData('rates_endpoint');
+        $originStreet1 = $originStreet;
+        $originStreet2 = $originStreet;
+
+
+        $items = $request->getAllItems();
+
+        $itemsArray = [];
+
+        foreach ($items as $item) {
+            $itemsArray[] = [
+                'name' => $item->getName(),
+                'sku' => $item->getSku(),
+                'quantity' => $item->getQty(),
+                'price' => $item->getPrice(),
+                'grams' => $item->getWeight() * 1000,
+                'requires_shipping' => $item->getIsVirtual(),
+                'taxable' => true,
+                'fulfillment_service' => 'manual',
+                'properties' => [],
+                'vendor' => $item->getStoreId(),
+                'product_id' => $item->getProductId(),
+                'variant_id' => $item->getProduct()->getId()
+            ];
+        }
+
+        $payload = [
+            'rate' => [
+                'origin' => [
+                    'country' => $originCountry,
+                    'postal_code' => $origin,
+                    'province' => $originRegion,
+                    'city' => $originCity,
+                    'name' => $url,
+                    'address1' => $originStreet1,
+                    'address2' => $originStreet2,
+                    'address3' => '',
+                    'phone' => '+27313039670',
+                    'fax' => '',
+                    'email' => '',
+                    'address_type' => '',
+                    'company_name' => 'Jam Clothing'
+                ],
+                'destination' => [
+                    'country' => $destCountry,
+                    'postal_code' => $destination,
+                    'province' => $destRegion,
+                    'city' => $destCity,
+                    'name' => 'Brian Singh',
+                    'address1' => $destStreet1,
+                    'address2' => $destStreet2,
+                    'address3' => '',
+                    'phone' => '081 346 5923',
+                    'fax' => '',
+                    'email' => '',
+                    'address_type' => '',
+                    'company_name' => ''
+                ],
+                'items' => $itemsArray,
+                'currency' => 'ZAR',
+                'locale' => 'en-PT'
+            ]
+        ];
+
+        $this->_getRates($payload, $result);
+
+        return $result;
+    }
+
+
+    /**
+     * Get result of request
      *
-     *  @param string $type
-     *  @param string $code
-     *  @param array|false
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * @return Result|null
+     */
+    public function getResult()
+    {
+        if (!$this->_result) {
+            $this->_result = $this->_trackFactory->create();
+        }
+        return $this->_result;
+    }
+
+    /**
+     * Get final price for shipping method with handling fee per package
+     *
+     * @param float $cost
+     * @param string $handlingType
+     * @param float $handlingFee
+     * @return float
+     */
+    protected function _getPerpackagePrice($cost, $handlingType, $handlingFee)
+    {
+        if ($handlingType == AbstractCarrier::HANDLING_TYPE_PERCENT) {
+            return $cost + $cost * $this->_numBoxes * $handlingFee / 100;
+        }
+
+        return $cost + $this->_numBoxes * $handlingFee;
+    }
+
+    /**
+     * Get final price for shipping method with handling fee per order
+     *
+     * @param float $cost
+     * @param string $handlingType
+     * @param float $handlingFee
+     * @return float
+     */
+    protected function _getPerorderPrice($cost, $handlingType, $handlingFee)
+    {
+        if ($handlingType == self::HANDLING_TYPE_PERCENT) {
+            return $cost + $cost * $handlingFee / 100;
+        }
+
+        return $cost + $handlingFee;
+    }
+
+
+    /**
+     * Get configuration data of carrier
+     *
+     * @param string $type
+     * @param string $code
+     * @return array|false
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
-    public function getCode($type, string $code = '')
+    public function getCode($type, $code = '')
     {
         $codes = [
             'method' => [
-                'uafrica_FIRST_INTERNATIONAL_PRIORITY' => __('uafrica First Priority'),
-                'uafrica_1_DAY_FREIGHT' => __('1 Day Freight'),
-                'uafrica_2_DAY_FREIGHT' => __('2 Day Freight'),
-                'uafrica_2_DAY' => __('2 Day'),
-                'uafrica_2_DAY_AM' => __('2 Day AM'),
-                'uafrica_3_DAY_FREIGHT' => __('3 Day Freight'),
-                'uafrica_EXPRESS_SAVER' => __('Express Saver'),
-                'uafrica_GROUND' => __('Ground'),
-                'FIRST_OVERNIGHT' => __('First Overnight'),
-                'GROUND_HOME_DELIVERY' => __('Home Delivery'),
-                'INTERNATIONAL_ECONOMY' => __('International Economy'),
-                'INTERNATIONAL_ECONOMY_FREIGHT' => __('Intl Economy Freight'),
-                'INTERNATIONAL_FIRST' => __('International First'),
-                'INTERNATIONAL_GROUND' => __('International Ground'),
-                'INTERNATIONAL_PRIORITY' => __('International Priority'),
-                'INTERNATIONAL_PRIORITY_FREIGHT' => __('Intl Priority Freight'),
-                'PRIORITY_OVERNIGHT' => __('Priority Overnight'),
-                'SMART_POST' => __('Smart Post'),
-                'STANDARD_OVERNIGHT' => __('Standard Overnight'),
-                'uafrica_FREIGHT' => __('Freight'),
-                'uafrica_NATIONAL_FREIGHT' => __('National Freight'),
-            ],
-            'dropoff' => [
-                'REGULAR_PICKUP' => __('Regular Pickup'),
-                'REQUEST_COURIER' => __('Request Courier'),
-                'DROP_BOX' => __('Drop Box'),
-                'BUSINESS_SERVICE_CENTER' => __('Business Service Center'),
-                'STATION' => __('Station'),
-            ],
-            'packaging' => [
-                'uafrica_ENVELOPE' => __('uafrica Envelope'),
-                'uafrica_PAK' => __('uafrica Pak'),
-                'uafrica_BOX' => __('uafrica Box'),
-                'uafrica_TUBE' => __('uafrica Tube'),
-                'uafrica_10KG_BOX' => __('uafrica 10kg Box'),
-                'uafrica_25KG_BOX' => __('uafrica 25kg Box'),
-                'YOUR_PACKAGING' => __('Your Packaging'),
-            ],
-            'containers_filter' => [
-                [
-                    'containers' => ['uafrica_ENVELOPE', 'uafrica_PAK'],
-                    'filters' => [
-                        'within_us' => [
-                            'method' => [
-                                'uafrica_EXPRESS_SAVER',
-                                'uafrica_2_DAY',
-                                'uafrica_2_DAY_AM',
-                                'STANDARD_OVERNIGHT',
-                                'PRIORITY_OVERNIGHT',
-                                'FIRST_OVERNIGHT',
-                            ],
-                        ],
-                        'from_us' => [
-                            'method' => ['INTERNATIONAL_FIRST', 'INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY'],
-                        ],
-                    ],
-                ],
-                [
-                    'containers' => ['uafrica_BOX', 'uafrica_TUBE'],
-                    'filters' => [
-                        'within_us' => [
-                            'method' => [
-                                'uafrica_2_DAY',
-                                'uafrica_2_DAY_AM',
-                                'STANDARD_OVERNIGHT',
-                                'PRIORITY_OVERNIGHT',
-                                'FIRST_OVERNIGHT',
-                                'uafrica_FREIGHT',
-                                'uafrica_1_DAY_FREIGHT',
-                                'uafrica_2_DAY_FREIGHT',
-                                'uafrica_3_DAY_FREIGHT',
-                                'uafrica_NATIONAL_FREIGHT',
-                            ],
-                        ],
-                        'from_us' => [
-                            'method' => ['INTERNATIONAL_FIRST', 'INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY'],
-                        ],
-                    ],
-                ],
-                [
-                    'containers' => ['uafrica_10KG_BOX', 'uafrica_25KG_BOX'],
-                    'filters' => [
-                        'within_us' => [],
-                        'from_us' => ['method' => ['INTERNATIONAL_PRIORITY']],
-                    ],
-                ],
-                [
-                    'containers' => ['YOUR_PACKAGING'],
-                    'filters' => [
-                        'within_us' => [
-                            'method' => [
-                                'uafrica_GROUND',
-                                'GROUND_HOME_DELIVERY',
-                                'SMART_POST',
-                                'uafrica_EXPRESS_SAVER',
-                                'uafrica_2_DAY',
-                                'uafrica_2_DAY_AM',
-                                'STANDARD_OVERNIGHT',
-                                'PRIORITY_OVERNIGHT',
-                                'FIRST_OVERNIGHT',
-                                'uafrica_FREIGHT',
-                                'uafrica_1_DAY_FREIGHT',
-                                'uafrica_2_DAY_FREIGHT',
-                                'uafrica_3_DAY_FREIGHT',
-                                'uafrica_NATIONAL_FREIGHT',
-                            ],
-                        ],
-                        'from_us' => [
-                            'method' => [
-                                'INTERNATIONAL_FIRST',
-                                'INTERNATIONAL_ECONOMY',
-                                'INTERNATIONAL_PRIORITY',
-                                'INTERNATIONAL_GROUND',
-                                'uafrica_FREIGHT',
-                                'uafrica_1_DAY_FREIGHT',
-                                'uafrica_2_DAY_FREIGHT',
-                                'uafrica_3_DAY_FREIGHT',
-                                'uafrica_NATIONAL_FREIGHT',
-                                'INTERNATIONAL_ECONOMY_FREIGHT',
-                                'INTERNATIONAL_PRIORITY_FREIGHT',
-                            ],
-                        ],
-                    ],
-                ],
+                'UAFRICA_SHIPPING' => __('uAfrica Shipping'),
             ],
             'delivery_confirmation_types' => [
                 'NO_SIGNATURE_REQUIRED' => __('Not Required'),
@@ -246,7 +415,6 @@ class Customshipping extends AbstractCarrier implements CarrierInterface
                 'INDIRECT' => __('Indirect'),
             ],
             'unit_of_measure' => [
-                'LB' => __('Pounds'),
                 'KG' => __('Kilograms'),
             ],
         ];
@@ -262,291 +430,394 @@ class Customshipping extends AbstractCarrier implements CarrierInterface
         } else {
             return $codes[$type][$code];
         }
-
     }
 
+
     /**
-     * Whether this carrier has shipping labels
+     * Get tracking
+     *
+     * @param string|string[] $trackings
+     * @return Result|null
      */
-    public function isShippingLabelsAvailable(): bool
+    public function getTracking($trackings)
     {
-        return true;
+        $this->setTrackingReqeust();
+
+        if (!is_array($trackings)) {
+            $trackings = [$trackings];
+        }
+
+        foreach ($trackings as $tracking) {
+            $this->_getXMLTracking($tracking);
+        }
+
+        return $this->_result;
     }
 
     /**
-     * @param string $tracking
-     * @return DataObject
+     * Set tracking request
+     *
+     * @return void
      */
-    public function getTrackingInfo($tracking): DataObject
+    protected function setTrackingReqeust()
     {
-        //Not Used Yet On This Phase of Development
-        //  $result = $this->_trackFactory->create();
-        $result = new DataObject();
-        //Insert tracking code dynamically here
-        $result->setUrl(self::TRACKING.$tracking);
-        $result->setTracking($tracking);
+        $r = new \Magento\Framework\DataObject();
 
-        $result->setCarrierTitle($this->getConfigData('title'));
+        $account = $this->getConfigData('account');
+        $r->setAccount($account);
 
-        //Perform curl request to get tracking info from uAfrica API
-        //Inject tracking code into the url dynamically
-        $this->curl->get(self::TRACKING.$tracking);
+        $this->_rawTrackingRequest = $r;
+    }
 
-        $response = $this->curl->getBody();
+    /**
+     * Send request for tracking
+     *
+     * @param string[] $tracking
+     * @return void
+     */
+    protected function _getXMLTracking($tracking)
+    {
+        $this->_parseTrackingResponse($tracking);
+    }
 
-        $response = json_decode($response, true);
+    /**
+     * Parse tracking response
+     *
+     * @param string $trackingValue
+     * @return void
+     */
+    protected function _parseTrackingResponse($trackingValue)
+    {
 
-        $result->addData((array)$response);
-        /**1. Image to be dynamic in the next phase
-         * 2. Tracking status to be dynamic in the next phase
-         * 3. This method feels hacky, not sure if I will need to refactor, but it works for now,
-         * I am open for suggestions.
-         */
-        echo "<pre>";
-                print_r("
-        <img src='https://ik.imagekit.io/z1viz85yxs/dev-v3/provider-logos/devpanda_logo.png' alt='Dev Panda' width='100' height='100'>
-
-                <table '>
-                <tr>
-                <th>Order Number</th>
-                <th>Order Date</th>
-                <th>Order Status</th>
-                </tr>
-                <tr>
-                <td>".$response[0]['order_number']."</td>
-                <td>".$response[0]['shipment_time_created']."</td>
-                <td>".$response[0]['status_friendly']."</td>
-                </tr>
-                </table>
-
-                <h4>Tracking</h4>
-                <table>
-                <tr>
-                <th>Tracking Number</th>
-                <th>Tracking Status</th>
-                <th>Tracking Date</th>
-                </tr>
-                <tr>
-                <td>".$response[0]['shipment_tracking_reference']."</td>
-                <td>".$response[0]['status_friendly']."</td>
-                <td>".$response[0]['last_checkpoint_time']."</td>
-                </tr>
-                </table>
-
-        ");
-
-      print_r(" <h4>Checkpoints</h4>
-        <table>
-            <tr>
-                <th>Status</th>
-                <th>Status Friendly</th>
-                <th>Country</th>
-                <th>Zone</th>
-                <th>City</th>
-                <th>Zip</th>
-                <th>Location</th>
-                <th>Message</th>
-                <th>Time</th>
-            </tr>"
-      );
-        foreach ($response[0]['checkpoints'] as $checkpoint) {
-            print_r("<tr>
-                <td>" . $checkpoint['status'] . "</td>
-                <td>" . $checkpoint['status_friendly'] . "</td>
-                <td>" . $checkpoint['country'] . "</td>
-                <td>" . $checkpoint['zone'] . "</td>
-                <td>" . $checkpoint['city'] . "</td>
-                <td>" . $checkpoint['zip'] . "</td>
-                <td>" . $checkpoint['location'] . "</td>
-                <td>" . $checkpoint['message'] . "</td>
-                <td>" . $checkpoint['time'] . "</td>
-            </tr>
-            ");
+        $result = $this->getResult();
+        $carrierTitle = $this->getConfigData('title');
+        $counter = 0;
+        if (!is_array($trackingValue)) {
+            $trackingValue = [$trackingValue];
+        }
+        foreach ($trackingValue as $item) {
+            $tracking = $this->_trackStatusFactory->create();
+
+            $tracking->setCarrier(self::CODE);
+            $tracking->setCarrierTitle($carrierTitle);
+            $tracking->setUrl(self::TRACKING.$item);
+            $tracking->setTracking($item);
+            $tracking->addData($this->processTrackingDetails($item));
+            $result->append($tracking);
+            $counter ++;
+        }
 
+        // no available tracking details
+        if (!$counter) {
+            $this->appendTrackingError(
+                $trackingValue,
+                __('For some reason we can\'t retrieve tracking info right now.')
+            );
         }
-       print_r("</table>");
+    }
 
-        echo "</pre>";
+    /**
+     * Get tracking response
+     *
+     * @return string
+     */
+    public function getResponse()
+    {
+        $statuses = '';
+        if ($this->_result instanceof \Magento\Shipping\Model\Tracking\Result) {
+            if ($trackings = $this->_result->getAllTrackings()) {
+                foreach ($trackings as $tracking) {
+                    if ($data = $tracking->getAllData()) {
+                        if (!empty($data['status'])) {
+                            $statuses .= __($data['status']) . "\n<br/>";
+                        } else {
+                            $statuses .= __('Empty response') . "\n<br/>";
+                        }
+                    }
+                }
+            }
+        }
+        // phpstan:ignore
+        if (empty($statuses)) {
+            $statuses = __('Empty response');
+        }
 
-        return $result;
+        return $statuses;
     }
 
     /**
-     * @return string
+     * Get allowed shipping methods
+     *
+     * @return array
      */
-    private function getApiUrl(): string
+    public function getAllowedMethods()
     {
+        $allowed = explode(',', $this->getConfigData('allowed_methods'));
+        $arr = [];
+        foreach ($allowed as $k) {
+            $arr[$k] = $this->getCode('method', $k);
+        }
 
-        return self::RATES_ENDPOINT;
+        return $arr;
     }
 
+
     /**
-     * Make request to uAfrica API to get shipping rates
-     *  @return array
+     * Do shipment request to carrier web service, obtain Print Shipping Labels and process errors in response
+     *
+     * @param \Magento\Framework\DataObject $request
+     * @return \Magento\Framework\DataObject
      */
-    private function getRates($payload): array
+    protected function _doShipmentRequest(\Magento\Framework\DataObject $request)
     {
-        $this->curl->post($this->getApiUrl(), $payload);
+        return null;
 
-        $response = $this->curl->getBody();
+    }
 
-        $response = json_decode($response, true);
+    /**
+     * For multi package shipments. Delete requested shipments if the current shipment request is failed
+     *
+     * @param array $data
+     *
+     * @return bool
+     */
+    public function rollBack($data)
+    {
+        return true;
+    }
 
-        return $response;
+    /**
+     * Return container types of carrier
+     *
+     * @param \Magento\Framework\DataObject|null $params
+     *
+     * @return array|bool
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    public function getContainerTypes(\Magento\Framework\DataObject $params = null)
+    {
+      //return null
+        $result = [];
+        $allowedContainers = $this->getConfigData('containers');
+        if ($allowedContainers) {
+            $allowedContainers = explode(',', $allowedContainers);
+        }
+        if ($allowedContainers) {
+            foreach ($allowedContainers as $container) {
+                $result[$container] = $this->getCode('container_types', $container);
+            }
+        }
+
+        return $result;
     }
 
     /**
-     * Collect and get rates for storefront
+     * Return delivery confirmation types of carrier
+     *
+     * @param \Magento\Framework\DataObject|null $params
      *
+     * @return array
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
-     * @param RateRequest $request
-     * @return DataObject|bool|null
-     * @api
      */
-    public function collectRates(RateRequest $request)
+    public function getDeliveryConfirmationTypes(\Magento\Framework\DataObject $params = null)
     {
-        //TODO: You need to work with this function in order to implement getting rates at checkout
-        /**
-         * Make sure that Shipping method is enabled
-         */
-        if (!$this->isActive()) {
-            return false;
+        return $this->getCode('delivery_confirmation_types');
+    }
+
+    /**
+     * Recursive replace sensitive fields in debug data by the mask
+     *
+     * @param string $data
+     * @return string
+     */
+    protected function filterDebugData($data)
+    {
+        foreach (array_keys($data) as $key) {
+            if (is_array($data[$key])) {
+                $data[$key] = $this->filterDebugData($data[$key]);
+            } elseif (in_array($key, $this->_debugReplacePrivateDataKeys)) {
+                $data[$key] = self::DEBUG_KEYS_MASK;
+            }
         }
+        return $data;
+    }
 
-        /** @var \Magento\Shipping\Model\Rate\Result $result */
+    /**
+     * Parse track details response from uAfrica
+     *
+     * @return array
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    private function processTrackingDetails($trackInfo): array
+    {
+        $result = [
+            'shippeddate' => null,
+            'deliverydate' => null,
+            'deliverytime' => null,
+            'deliverylocation' => null,
+            'weight' => null,
+            'progressdetail' => [],
+        ];
 
-        $result = $this->_rateResultFactory->create();
-
-        //TODO: Get the rates from the API and append them to the result object
-        //JSON data fed to post man mock server as a response to the request for rates
-        //{
-        //"rates": [
-        //{
-        //"id": "113810",
-        //"description": "Standard Economy Shipping Rate",
-        //"service_name": "Courier Door to Door Delivery - Economy",
-        //"service_code": "113810_23",
-        //"total_price": 7500,
-        //"currency": "ZAR",
-        //"min_delivery_date": "2022-12-29",
-        //"max_delivery_date": "2023-01-03"
-        //}
-        //]
-        //}
-        $destination = $request->getDestPostcode();
-        $destCountry = $request->getDestCountryId();
-        $destRegion = $request->getDestRegionCode();
-        $destCity = $request->getDestCity();
-        $destStreet = $request->getDestStreet();
-        $destStreet1 = $destStreet;
-        $destStreet2 = $destStreet;
+        $result = $this->_requestTracking($trackInfo, $result);
 
-        //Get all the origin data from the request
-        $origin = $this->getConfigData('origin_postcode');
-        $originCountry = $this->getConfigData('origin_country_id');
-        $originRegion = $this->getConfigData('origin_region_id');
-        $originCity = $this->getConfigData('origin_city');
-        $originStreet = $this->getConfigData('origin_street');
-        //URL to get the rates from
-        $url = $this->getConfigData('rates_endpoint');
-        $originStreet1 = $originStreet;
-        $originStreet2 = $originStreet;
+        return $result;
+    }
 
+    /**
+     * Append error message to rate result instance
+     *
+     * @param string $trackingValue
+     * @param string $errorMessage
+     */
+    private function appendTrackingError($trackingValue, $errorMessage)
+    {
+        $error = $this->_trackErrorFactory->create();
+        $error->setCarrier('uafrica');
+        $error->setCarrierTitle($this->getConfigData('title'));
+        $error->setTracking($trackingValue);
+        $error->setErrorMessage($errorMessage);
+        $result = $this->getResult();
+        $result->append($error);
+    }
 
-        $items = $request->getAllItems();
-        $itemsArray = [];
-        foreach ($items as $item) {
-            $itemsArray[] = [
-                'name' => $item->getName(),
-                'sku' => $item->getSku(),
-                'quantity' => $item->getQty(),
-                'price' => $item->getPrice(),
-                'grams' => $item->getWeight() * 1000,
-                'requires_shipping' => $item->getIsVirtual(),
-                'taxable' => true,
-                'fulfillment_service' => 'manual',
-                'properties' => [],
-                'vendor' => $item->getStoreId(),
-                'product_id' => $item->getProductId(),
-                'variant_id' => $item->getProduct()->getId()
-            ];
-        }
-            $payload = [
-                'rate' => [
-                    //TODO: Get the data from the request object
-                    'origin' => [
-                        'country' => $originCountry,
-                        'postal_code' => $origin,
-                        'province' => $originRegion,
-                        'city' => $originCity,
-                        'name' => $url,
-                        'address1' => $originStreet1,
-                        'address2' => $originStreet2,
-                        'address3' => '',
-                        'phone' => '+27313039670',
-                        'fax' => '',
-                        'email' => '',
-                        'address_type' => '',
-                        'company_name' => 'Jam Clothing'
-                    ],
-                    //TODO: Get the destination (Receiver Details) from the request
-                    'destination' => [
-                        'country' => $destCountry,
-                        'postal_code' => $destination,
-                        'province' => $destRegion,
-                        'city' => $destCity,
-                        'name' => 'Brian Singh',
-                        'address1' => $destStreet1,
-                        'address2' => $destStreet2,
-                        'address3' => '',
-                        'phone' => '081 346 5923',
-                        'fax' => '',
-                        'email' => '',
-                        'address_type' => '',
-                        'company_name' => ''
-                    ],
-                    'items' => $itemsArray,
-                    'currency' => 'ZAR',
-                    'locale' => 'en-PT'
-                ]
-            ];
+    /**
+     * @param string $date
+     * @return string
+     */
+    public function formatDate(string $date): string
+    {
+        return date('d M Y', strtotime($date));
+    }
 
-        $rates = $this->getRates($payload);
+    /**
+     * @param string $time
+     * @return string
+     */
+    public function formatTime(string $time): string
+    {
+        return date('H:i', strtotime($time));
+    }
 
-        $method = $this->_rateMethodFactory->create();
+    /**
+     * @return string
+     */
+    private function getApiUrl(): string
+    {
+        return self::RATES_ENDPOINT;
+    }
 
-        foreach ($rates['rates'] as $code => $title) {
-            $method->setCarrier('uafrica');
-            $method->setCarrierTitle('uafrica');
-            $method->setMethod($code);
-            $method->setMethodTitle($title['service_name']);
-            $method->setPrice($title['total_price'] / 100);
-            $method->setCost($title['total_price'] / 100);
-            $result->append($method);
-        }
+    /**
+     *  Perfom API Request to uAfrica API and return response
+     * @param array $payload
+     * @param Result $result
+     * @return void
+     */
+    protected function _getRates(array $payload, Result $result): void
+    {
+
+        $rates = $this->uRates($payload);
+
+        $this->_formatRates($rates, $result);
+
+    }
+
+    /**
+     * Perfom API Request for Shipment Tracking to uAfrica API and return response
+     * @param $trackInfo
+     * @param array $result
+     * @return array
+     */
+    private function _requestTracking($trackInfo, array $result): array
+    {
+        $response = $this->trackUafricaShipment($trackInfo);
+
+        $result = $this->prepareActivity($response[0], $result);
 
         return $result;
     }
 
     /**
-     *Get Allowed shipping methods (for this part make fake methods)
+     * Prepare received checkpoints and activity from uAfrica Shipment Tracking API
+     * @param $response
+     * @param array $result
      * @return array
-     *
      */
-    public function getAllowedMethods(): array
+    private function prepareActivity($response, array $result): array
     {
-        $arr = [
-            'method' => 'uafrica',
+        $result['shippeddate'] = $this->formatDate($response['shipment_time_created']);
+        $result['deliverydate'] = $this->formatDate('2022-12-14 09:40:41+00:00');
+        $result['deliverytime'] = $this->formatTime('2022-12-14 09:40:41+00:00');
+        $result['deliverylocation'] = 'Johannesburg';
+
+        foreach ($response['checkpoints'] as $checkpoint) {
+            $result['progressdetail'][] = [
+                'activity' => $checkpoint['status'],
+                'deliverydate' => $this->formatDate($checkpoint['time']),
+                'deliverytime' => $this->formatTime($checkpoint['time']),
+                //TODO:Not Receiving Checkpoint location from the sample body of response so, this is temp
+                'deliverylocation' => 'Pretoria',
+            ];
+        }
+        return $result;
+    }
 
-        ];
-        //Get shipping methods dynamically from the API
-//        $arr = [];
-//        $rates = $this->getRates();
-//
-//        foreach ($rates['rates'] as $code => $title) {
-//            $arr[$code] = $title['service_name'];
-//        }
-        return $arr;
+    /**
+     * Format rates from uAfrica API response and append to rate result instance of carrier
+     * @param mixed $rates
+     * @param Result $result
+     * @return void
+     */
+    protected function _formatRates(mixed $rates, Result $result): void
+    {
+        if (empty($rates)) {
+            $error = $this->_rateErrorFactory->create();
+            $error->setCarrier('uafrica');
+            $error->setCarrierTitle($this->getConfigData('title'));
+            $error->setErrorMessage($this->getConfigData('specificerrmsg'));
+
+            $result->append($error);
+        } else {
+            foreach ($rates['rates'] as $code => $title) {
+                $method = $this->_rateMethodFactory->create();
+                $method->setCarrier('uafrica');
+                $method->setCarrierTitle('uafrica');
+                $method->setMethod($code);
+                $method->setMethodTitle($title['service_name']);
+                $method->setPrice($title['total_price'] / 100);
+                $method->setCost($title['total_price'] / 100);
+                $result->append($method);
+            }
+        }
     }
 
+    /**
+     * Curl request to uAfrica Shipment Tracking API
+     * @param $trackInfo
+     * @return mixed
+     */
+    private function trackUafricaShipment($trackInfo): mixed
+    {
+        $this->curl->get(self::TRACKING . $trackInfo);
+
+        $response = $this->curl->getBody();
+
+        $response = json_decode($response, true);
+        return $response;
+    }
+
+    /**
+     * @param array $payload
+     * @return mixed
+     */
+    protected function uRates(array $payload): mixed
+    {
+        $this->curl->post($this->getApiUrl(), $payload);
+
+        $rates = $this->curl->getBody();
+
+        $rates = json_decode($rates, true);
+        return $rates;
+    }
 }
diff --git a/uafrica/Customshipping/etc/adminhtml/system.xml b/uafrica/Customshipping/etc/adminhtml/system.xml
index 034de7f..b1a7bf7 100644
--- a/uafrica/Customshipping/etc/adminhtml/system.xml
+++ b/uafrica/Customshipping/etc/adminhtml/system.xml
@@ -23,7 +23,7 @@
                     <frontend_model>uafrica\Customshipping\Block\System\Config\Form\Field\Version</frontend_model>
                 </field>
                 <field id="enabled" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
-                    <label>Enabled</label>
+                    <label>Enabled for Checkout</label>
                     <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                 </field>
                 <field id="debug" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
@@ -50,28 +50,11 @@
                     <label>Title</label>
                 </field>
 
-<!--                <field id="name" translate="label" type="text" sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="1">-->
-<!--                    <label>Method Name</label>-->
-<!--                </field>-->
 
                 <field id="residence_delivery" translate="label" type="select" sortOrder="7" showInDefault="1" showInWebsite="1">
                     <label>Residential Delivery</label>
                     <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                 </field>
-<!--                <field id="production_webservices_url" translate="label" type="text" sortOrder="90" showInDefault="0" showInWebsite="1" canRestore="1">-->
-<!--                    <label>Get Rates(uAfrica)</label>-->
-<!--                    <depends>-->
-<!--                        <field id="sandbox_mode">0</field>-->
-<!--             </depends>-->
-<!--&lt;!&ndash;- Not Functional at this stage&ndash;&gt;-->
-<!--                    <comment>URL To Get Shipping Rates</comment>-->
-<!--                </field>-->
-
-<!--                <field id="price" translate="label" type="text" sortOrder="4" showInDefault="1" showInWebsite="1" showInStore="0">-->
-<!--                    <label>Shipping Cost</label>-->
-<!--                    <validate>validate-number validate-zero-or-greater</validate>-->
-<!--                </field>-->
-
                 <field id="specificerrmsg" translate="label" type="textarea" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Displayed Error Message</label>
                 </field>
@@ -82,40 +65,6 @@
                     <source_model>Magento\Shipping\Model\Config\Source\Allspecificcountries</source_model>
                 </field>
 
-                <field id="allowed_methods" translate="label" type="multiselect" sortOrder="95" showInDefault="1" showInWebsite="1" canRestore="1">
-                    <label>Allowed Methods</label>
-                    <source_model>uafrica\Customshipping\Model\Source\Method</source_model>
-                    <can_be_empty>1</can_be_empty>
-                </field>
-                <field id="free_method" translate="label" type="select" sortOrder="210" showInDefault="1" showInWebsite="1" canRestore="1">
-                    <label>Free Method</label>
-                    <frontend_class>free-method</frontend_class>
-                    <source_model>uafrica\Customshipping\Model\Source\Freemethod</source_model>
-                </field>
-                <field id="packaging" translate="label" type="select" sortOrder="120" showInDefault="1" showInWebsite="1" canRestore="1">
-                    <label>Packaging</label>
-                    <source_model>uafrica\Customshipping\Model\Source\Packaging</source_model>
-                </field>
-                <field id="dropoff" translate="label" type="select" sortOrder="130" showInDefault="1" showInWebsite="1" canRestore="1">
-                    <label>Dropoff</label>
-                    <source_model>uafrica\Customshipping\Model\Source\Dropoff</source_model>
-                </field>
-                <field id="handling_fee" translate="label" type="text" sortOrder="170" showInDefault="1" showInWebsite="1">
-                    <label>Handling Fee</label>
-                    <validate>validate-number validate-zero-or-greater</validate>
-                </field>
-                <field id="handling_type" translate="label" type="select" sortOrder="150" showInDefault="1" showInWebsite="1" canRestore="1">
-                    <label>Calculate Handling Fee</label>
-                    <source_model>Magento\Shipping\Model\Source\HandlingType</source_model>
-                </field>
-                <field id="handling_action" translate="label" type="select" sortOrder="160" showInDefault="1" showInWebsite="1" canRestore="1">
-                    <label>Handling Applied</label>
-                    <source_model>Magento\Shipping\Model\Source\HandlingAction</source_model>
-                </field>
-                <field id="free_shipping_enable" translate="label" type="select" sortOrder="220" showInDefault="1" showInWebsite="1">
-                    <label>Enable Free Shipping Threshold</label>
-                    <source_model>Magento\Config\Model\Config\Source\Enabledisable</source_model>
-                </field>
                 <field id="specificcountry" translate="label" type="multiselect" sortOrder="91" showInDefault="1" showInWebsite="1" showInStore="0">
                     <label>Ship to Specific Countries</label>
                     <source_model>Magento\Directory\Model\Config\Source\Country</source_model>
@@ -127,33 +76,6 @@
                     <frontend_class>shipping-skip-hide</frontend_class>
                     <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                 </field>
-                <field id="access_token" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
-                    <label>uAfrica Access Token</label>
-                    <comment>The Access token you received from uAfrica</comment>
-                </field>
-          <field id="client_id" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
-                    <label>uAfrica Client ID</label>
-                    <comment>The Client ID you received from uAfrica</comment>
-                </field>
-                <field id="client_secret" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
-                    <label>uAfrica Client Secret</label>
-                    <comment>The Client Secret you received from uAfrica</comment>
-                </field>
-                <field id="rates_endpoint" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
-                    <label>uAfrica Rates (Production)</label>
-                    <comment>Rates at check out collection Endpoint</comment>
-
-                </field>
-                 <field id="rates_endpoint_sandbox" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
-                    <label>uAfrica Rates (Sandbox)</label>
-                    <comment>Rates at check out collection Endpoint</comment>
-
-                </field>
-
-                <field id="sort_order" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0">
-                    <label>Sort Order</label>
-                </field>
-
                 <field id="unit_of_measure" translate="label" type="select" sortOrder="73" showInDefault="1" showInWebsite="1" canRestore="1">
                     <label>Weight Unit</label>
                     <source_model>uafrica\Customshipping\Model\Source\Unitofmeasure</source_model>
diff --git a/uafrica/Customshipping/etc/config.xml b/uafrica/Customshipping/etc/config.xml
index e656076..eeba0c6 100644
--- a/uafrica/Customshipping/etc/config.xml
+++ b/uafrica/Customshipping/etc/config.xml
@@ -21,7 +21,7 @@
                 <price>0.00</price>
                 <model>uafrica\Customshipping\Model\Carrier\Customshipping</model>
                 <name>Fixed</name>
-                <title>uafrica</title>
+                <title>uAfrica</title>
                 <specificerrmsg>This shipping method is not available. To use this shipping method, please contact us.</specificerrmsg>
             </uafrica>
         </carriers>
-- 
GitLab