function uc_ups_quote in Ubercart 5
Same name and namespace in other branches
- 8.4 shipping/uc_ups/uc_ups.module \uc_ups_quote()
- 6.2 shipping/uc_ups/uc_ups.module \uc_ups_quote()
- 7.3 shipping/uc_ups/uc_ups.module \uc_ups_quote()
Callback for retrieving a UPS shipping quote.
Request a quote for each enabled UPS Service. Therefore, the quote will take longer to display to the user for each option the customer has available.
Parameters
$products: Array of cart contents.
$details: Order details other than product information.
Return value
JSON object containing rate, error, and debugging information.
2 string references to 'uc_ups_quote'
- hook_shipping_method in docs/
hooks.php - Define callbacks and service options for shipping methods.
- uc_ups_shipping_method in shipping/
uc_ups/ uc_ups.module - Implementation of Übercart's hook_shipping_method().
File
- shipping/
uc_ups/ uc_ups.module, line 805 - Shipping quote module that interfaces with www.ups.com to get rates for small package shipments.
Code
function uc_ups_quote($products, $details) {
include_once drupal_get_path('module', 'uc_store') . '/includes/simplexml.php';
$quotes = array();
$method = uc_ups_shipping_method();
$addresses = array(
(array) variable_get('uc_quote_store_default_address', new stdClass()),
);
$key = 0;
$last_key = 0;
$packages = array();
if (variable_get('uc_ups_all_in_one', true) && count($products) > 1) {
foreach ($products as $product) {
if ($product->nid) {
// Packages are grouped by the address from which they will be
// shipped. We will keep track of the different addresses in an array
// and use their keys for the array of packages.
$address = (array) uc_quote_get_default_shipping_address($product->nid);
$key = array_search($address, $addresses);
if ($key === false) {
// This is a new address. Increment the address counter $last_key
// instead of using [] so that it can be used in $packages and
// $addresses.
$addresses[++$last_key] = $address;
$key = $last_key;
}
}
// Add this product to the last package from the found address or start
// a new package.
if (isset($packages[$key]) && count($packages[$key])) {
$package = array_pop($packages[$key]);
}
else {
$package = _uc_ups_new_package();
}
$weight = $product->weight * $product->qty * uc_weight_conversion($product->weight_units, 'lb');
$package->weight += $weight;
$package->price += $product->price * $product->qty;
$conversion = uc_weight_conversion($product->length_units, 'in');
$package->length = max($product->length * $conversion, $package->length);
$package->width = max($product->width * $conversion, $package->width);
$package->height = max($product->height * $conversion, $package->height);
$packages[$key][] = $package;
}
foreach ($packages as $addr_key => $shipment) {
foreach ($shipment as $key => $package) {
if (!$package->weight) {
unset($packages[$addr_key][$key]);
continue;
}
elseif ($package->weight > 150) {
// UPS has a weight limit on packages of 150 lbs. Pretend the
// products can be divided into enough packages.
$qty = floor($package->weight / 150) + 1;
$package->qty = $qty;
$package->weight /= $qty;
$package->price /= $qty;
}
}
}
}
else {
foreach ($products as $product) {
$key = 0;
if ($product->nid) {
$address = (array) uc_quote_get_default_shipping_address($product->nid);
$key = array_search($address, $addresses);
if ($key === false) {
$addresses[++$last_key] = $address;
$key = $last_key;
}
}
if (!$product->pkg_qty) {
$product->pkg_qty = 1;
}
$num_of_pkgs = (int) ($product->qty / $product->pkg_qty);
if ($num_of_pkgs) {
$package = drupal_clone($product);
$package->description = $product->model;
$package->weight = $product->weight * $product->pkg_qty;
$package->price = $product->price * $product->pkg_qty;
$package->qty = $num_of_pkgs;
$package->pkg_type = $product->ups ? $product->ups['pkg_type'] : '02';
if ($package->weight) {
$packages[$key][] = $package;
}
}
$remaining_qty = $product->qty % $product->pkg_qty;
if ($remaining_qty) {
$package = drupal_clone($product);
$package->description = $product->model;
$package->weight = $product->weight * $remaining_qty;
$package->price = $product->price * $remaining_qty;
$package->qty = 1;
$package->pkg_type = $product->ups ? $product->ups['pkg_type'] : '02';
if ($package->weight) {
$packages[$key][] = $package;
}
}
}
}
if (!count($packages)) {
return array();
}
$dest = (object) $details;
foreach ($packages as $key => $ship_packages) {
$orig = (object) $addresses[$key];
$orig->email = variable_get('uc_store_email', '');
foreach (array_keys(array_filter(variable_get('uc_ups_services', array()))) as $ups_service) {
$request = uc_ups_shipping_quote($ship_packages, $orig, $dest, $ups_service);
$resp = drupal_http_request(variable_get('uc_ups_connection_address', 'https://wwwcie.ups.com/ups.app/xml/') . 'Rate', array(), 'POST', $request);
if (user_access('configure quotes') && variable_get('uc_quote_display_debug', false)) {
$quotes[$ups_service]['debug'] .= htmlentities($request) . ' <br /><br /> ' . htmlentities($resp->data);
}
$response = new JSimpleXML();
$response
->loadString($resp->data);
if (isset($response->document->response[0]->error)) {
foreach ($response->document->response[0]->error as $error) {
if (user_access('configure quotes') && variable_get('uc_quote_display_debug', false)) {
$quotes[$ups_service]['error'][] = $error->errorseverity[0]
->data() . ' ' . $error->errorcode[0]
->data() . ': ' . $error->errordescription[0]
->data();
}
if ($error->errorseverity[0]
->data() == 'HardError') {
// All or nothing quote. If some products can't be shipped by
// a certain service, no quote is given for that service. If
// that means no quotes are given at all, they'd better call in.
unset($quotes[$ups_service]['rate']);
}
}
}
// if NegotiatedRates exist, quote based on those, otherwise, use TotalCharges
if (isset($response->document->ratedshipment)) {
$charge = $response->document->ratedshipment[0]->totalcharges[0];
if (isset($response->document->ratedshipment[0]->negotiatedrates)) {
$charge = $response->document->ratedshipment[0]->negotiatedrates[0]->netsummarycharges[0]->grandtotal[0];
}
if (!isset($charge->currencycode) || $charge->currencycode[0]
->data() == variable_get('uc_currency_code', "USD")) {
$rate = uc_ups_markup($charge->monetaryvalue[0]
->data());
$quotes[$ups_service]['rate'] += $rate;
}
}
}
}
uasort($quotes, 'uc_quote_price_sort');
foreach ($quotes as $key => $quote) {
if (isset($quote['rate'])) {
$quotes[$key]['format'] = uc_currency_format($quote['rate']);
$quotes[$key]['option_label'] = '<img class="ups_logo" src="' . base_path() . drupal_get_path('module', 'uc_ups') . '/uc_ups_logo.gif" /> ' . $method['ups']['quote']['accessorials'][$key] . t(' Rate');
}
}
/**
* Ugly hack to work around PHP bug, details here:
* http://bugs.php.net/bug.php?id=23220
* We strip out errors that look something like:
* warning: fread() [function.fread]: SSL fatal protocol error in...
* Copied from http://drupal.org/node/70915 and then improved by Lyle.
*/
$messages = drupal_set_message();
$errors = $messages['error'];
$total = count($errors);
for ($i = 0; $i <= $total; $i++) {
if (strpos($errors[$i], 'SSL: fatal protocol error in')) {
unset($_SESSION['messages']['error'][$i]);
}
}
if (empty($_SESSION['messages']['error'])) {
unset($_SESSION['messages']['error']);
}
db_query("DELETE FROM {watchdog} WHERE type = 'php' AND message LIKE '%%SSL: fatal protocol error%%'");
// End of ugly hack.
return $quotes;
}