There always comes the time when shopkeeper decides that he want’s to inform his customer of shipping estimate on checkout, so they could know approximately when they will get their goods. And for that, many shops today rely on API-s like ones from USPS or FedEx. Both of which are available for Magento.
In this article I will be showing you how to override FedEx carrier to return shipping estimate for given rates.
Overriding carrier
FedEx carrier works by sending request with given flags to FedEx server, who then, based on given flags, prepares response. After Magento receives response, it parses each rate as “Mage_Shipping_Model_Rate_Result” which he will later pass on to “Mage_Sales_Model_Quote_Address_Rate”. From which we will be able to access in template to show in frontend. For that, we will first override “Mage_Usa_Model_Shipping_Carrier_Fedex”.
Adding a flag for api
For FedEx API to know that it needs to return shipping estimate it needs to be given a “ReturnTransitAndCommit” flag. If we look into “Mage_Usa_Model_Shipping_Carrier_Fedex::_formRateRequest()” method, we will see that all it does is prepare flags into an array before it is sent to be parsed into request.
All we need to do here is rewrite original method and at the end of the array add our own flag.
Like in given example:
public function _formRateRequest($purpose)
{
$ratesRequest = parent::_formRateRequest($purpose);
$ratesRequest['ReturnTransitAndCommit'] = true ;//Here we are adding flag
return $ratesRequest;
}
Storing the response data
After we receive data from api it will be parsed into stdClass,and in that class we are only interested in ‘RateReplyDetails’ array, which holds all our rates and their details, including their shipping estimates.
What we need to do here is pass our shipping estimate data into rate that will be passed on. For that we will be rewriting “Mage_Usa_Model_Shipping_Carrier_Fedex::_prepareRateResponse()” method.
protected function _prepareRateResponse($response)
{
$costArr = array();
$priceArr = array();
// Array in which to store timestamp
$deliveryTimeStamp = array(); //
$errorTitle = 'Unable to retrieve tracking';
if (is_object($response)) {
if ($response->HighestSeverity == 'FAILURE' || $response->HighestSeverity == 'ERROR') {
if (is_array($response->Notifications)) {
$notification = array_pop($response->Notifications);
$errorTitle = (string)$notification->Message;
} else {
$errorTitle = (string)$response->Notifications->Message;
}
} elseif (isset($response->RateReplyDetails)) {
$allowedMethods = explode(",", $this->getConfigData('allowed_methods'));
if (is_array($response->RateReplyDetails)) {
foreach ($response->RateReplyDetails as $rate) {
$serviceName = (string)$rate->ServiceType;
if (in_array($serviceName, $allowedMethods)) {
$amount = $this->_getRateAmountOriginBased($rate);
$costArr[$serviceName] = $amount;
$priceArr[$serviceName] = $this->getMethodPrice($amount, $serviceName);
//Store timestamp into prepared array
$deliveryTimeStamp[$serviceName] = $rate->DeliveryTimestamp; //
}
}
asort($priceArr);
} else {
$rate = $response->RateReplyDetails;
$serviceName = (string)$rate->ServiceType;
if (in_array($serviceName, $allowedMethods)) {
$amount = $this->_getRateAmountOriginBased($rate);
$costArr[$serviceName] = $amount;
$priceArr[$serviceName] = $this->getMethodPrice($amount, $serviceName);
}
}
}
}
$result = Mage::getModel('shipping/rate_result');
if (empty($priceArr)) {
$error = Mage::getModel('shipping/rate_result_error');
$error->setCarrier($this->_code);
$error->setCarrierTitle($this->getConfigData('title'));
$error->setErrorMessage($errorTitle);
$error->setErrorMessage($this->getConfigData('specificerrmsg'));
$result->append($error);
} else {
foreach ($priceArr as $method=>$price) {
$rate = Mage::getModel('shipping/rate_result_method');
$rate->setCarrier($this->_code);
$rate->setCarrierTitle($this->getConfigData('title'));
$rate->setMethod($method);
$rate->setMethodTitle($this->getCode('method', $method));
$rate->setCost($costArr[$method]);
$rate->setPrice($price);
//Store timestamp into rate
$rate->setDeliveryTimeStamp($deliveryTimeStamp[$method]); //
$result->append($rate);
}
}
return $result;
}
Almost done..
Before we start celebrating we will notice that we are still not getting that data in fronted. That is because we stored that data into “Mage_Shipping_Model_Rate_Result_Method” which is is not same type of rate as in template, where we have “Mage_Sales_Model_Quote_Address_Rate”. So we will additionally rewrite method “Mage_Sales_Quote_Address_Rate::importShippingRate()” and just pass our data whether its present or not.
public function importShippingRate(Mage_Shipping_Model_Rate_Result_Abstract $rate)
{
parent::importShippingRate($rate);
if ($rate instanceof Mage_Shipping_Model_Rate_Result_Method) {
$this->setDeliveryTimeStamp($rate->getDeliveryTimeStamp());
}
return $this;
}
And we are done. Wherever you call for rates (in my case it was checkout/onepage/shipping_method/available.phtml – onepages shipping methods) fedEx api will provide shipping estimate.
Thanks for being with me and happy coding.