Skip to content

Commit 1978e29

Browse files
committed
AC-9030::Fedex API Upgrade - Update Rate API to REST
1 parent 24ce222 commit 1978e29

File tree

5 files changed

+155
-85
lines changed

5 files changed

+155
-85
lines changed

app/code/Magento/Fedex/Model/Carrier.php

Lines changed: 109 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
7979
*/
8080
public const TRACK_REQUEST_END_POINT = 'track/v1/trackingnumbers';
8181

82+
/**
83+
* REST end point for Rate API
84+
*
85+
* @var string
86+
*/
87+
public const RATE_REQUEST_END_POINT = 'rate/v1/rates/quotes';
88+
8289
/**
8390
* REST end point of Tracking API
8491
*
@@ -291,16 +298,6 @@ protected function _createSoapClient($wsdl, $trace = false)
291298
return $client;
292299
}
293300

294-
/**
295-
* Create rate soap client
296-
*
297-
* @return \SoapClient
298-
*/
299-
protected function _createRateSoapClient()
300-
{
301-
return $this->_createSoapClient($this->_rateServiceWsdl);
302-
}
303-
304301
/**
305302
* Create ship soap client
306303
*
@@ -459,66 +456,76 @@ public function getVersionInfo()
459456
* @param string $purpose
460457
* @return array
461458
*/
462-
protected function _formRateRequest($purpose)
459+
protected function _formRateRequest($purpose) : array
463460
{
464461
$r = $this->_rawRequest;
465462
$ratesRequest = [
466-
'WebAuthenticationDetail' => [
467-
'UserCredential' => ['Key' => $r->getKey(), 'Password' => $r->getPassword()],
463+
'accountNumber' => [
464+
'value' => $r->getAccount()
468465
],
469-
'ClientDetail' => ['AccountNumber' => $r->getAccount(), 'MeterNumber' => $r->getMeterNumber()],
470-
'Version' => $this->getVersionInfo(),
471-
'RequestedShipment' => [
472-
'DropoffType' => $r->getDropoffType(),
473-
'ShipTimestamp' => date('c'),
474-
'PackagingType' => $r->getPackaging(),
475-
'Shipper' => [
476-
'Address' => ['PostalCode' => $r->getOrigPostal(), 'CountryCode' => $r->getOrigCountry()],
466+
'requestedShipment' => [
467+
'pickupType' => $this->getConfigData('pickup_type'),
468+
'packagingType' => $r->getPackaging(),
469+
'shipper' => [
470+
'address' => ['postalCode' => $r->getOrigPostal(), 'countryCode' => $r->getOrigCountry()],
477471
],
478-
'Recipient' => [
479-
'Address' => [
480-
'PostalCode' => $r->getDestPostal(),
481-
'CountryCode' => $r->getDestCountry(),
482-
'Residential' => (bool)$this->getConfigData('residence_delivery'),
472+
'recipient' => [
473+
'address' => [
474+
'postalCode' => $r->getDestPostal(),
475+
'countryCode' => $r->getDestCountry(),
476+
'residential' => (bool)$this->getConfigData('residence_delivery'),
483477
],
484478
],
485-
'ShippingChargesPayment' => [
486-
'PaymentType' => 'SENDER',
487-
'Payor' => ['AccountNumber' => $r->getAccount(), 'CountryCode' => $r->getOrigCountry()],
488-
],
489-
'CustomsClearanceDetail' => [
490-
'CustomsValue' => ['Amount' => $r->getValue(), 'Currency' => $this->getCurrencyCode()],
479+
'customsClearanceDetail' => [
480+
'dutiesPayment' => [
481+
'payor' => [
482+
'responsibleParty' => [
483+
'accountNumber' => [
484+
'value' => $r->getAccount()
485+
],
486+
'address' => [
487+
'countryCode' => $r->getOrigCountry()
488+
]
489+
]
490+
],
491+
'paymentType' => 'SENDER',
492+
],
493+
'commodities' => [
494+
[
495+
'customsValue' => ['amount' => $r->getValue(), 'currency' => $this->getCurrencyCode()]
496+
]
497+
]
491498
],
492-
'RateRequestTypes' => 'LIST',
493-
'PackageDetail' => 'INDIVIDUAL_PACKAGES',
494-
],
499+
'rateRequestType' => ['LIST']
500+
]
495501
];
496502

497503
foreach ($r->getPackages() as $packageNum => $package) {
498-
$ratesRequest['RequestedShipment']['RequestedPackageLineItems'][$packageNum]['GroupPackageCount'] = 1;
499-
$ratesRequest['RequestedShipment']['RequestedPackageLineItems'][$packageNum]['Weight']['Value']
504+
$ratesRequest['requestedShipment']['requestedPackageLineItems'][$packageNum]['subPackagingType'] =
505+
'PACKAGE';
506+
$ratesRequest['requestedShipment']['requestedPackageLineItems'][$packageNum]['groupPackageCount'] = 1;
507+
$ratesRequest['requestedShipment']['requestedPackageLineItems'][$packageNum]['weight']['value']
500508
= (double) $package['weight'];
501-
$ratesRequest['RequestedShipment']['RequestedPackageLineItems'][$packageNum]['Weight']['Units']
509+
$ratesRequest['requestedShipment']['requestedPackageLineItems'][$packageNum]['weight']['units']
502510
= $this->getConfigData('unit_of_measure');
503511
if (isset($package['price'])) {
504-
$ratesRequest['RequestedShipment']['RequestedPackageLineItems'][$packageNum]['InsuredValue']['Amount']
512+
$ratesRequest['requestedShipment']['requestedPackageLineItems'][$packageNum]['declaredValue']['amount']
505513
= (double) $package['price'];
506-
$ratesRequest['RequestedShipment']['RequestedPackageLineItems'][$packageNum]['InsuredValue']['Currency']
507-
= $this->getCurrencyCode();
514+
$ratesRequest['requestedShipment']['requestedPackageLineItems'][$packageNum]['declaredValue']
515+
['currency'] = $this->getCurrencyCode();
508516
}
509517
}
510518

511-
$ratesRequest['RequestedShipment']['PackageCount'] = count($r->getPackages());
512-
519+
$ratesRequest['requestedShipment']['totalPackageCount'] = count($r->getPackages());
513520
if ($r->getDestCity()) {
514-
$ratesRequest['RequestedShipment']['Recipient']['Address']['City'] = $r->getDestCity();
521+
$ratesRequest['requestedShipment']['recipient']['address']['city'] = $r->getDestCity();
515522
}
516523

517524
if ($purpose == self::RATE_REQUEST_SMARTPOST) {
518-
$ratesRequest['RequestedShipment']['ServiceType'] = self::RATE_REQUEST_SMARTPOST;
519-
$ratesRequest['RequestedShipment']['SmartPostDetail'] = [
520-
'Indicia' => (double)$r->getWeight() >= 1 ? 'PARCEL_SELECT' : 'PRESORTED_STANDARD',
521-
'HubId' => $this->getConfigData('smartpost_hubid'),
525+
$ratesRequest['requestedShipment']['serviceType'] = self::RATE_REQUEST_SMARTPOST;
526+
$ratesRequest['requestedShipment']['smartPostInfoDetail'] = [
527+
'indicia' => (double)$r->getWeight() >= 1 ? 'PARCEL_SELECT' : 'PRESORTED_STANDARD',
528+
'hubId' => $this->getConfigData('smartpost_hubid'),
522529
];
523530
}
524531

@@ -531,29 +538,45 @@ protected function _formRateRequest($purpose)
531538
* @param string $purpose
532539
* @return mixed
533540
*/
534-
protected function _doRatesRequest($purpose)
541+
protected function _doRatesRequest($purpose) : mixed
535542
{
543+
$response = null;
544+
$accessToken = $this->_getAccessToken($tracking = null);
545+
if (empty($accessToken)) {
546+
return null;
547+
}
548+
536549
$ratesRequest = $this->_formRateRequest($purpose);
537-
$ratesRequestNoShipTimestamp = $ratesRequest;
538-
unset($ratesRequestNoShipTimestamp['RequestedShipment']['ShipTimestamp']);
539-
$requestString = $this->serializer->serialize($ratesRequestNoShipTimestamp);
550+
$requestString = $this->serializer->serialize($ratesRequest);
540551
$response = $this->_getCachedQuotes($requestString);
541552
$debugData = ['request' => $this->filterDebugData($ratesRequest)];
553+
542554
if ($response === null) {
555+
$headers = [
556+
'Content-Type' => 'application/json',
557+
'Authorization' => 'Bearer '.$accessToken,
558+
'X-locale' => 'en_US',
559+
560+
];
561+
$url = $this->_getBaseUrl() . self::RATE_REQUEST_END_POINT;
562+
$curlClient = $this->curlFactory->create();
543563
try {
544-
$client = $this->_createRateSoapClient();
545-
$response = $client->getRates($ratesRequest);
546-
$this->_setCachedQuotes($requestString, $response);
564+
$curlClient->setHeaders($headers);
565+
$curlClient->setOptions([CURLOPT_ENCODING => 'gzip,deflate,sdch']);
566+
$curlClient->post($url, $requestString);
567+
$response = $curlClient->getBody();
547568
$debugData['result'] = $response;
569+
$response = $this->serializer->unserialize($response);
570+
$this->_setCachedQuotes($requestString, $response);
548571
} catch (\Exception $e) {
549572
$debugData['result'] = ['error' => $e->getMessage(), 'code' => $e->getCode()];
550573
$this->_logger->critical($e);
551574
}
552575
} else {
553576
$debugData['result'] = $response;
554577
}
555-
$this->_debug($debugData);
556578

579+
$this->_debug($debugData);
557580
return $response;
558581
}
559582

@@ -594,41 +617,32 @@ protected function _getQuotes()
594617
* @return Result
595618
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
596619
*/
597-
protected function _prepareRateResponse($response)
620+
protected function _prepareRateResponse($response) : Result
598621
{
599622
$costArr = [];
600623
$priceArr = [];
601624
$errorTitle = 'For some reason we can\'t retrieve tracking info right now.';
602625

603-
if (is_object($response)) {
604-
if ($response->HighestSeverity == 'FAILURE' || $response->HighestSeverity == 'ERROR') {
605-
if (is_array($response->Notifications)) {
606-
$notification = array_pop($response->Notifications);
607-
$errorTitle = (string)$notification->Message;
626+
if (is_array($response)) {
627+
if (!empty($response['errors'])) {
628+
if (is_array($response['errors'])) {
629+
$notification = reset($response['errors']);
630+
$errorTitle = (string)$notification['message'];
608631
} else {
609-
$errorTitle = (string)$response->Notifications->Message;
632+
$errorTitle = (string)$response['errors']['message'];
610633
}
611-
} elseif (isset($response->RateReplyDetails)) {
634+
} elseif (isset($response['output']['rateReplyDetails'])) {
612635
$allowedMethods = explode(",", $this->getConfigData('allowed_methods'));
613-
614-
if (is_array($response->RateReplyDetails)) {
615-
foreach ($response->RateReplyDetails as $rate) {
616-
$serviceName = (string)$rate->ServiceType;
636+
if (is_array($response['output']['rateReplyDetails'])) {
637+
foreach ($response['output']['rateReplyDetails'] as $rate) {
638+
$serviceName = (string)$rate['serviceType'];
617639
if (in_array($serviceName, $allowedMethods)) {
618640
$amount = $this->_getRateAmountOriginBased($rate);
619641
$costArr[$serviceName] = $amount;
620642
$priceArr[$serviceName] = $this->getMethodPrice($amount, $serviceName);
621643
}
622644
}
623645
asort($priceArr);
624-
} else {
625-
$rate = $response->RateReplyDetails;
626-
$serviceName = (string)$rate->ServiceType;
627-
if (in_array($serviceName, $allowedMethods)) {
628-
$amount = $this->_getRateAmountOriginBased($rate);
629-
$costArr[$serviceName] = $amount;
630-
$priceArr[$serviceName] = $this->getMethodPrice($amount, $serviceName);
631-
}
632646
}
633647
}
634648
}
@@ -697,17 +711,18 @@ protected function _getPerorderPrice($cost, $handlingType, $handlingFee)
697711
* @param \stdClass $rate
698712
* @return null|float
699713
*/
700-
protected function _getRateAmountOriginBased($rate)
714+
protected function _getRateAmountOriginBased($rate) : null|float
701715
{
702716
$amount = null;
703717
$currencyCode = '';
704718
$rateTypeAmounts = [];
705-
if (is_object($rate)) {
719+
720+
if (is_array($rate)) {
706721
// The "RATED..." rates are expressed in the currency of the origin country
707-
foreach ($rate->RatedShipmentDetails as $ratedShipmentDetail) {
708-
$netAmount = (string)$ratedShipmentDetail->ShipmentRateDetail->TotalNetCharge->Amount;
709-
$currencyCode = (string)$ratedShipmentDetail->ShipmentRateDetail->TotalNetCharge->Currency;
710-
$rateType = (string)$ratedShipmentDetail->ShipmentRateDetail->RateType;
722+
foreach ($rate['ratedShipmentDetails'] as $ratedShipmentDetail) {
723+
$netAmount = (string)$ratedShipmentDetail['totalNetCharge'];
724+
$currencyCode = (string)$ratedShipmentDetail['shipmentRateDetail']['currency'];
725+
$rateType = (string)$ratedShipmentDetail['rateType'];
711726
$rateTypeAmounts[$rateType] = $netAmount;
712727
}
713728

@@ -719,7 +734,7 @@ protected function _getRateAmountOriginBased($rate)
719734
}
720735

721736
if ($amount === null) {
722-
$amount = (string)$rate->RatedShipmentDetails[0]->ShipmentRateDetail->TotalNetCharge->Amount;
737+
$amount = (string)$rate['ratedShipmentDetails'][0]['totalNetCharge'];
723738
}
724739

725740
$amount = (float)$amount * $this->getBaseCurrencyRate($currencyCode);
@@ -916,10 +931,10 @@ protected function _parseXmlResponse($response)
916931
*
917932
* @param string $type
918933
* @param string $code
919-
* @return array|false
934+
* @return \Magento\Framework\Phrase|array|false
920935
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
921936
*/
922-
public function getCode($type, $code = '')
937+
public function getCode($type, $code = '') : \Magento\Framework\Phrase|array|false
923938
{
924939
$codes = [
925940
'method' => [
@@ -1058,6 +1073,15 @@ public function getCode($type, $code = '')
10581073
'LB' => __('Pounds'),
10591074
'KG' => __('Kilograms'),
10601075
],
1076+
'pickup_type' => [
1077+
'CONTACT_FEDEX_TO_SCHEDULE' => __('Contact Fedex to Schedule'),
1078+
'DROPOFF_AT_FEDEX_LOCATION' => __('DropOff at Fedex Location'),
1079+
'USE_SCHEDULED_PICKUP' => __('Use Scheduled Pickup'),
1080+
'ON_CALL' => __('On Call'),
1081+
'PACKAGE_RETURN_PROGRAM' => __('Package Return Program'),
1082+
'REGULAR_STOP' => __('Regular Stop'),
1083+
'TAG' => __('Tag'),
1084+
]
10611085
];
10621086

10631087
if (!isset($codes[$type])) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* ADOBE CONFIDENTIAL
5+
* ___________________
6+
*
7+
* Copyright 2023 Adobe
8+
* All Rights Reserved.
9+
*
10+
* NOTICE: All information contained herein is, and remains
11+
* the property of Adobe and its suppliers, if any. The intellectual
12+
* and technical concepts contained herein are proprietary to Adobe
13+
* and its suppliers and are protected by all applicable intellectual
14+
* property laws, including trade secret and copyright laws.
15+
* Dissemination of this information or reproduction of this material
16+
* is strictly forbidden unless prior written permission is obtained
17+
* from Adobe.
18+
*************************************************************************
19+
*/
20+
21+
namespace Magento\Fedex\Model\Source;
22+
23+
/**
24+
* Fedex pickupType source implementation
25+
*/
26+
class PickupType extends \Magento\Fedex\Model\Source\Generic
27+
{
28+
/**
29+
* Carrier code
30+
*
31+
* @var string
32+
*/
33+
protected $_code = 'pickup_type';
34+
}

app/code/Magento/Fedex/etc/adminhtml/system.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@
179179
<field id="rest_sandbox_mode">1</field>
180180
</depends>
181181
</field>
182+
<field id="pickup_type" translate="label" type="select" sortOrder="350" showInDefault="1" showInWebsite="1" canRestore="1">
183+
<label>REST Configuration | PickUp Type</label>
184+
<source_model>Magento\Fedex\Model\Source\PickupType</source_model>
185+
</field>
182186
</group>
183187
</section>
184188
</system>

app/code/Magento/Fedex/etc/config.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
<rest_sandbox_mode>0</rest_sandbox_mode>
5454
<rest_production_webservices_url><![CDATA[https://apis.fedex.com/]]></rest_production_webservices_url>
5555
<rest_sandbox_webservices_url><![CDATA[https://apis-sandbox.fedex.com/]]></rest_sandbox_webservices_url>
56+
<pickup_type>DROPOFF_AT_FEDEX_LOCATION</pickup_type>
5657
</fedex>
5758
</carriers>
5859
</default>

app/code/Magento/Fedex/i18n/en_US.csv

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,10 @@ Debug,Debug
8181
"Fedex API endpoint URL\'s must use fedex.com","Fedex API endpoint URL\'s must use fedex.com"
8282
"Authentication keys are missing.","Authentication keys are missing."
8383
"Authorization Error. No Access Token found with given credentials.","Authorization Error. No Access Token found with given credentials."
84+
"Contact Fedex to Schedule","Contact Fedex to Schedule"
85+
"DropOff at Fedex Location","DropOff at Fedex Location"
86+
"Scheduled Pickup","Scheduled Pickup"
87+
"On Call","On Call"
88+
"Package Return Program","Package Return Program"
89+
"Regular Stop","Regular Stop"
90+
"Tag","Tag"

0 commit comments

Comments
 (0)