4

i need my shipping methods from UPS to say an estimated delivery date (or range) do i need to extend Magento's core UPS API functionality or is this information already being retrieved and i just need to display it? my store is magento 1.9.3

UPS shipping rates

4

You will need to extend it, but the information is provided in the UPS response for some of the shipping methods. One notable exception seems to be UPS Ground, although that might be a configuration setting for the webservices account or in the request.

You can turn on the DEBUG option in Admin > System > Configuration > Shipping Methods > UPS... this allows you to see the response XML that comes back from the request.

Here is part of the response for method "UPS Next Day Air Saver":

<RatedShipment>
  <Service>
     <Code>13</Code>
  </Service>
  <RatedShipmentWarning>Your invoice may vary from the displayed reference rates</RatedShipmentWarning>
  <BillingWeight>
     <UnitOfMeasurement>
        <Code>LBS</Code>
     </UnitOfMeasurement>
     <Weight>2.0</Weight>
  </BillingWeight>
  <TransportationCharges>
     <CurrencyCode>USD</CurrencyCode>
     <MonetaryValue>56.09</MonetaryValue>
  </TransportationCharges>
  <ServiceOptionsCharges>
     <CurrencyCode>USD</CurrencyCode>
     <MonetaryValue>0.00</MonetaryValue>
  </ServiceOptionsCharges>
  <TotalCharges>
     <CurrencyCode>USD</CurrencyCode>
     <MonetaryValue>56.09</MonetaryValue>
  </TotalCharges>
  <GuaranteedDaysToDelivery>1</GuaranteedDaysToDelivery>
  <ScheduledDeliveryTime>4:30 P.M.</ScheduledDeliveryTime>
  <RatedPackage>
     <TransportationCharges>
        <CurrencyCode>USD</CurrencyCode>
        <MonetaryValue>56.09</MonetaryValue>
     </TransportationCharges>
     <ServiceOptionsCharges>
        <CurrencyCode>USD</CurrencyCode>
        <MonetaryValue>0.00</MonetaryValue>
     </ServiceOptionsCharges>
     <TotalCharges>
        <CurrencyCode>USD</CurrencyCode>
        <MonetaryValue>56.09</MonetaryValue>
     </TotalCharges>
     <Weight>1.1</Weight>
     <BillingWeight>
        <UnitOfMeasurement>
           <Code>LBS</Code>
        </UnitOfMeasurement>
        <Weight>2.0</Weight>
     </BillingWeight>
  </RatedPackage>

It may be that this is actually generic info and does not represent the actual transit time (only the guaranteed arrival). This MIGHT be enough for you... but if it is not and you need further detail, there is actually a separate Time in Transit API. Take a look at the UPS API documents:

https://www.ups.com/content/us/en/resources/techsupport/developercenter.html

Regardless, some customization will be required.

  • thank you i really need for ground will look at ups api info – Yehuda Schwartz Nov 24 '16 at 18:07
2

Here's my solution to this. Still refining it but it gets the transit time and ETA for each service and displays it. You need to enable Time In Transit option in system config for UPS shipping method to work. One of the downsides to getting the transit times is that you have to pass in the destination city to get any results back from UPS. The address is also validated by them first so it needs to be correct otherwise no rates are returned.

magento/app/code/local/JustKampers/Usa/etc/config.xml

    <?xml version="1.0"?>
<config>
    <modules>
        <JustKampers_Usa>
            <version>0.0.1</version>
            <depends>
                <Mage_Usa />
            </depends>
        </JustKampers_Usa>
    </modules>
    <global>
        <blocks>
            <checkout>
                <rewrite>
                    <cart_shipping>JustKampers_Usa_Block_Checkout_Cart_Shipping</cart_shipping>
                </rewrite>
            </checkout>
        </blocks>
        <models>
            <usa>
                <rewrite>
                    <shipping_carrier_ups>JustKampers_Usa_Model_Shipping_Carrier_Ups</shipping_carrier_ups>
                </rewrite>
            </usa>
        </models>
    </global>
    <frontend>
        <routers>
            <usa>
                <args>
                    <modules>
                        <JustKampers_Usa before="Mage_Usa">JustKampers_Usa</JustKampers_Usa>
                    </modules>
                </args>
            </usa>
        </routers>
    </frontend>
</config>

magento/app/code/local/JustKampers/Usa/etc/system.xml

<?xml version="1.0"?>
<config>
    <sections>
        <carriers>
            <groups>
                <ups translate="label" module="usa">
                    <fields>
                        <time_in_transit translate="label">
                            <label>Enable Time In Transit</label>
                            <frontend_type>select</frontend_type>
                            <source_model>adminhtml/system_config_source_yesno</source_model>
                            <sort_order>920</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </time_in_transit>
                    </fields>
                </ups>
            </groups>
        </carriers>
    </sections>
</config>

magento/app/code/local/JustKampers/Usa/Model/Shipping/Carrier/Ups.php

<?php

class JustKampers_Usa_Model_Shipping_Carrier_Ups extends Mage_Usa_Model_Shipping_Carrier_Ups implements Mage_Shipping_Model_Carrier_Interface
{

    public function isCityRequired()
    {
        return (bool)Mage::getStoreConfig('carriers/ups/time_in_transit');
    }

    /**
     * Prepare and set request to this instance
     *
     * @param Mage_Shipping_Model_Rate_Request $request
     * @return Mage_Usa_Model_Shipping_Carrier_Ups
     */
    public function setRequest(Mage_Shipping_Model_Rate_Request $request)
    {

        parent::setRequest($request);

        $r = $this->_rawRequest;

        $r->setCurrencyCode(Mage::app()->getStore()->getBaseCurrencyCode());

        $r->setDestCity($request->getDestCity());

        $this->_rawRequest = $r;

        return $this;
    }


    /**
     * Get xml rates
     *
     * @return Mage_Shipping_Model_Rate_Result
     */
    protected function _getXmlQuotes()
    {
        $url = $this->getConfigData('gateway_xml_url');
        if (!$url) {
            $url = $this->_defaultUrls['Rate'];
        }

        $this->setXMLAccessRequest();
        $xmlRequest=$this->_xmlAccessRequest;

        $r = $this->_rawRequest;
        $params = array(
            'accept_UPS_license_agreement' => 'yes',
            '10_action'      => $r->getAction(),
            '13_product'     => $r->getProduct(),
            '14_origCountry' => $r->getOrigCountry(),
            '15_origPostal'  => $r->getOrigPostal(),
            'origCity'       => $r->getOrigCity(),
            'origRegionCode' => $r->getOrigRegionCode(),
            '19_destPostal'  => Mage_Usa_Model_Shipping_Carrier_Abstract::USA_COUNTRY_ID == $r->getDestCountry() ?
                substr($r->getDestPostal(), 0, 5) :
                $r->getDestPostal(),
            '22_destCountry' => $r->getDestCountry(),
            'destRegionCode' => $r->getDestRegionCode(),
            '23_weight'      => $r->getWeight(),
            '47_rate_chart'  => $r->getPickup(),
            '48_container'   => $r->getContainer(),
            '49_residential' => $r->getDestType(),
        );

        if ($params['10_action'] == '4') {


            /* ------- XML Mod For Time In Transit Params ---------*/
            $params['10_action'] = 'Shoptimeintransit';
            /* ---------------- End of XML Mod --------------------*/


            $serviceCode = null; // Service code is not relevant when we're asking ALL possible services' rates
        } else {
            $params['10_action'] = 'Rate';
            $serviceCode = $r->getProduct() ? $r->getProduct() : '';
        }
        $serviceDescription = $serviceCode ? $this->getShipmentByCode($serviceCode) : '';

$xmlRequest .= <<< XMLRequest
<?xml version="1.0"?>
<RatingServiceSelectionRequest xml:lang="en-US">
  <Request>
    <TransactionReference>
      <CustomerContext>Rating and Service</CustomerContext>
      <XpciVersion>1.0</XpciVersion>
    </TransactionReference>
    <RequestAction>Rate</RequestAction>
    <RequestOption>{$params['10_action']}</RequestOption>
  </Request>
  <PickupType>
          <Code>{$params['47_rate_chart']['code']}</Code>
          <Description>{$params['47_rate_chart']['label']}</Description>
  </PickupType>

  <Shipment>
XMLRequest;

        if ($serviceCode !== null) {
            $xmlRequest .= "<Service>" .
                "<Code>{$serviceCode}</Code>" .
                "<Description>{$serviceDescription}</Description>" .
                "</Service>";
        }

      $xmlRequest .= <<< XMLRequest
      <Shipper>
XMLRequest;

        if ($this->getConfigFlag('negotiated_active') && ($shipper = $this->getConfigData('shipper_number')) ) {
            $xmlRequest .= "<ShipperNumber>{$shipper}</ShipperNumber>";
        }

        if ($r->getIsReturn()) {
            $shipperCity = '';
            $shipperPostalCode = $params['19_destPostal'];
            $shipperCountryCode = $params['22_destCountry'];
            $shipperStateProvince = $params['destRegionCode'];
        } else {
            $shipperCity = $params['origCity'];
            $shipperPostalCode = $params['15_origPostal'];
            $shipperCountryCode = $params['14_origCountry'];
            $shipperStateProvince = $params['origRegionCode'];
        }

$xmlRequest .= <<< XMLRequest
      <Address>
          <City>{$shipperCity}</City>
          <PostalCode>{$shipperPostalCode}</PostalCode>
          <CountryCode>{$shipperCountryCode}</CountryCode>
          <StateProvinceCode>{$shipperStateProvince}</StateProvinceCode>
      </Address>
    </Shipper>
    <ShipTo>
      <Address>
XMLRequest;

/* ------- XML Mod For Time In Transit Params ---------*/
$xmlRequest .= <<< XMLRequest
            <City>{$r->getDestCity()}</City>
XMLRequest;
/* ---------------- End of XML Mod --------------------*/

$xmlRequest .= <<< XMLRequest
          <PostalCode>{$params['19_destPostal']}</PostalCode>
          <CountryCode>{$params['22_destCountry']}</CountryCode>
          <ResidentialAddress>{$params['49_residential']}</ResidentialAddress>
          <StateProvinceCode>{$params['destRegionCode']}</StateProvinceCode>
XMLRequest;

          $xmlRequest .= ($params['49_residential']==='01'
                  ? "<ResidentialAddressIndicator>{$params['49_residential']}</ResidentialAddressIndicator>"
                  : ''
          );

$xmlRequest .= <<< XMLRequest
      </Address>
    </ShipTo>


    <ShipFrom>
      <Address>
          <PostalCode>{$params['15_origPostal']}</PostalCode>
          <CountryCode>{$params['14_origCountry']}</CountryCode>
          <StateProvinceCode>{$params['origRegionCode']}</StateProvinceCode>
      </Address>
    </ShipFrom>

    <Package>
      <PackagingType><Code>{$params['48_container']}</Code></PackagingType>
      <PackageWeight>
         <UnitOfMeasurement><Code>{$r->getUnitMeasure()}</Code></UnitOfMeasurement>
        <Weight>{$params['23_weight']}</Weight>
      </PackageWeight>
    </Package>
XMLRequest;
        if ($this->getConfigFlag('negotiated_active')) {
            $xmlRequest .= "<RateInformation><NegotiatedRatesIndicator/></RateInformation>";
        }

/* ------- XML Mod For Time In Transit Params ---------*/
$xmlRequest .= <<< XMLRequest
    <DeliveryTimeInformation>
        <PackageBillType>03</PackageBillType>
    </DeliveryTimeInformation>
    <ShipmentTotalWeight>
        <UnitOfMeasurement>
            <Code>{$r->getUnitMeasure()}</Code>
        </UnitOfMeasurement>
        <Weight>{$params['23_weight']}</Weight>
    </ShipmentTotalWeight>
    <InvoiceLineTotal>
        <CurrencyCode>{$r->getCurrencyCode()}</CurrencyCode>
        <MonetaryValue>{$r->getBaseSubtotalInclTax()}</MonetaryValue>
    </InvoiceLineTotal>
XMLRequest;
/* ---------------- End of XML Mod --------------------*/

$xmlRequest .= <<< XMLRequest
   </Shipment>
</RatingServiceSelectionRequest>
XMLRequest;

        $xmlResponse = $this->_getCachedQuotes($xmlRequest);
        if ($xmlResponse === null) {
            $debugData = array('request' => $xmlRequest);
            try {
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                curl_setopt($ch, CURLOPT_HEADER, 0);
                curl_setopt($ch, CURLOPT_POST, 1);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
                curl_setopt($ch, CURLOPT_TIMEOUT, 30);
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->getConfigFlag('verify_peer'));
                $xmlResponse = curl_exec ($ch);

                $debugData['result'] = $xmlResponse;
                $this->_setCachedQuotes($xmlRequest, $xmlResponse);
            }
            catch (Exception $e) {
                $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode());
                $xmlResponse = '';
            }
            $this->_debug($debugData);
        }

        return $this->_parseXmlResponse($xmlResponse);
    }

    /**
     * Prepare shipping rate result based on response
     *
     * @param mixed $response
     * @return Mage_Shipping_Model_Rate_Result
     */
    protected function _parseXmlResponse($xmlResponse)
    {
        $costArr = array();
        $priceArr = array();
        $timeInTransitArr = array();
        $etaArr = array();

        if (strlen(trim($xmlResponse))>0) {
            $xml = new Varien_Simplexml_Config();
            $xml->loadString($xmlResponse);
            $arr = $xml->getXpath("//RatingServiceSelectionResponse/Response/ResponseStatusCode/text()");
            $success = (int)$arr[0];
            if ($success===1) {
                $arr = $xml->getXpath("//RatingServiceSelectionResponse/RatedShipment");
                $allowedMethods = explode(",", $this->getConfigData('allowed_methods'));

                // Negotiated rates
                $negotiatedArr = $xml->getXpath("//RatingServiceSelectionResponse/RatedShipment/NegotiatedRates");
                $negotiatedActive = $this->getConfigFlag('negotiated_active')
                    && $this->getConfigData('shipper_number')
                    && !empty($negotiatedArr);

                $allowedCurrencies = Mage::getModel('directory/currency')->getConfigAllowCurrencies();

                foreach ($arr as $shipElement){
                    $code = (string)$shipElement->Service->Code;
                    if (in_array($code, $allowedMethods)) {

                        if ($negotiatedActive) {
                            $cost = $shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->MonetaryValue;
                        } else {
                            $cost = $shipElement->TotalCharges->MonetaryValue;
                        }

                        /* ------------ Time In Transit Mod ------------*/

                        $daysInTransit = $shipElement->TimeInTransit->ServiceSummary->EstimatedArrival->TotalTransitDays;
                        $etaDate = $shipElement->TimeInTransit->ServiceSummary->EstimatedArrival->Arrival->Date;
                        $etaTime = $shipElement->TimeInTransit->ServiceSummary->EstimatedArrival->Arrival->Time;
                        $eta = new DateTime();
                        $eta->setDate(substr($etaDate, 0, 4), substr($etaDate, 4, 2), substr($etaDate, 6, 2));
                        $eta->setTime(substr($etaTime, 0, 2), substr($etaTime, 4, 2), substr($etaTime, 4, 2));

                        /* ----------- End Time In Transit Mod ---------*/

                        //convert price with Origin country currency code to base currency code
                        $successConversion = true;
                        $responseCurrencyCode = (string) $shipElement->TotalCharges->CurrencyCode;
                        if ($responseCurrencyCode) {
                            if (in_array($responseCurrencyCode, $allowedCurrencies)) {
                                $cost = (float) $cost * $this->_getBaseCurrencyRate($responseCurrencyCode);
                            } else {
                                $errorTitle = Mage::helper('directory')->__('Can\'t convert rate from "%s-%s".', $responseCurrencyCode, $this->_request->getPackageCurrency()->getCode());
                                $error = Mage::getModel('shipping/rate_result_error');
                                $error->setCarrier('ups');
                                $error->setCarrierTitle($this->getConfigData('title'));
                                $error->setErrorMessage($errorTitle);
                                $successConversion = false;
                            }
                        }

                        if ($successConversion) {
                            $costArr[$code] = $cost;
                            $priceArr[$code] = $this->getMethodPrice(floatval($cost),$code);

                            /* ------------ Time In Transit Mod ------------*/

                            $timeInTransitArr[$code] = $daysInTransit;
                            $etaArr[$code] = $eta;

                            /* ----------- End Time In Transit Mod ---------*/        

                        }
                    }
                }
            } else {
                $arr = $xml->getXpath("//RatingServiceSelectionResponse/Response/Error/ErrorDescription/text()");
                $errorTitle = (string)$arr[0][0];
                $error = Mage::getModel('shipping/rate_result_error');
                $error->setCarrier('ups');
                $error->setCarrierTitle($this->getConfigData('title'));
                $error->setErrorMessage($this->getConfigData('specificerrmsg'));
            }
        }

        $result = Mage::getModel('shipping/rate_result');
        $defaults = $this->getDefaults();
        if (empty($priceArr)) {
            $error = Mage::getModel('shipping/rate_result_error');
            $error->setCarrier('ups');
            $error->setCarrierTitle($this->getConfigData('title'));
            if(!isset($errorTitle)){
                $errorTitle = Mage::helper('usa')->__('Cannot retrieve shipping rates');
            }
            $error->setErrorMessage($this->getConfigData('specificerrmsg'));

            /* ------------ Time In Transit Mod ------------*/

            $error->setErrorMessage($errorTitle);

             /* ----------- End Time In Transit Mod ---------*/

            $result->append($error);

        } else {

            foreach ($priceArr as $method=>$price) {
                $rate = Mage::getModel('shipping/rate_result_method');
                $rate->setCarrier('ups');
                $rate->setCarrierTitle($this->getConfigData('title'));
                $rate->setMethod($method);
                $method_arr = $this->getShipmentByCode($method);

                /* ------------ Time In Transit Mod ------------*/

                $transitDays = intval($timeInTransitArr[$method]);
                $rate->setMethodTitle($method_arr . ' (ETA: ' . $etaArr[$method]->format('d-m-Y H:i'). ')');

                /* ----------- End Time In Transit Mod ---------*/

                // $rate->setMethodTitle($method_arr);
                $rate->setCost($costArr[$method]);
                $rate->setPrice($price);
                $result->append($rate);
            }
        }
        return $result;
    }
}

magento/app/code/local/JustKampers/Usa/Block/Checkout/Cart/Shipping.php

<?php

class JustKampers_Usa_Block_Checkout_Cart_Shipping extends Mage_Checkout_Block_Cart_Shipping
{

    /**
     * Show City in Shipping Estimation
     *
     * @return bool
     */
    public function getCityActive()
    {
        return (bool)Mage::getStoreConfig('carriers/ups/time_in_transit');
    }   
}

magento/app/etc/modules/JustKampers_Usa.xml

<?xml version="1.0"?>
<config>
    <modules>
        <JustKampers_Usa>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Usa />
            </depends>
        </JustKampers_Usa>
    </modules>
</config>
0

If you open UPS shipping module, you will see what Magento provides only simple details about shipping rate (CGI qoutes or XML quotes):

  • Carrier code
  • Carrier title
  • Shipping method
  • Shipping method title
  • Cost
  • Price

Unfortunately, Magento shipping module doesn't provide API to get more shipping details and in your case, I think possible solution override \Magento\Ups\Model\Carrier::_parseCgiResponse and \Magento\Ups\Model\Carrier::_parseXmlResponse methods.

  • my question was for magento 1.9.3 sorry i didn't note that – Yehuda Schwartz Nov 23 '16 at 17:40
  • I suppose my answer also will be relevant for Magento 1.x with some changes. – joni jones Nov 23 '16 at 17:50
  • the _parseCgiResponse method won't give any time info the _parseXmlResponse has some but not what is needed as noted in the response below – Yehuda Schwartz Nov 24 '16 at 18:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.