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>--> -<!--<!–- Not Functional at this stage–>--> -<!-- <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