You are here

function uc_usps_quote in Ubercart 6.2

Same name and namespace in other branches
  1. 5 shipping/uc_usps/uc_usps.module \uc_usps_quote()
  2. 7.3 shipping/uc_usps/uc_usps.module \uc_usps_quote()

Callback for retrieving USPS shipping quote.

Parameters

$products: Array of cart contents.

$details: Order details other than product information.

$method: The shipping method to create the quote.

Return value

JSON object containing rate, error, and debugging information.

1 string reference to 'uc_usps_quote'
uc_usps_shipping_method in shipping/uc_usps/uc_usps.module
Implements hook_shipping_method().

File

shipping/uc_usps/uc_usps.module, line 340
Shipping quote method module that receives quotes from the United States Postal Service via XML web service.

Code

function uc_usps_quote($products, $details, $method) {

  // The uc_quote AJAX query can fire before the customer has completely
  // filled out the destination address, so check to see whether the address
  // has all needed fields. If not, abort.
  $destination = (object) $details;

  // Country code is always needed.
  if (empty($destination->country)) {

    // Skip this shipping method.
    return array();
  }

  // Shipments to the US also need zone and postal_code.
  if ($destination->country == 840 && (empty($destination->zone) || empty($destination->postal_code))) {

    // Skip this shipping method.
    return array();
  }

  // USPS Production server.
  $connection_url = 'http://production.shippingapis.com/ShippingAPI.dll';

  // Initialize $services to prevent PHP notices here and in uc_quote.
  $services['data'] = array(
    'debug' => NULL,
    'error' => '',
  );
  $addresses = array(
    (array) variable_get('uc_quote_store_default_address', new stdClass()),
  );
  $packages = _uc_usps_package_products($products, $addresses);
  if (!count($packages)) {
    return array();
  }
  foreach ($packages as $key => $ship_packages) {
    $orig = (object) $addresses[$key];
    $orig->email = uc_store_email();
    if (strpos($method['id'], 'intl') && $destination->country != 840) {

      // Build XML for international rate request
      $request = uc_usps_intl_rate_request($ship_packages, $orig, $destination);
    }
    elseif ($destination->country == 840) {

      // Build XML for domestic rate request
      $request = uc_usps_rate_request($ship_packages, $orig, $destination);
    }
    if (user_access('configure quotes') && variable_get('uc_quote_display_debug', FALSE)) {
      $services['data']['debug'] .= htmlentities(urldecode($request)) . "<br />\n";
    }
    $result = drupal_http_request($connection_url, array(), 'POST', $request);
    if (user_access('configure quotes') && variable_get('uc_quote_display_debug', FALSE)) {
      $services['data']['debug'] .= htmlentities($result->data) . "<br />\n";
    }
    $rate_type = variable_get('uc_usps_online_rates', FALSE);
    $response = new SimpleXMLElement($result->data);

    // Map double-encoded HTML markup in service names to Unicode characters
    $service_markup = array(
      '&lt;sup&gt;&amp;reg;&lt;/sup&gt;' => '®',
      '&lt;sup&gt;&amp;trade;&lt;/sup&gt;' => '™',
      '&lt;sup&gt;&#174;&lt;/sup&gt;' => '®',
      '&lt;sup&gt;&#8482;&lt;/sup&gt;' => '™',
      '**' => '',
    );

    // Use this map to fix USPS service names
    if (strpos($method['id'], 'intl')) {

      // Find and replace markup in International service names
      foreach ($response
        ->xpath('//Service') as $service) {
        $service->SvcDescription = str_replace(array_keys($service_markup), $service_markup, $service->SvcDescription);
      }
    }
    else {

      // Find and replace markup in Domestic service names
      foreach ($response
        ->xpath('//Postage') as $postage) {
        $postage->MailService = str_replace(array_keys($service_markup), $service_markup, $postage->MailService);
      }
    }
    if (isset($response->Package)) {
      foreach ($response->Package as $package) {
        if (isset($package->Error)) {
          $services['data']['error'] .= (string) $package->Error[0]->Description . '<br />';
        }
        else {
          if (strpos($method['id'], 'intl')) {
            foreach ($package->Service as $service) {
              $id = (string) $service['ID'];
              $services[$id]['label'] = t('U.S.P.S. @service', array(
                '@service' => (string) $service->SvcDescription,
              ));

              // Markup rate before customer sees it
              if (!isset($services[$id]['rate'])) {
                $services[$id]['rate'] = 0;
              }
              $services[$id]['rate'] += uc_usps_markup((string) $service->Postage);
            }
          }
          else {
            foreach ($package->Postage as $postage) {
              $classid = (string) $postage['CLASSID'];
              if ($classid === '0') {
                if ((string) $postage->MailService == "First-Class Mail® Parcel") {
                  $classid = 'zeroParcel';
                }
                elseif ((string) $postage->MailService == "First-Class Mail® Letter") {
                  $classid = 'zeroFlat';
                }
                else {
                  $classid = 'zero';
                }
              }
              if (!isset($services[$classid]['rate'])) {
                $services[$classid]['rate'] = 0;
              }
              $services[$classid]['label'] = t('U.S.P.S. @service', array(
                '@service' => (string) $postage->MailService,
              ));

              // Markup rate before customer sees it
              // Rates are stored differently if ONLINE $rate_type is requested.
              // First Class doesn't have online rates, so if CommercialRate
              // is missing use Rate instead
              if ($rate_type && !empty($postage->CommercialRate)) {
                $services[$classid]['rate'] += uc_usps_markup((string) $postage->CommercialRate);
              }
              else {
                $services[$classid]['rate'] += uc_usps_markup((string) $postage->Rate);
              }
            }
          }
        }
      }
    }
  }
  $method_services = 'uc_' . $method['id'] . '_services';
  $usps_services = array_filter(variable_get($method_services, array_keys(call_user_func('_' . $method_services))));
  foreach ($services as $service => $quote) {
    if ($service != 'data' && !in_array($service, $usps_services)) {
      unset($services[$service]);
    }
  }
  $context = array(
    'revision' => 'themed',
    'type' => 'amount',
  );
  foreach ($services as $key => $quote) {
    if (isset($quote['rate'])) {
      $context['subject']['quote'] = $quote;
      $context['revision'] = 'altered';
      $services[$key]['rate'] = uc_price($quote['rate'], $context);
      $context['revision'] = 'formatted';
      $services[$key]['format'] = uc_price($quote['rate'], $context);
      $services[$key]['option_label'] = theme('uc_usps_option_label', $quote['label'], $packages);
    }
  }

  // Separate debug data out of $services.  This is necessary because
  // $services['data'] is not sortable by a 'rate' key, so it has to be
  // kept separate from the reset of the $services array until after the sort.
  $debug_data = $services['data'];
  unset($services['data']);
  uasort($services, 'uc_quote_price_sort');
  if (isset($debug_data['debug']) || isset($debug_data['error']) && count($debug_data['error'])) {
    $services['data'] = $debug_data;
  }
  return $services;
}