function uc_ups_quote in Ubercart 7.3
Same name and namespace in other branches
- 8.4 shipping/uc_ups/uc_ups.module \uc_ups_quote()
- 5 shipping/uc_ups/uc_ups.module \uc_ups_quote()
- 6.2 shipping/uc_ups/uc_ups.module \uc_ups_quote()
Callback for retrieving a UPS shipping quote.
Requests 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.
$method: The shipping method to create the quote.
Return value
JSON object containing rate, error, and debugging information.
2 string references to 'uc_ups_quote'
- hook_uc_shipping_method in shipping/
uc_quote/ uc_quote.api.php - Defines callbacks and service options for shipping methods.
- uc_ups_uc_shipping_method in shipping/
uc_ups/ uc_ups.module - Implements hook_uc_shipping_method().
File
- shipping/
uc_ups/ uc_ups.module, line 551 - UPS shipping quote module.
Code
function uc_ups_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;
if (empty($destination->zone) || empty($destination->postal_code) || empty($destination->country)) {
// Skip this shipping method.
return array();
}
$quotes = array();
$addresses = array(
variable_get('uc_quote_store_default_address', new UcAddress()),
);
$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.
$key = NULL;
$address = uc_quote_get_default_shipping_address($product->nid);
foreach ($addresses as $index => $value) {
if ($address
->isSamePhysicalLocation($value)) {
// This is an existing address.
$key = $index;
break;
}
}
if (!isset($key)) {
// 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();
}
// Grab some product properties directly from the (cached) product
// data. They are not normally available here because the $product
// object is being read out of the $order object rather than from
// the database, and the $order object only carries around a limited
// number of product properties.
$temp = node_load($product->nid);
$product->length = $temp->length;
$product->width = $temp->width;
$product->height = $temp->height;
$product->length_units = $temp->length_units;
$product->ups['pkg_type'] = isset($temp->ups) ? $temp->ups['pkg_type'] : '02';
$weight = $product->weight * $product->qty * uc_weight_conversion($product->weight_units, 'lb');
$package->weight += $weight;
$package->price += $product->price * $product->qty;
$length_factor = uc_length_conversion($product->length_units, 'in');
$package->length = max($product->length * $length_factor, $package->length);
$package->width = max($product->width * $length_factor, $package->width);
$package->height = max($product->height * $length_factor, $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 = uc_quote_get_default_shipping_address($product->nid);
if (in_array($address, $addresses)) {
// This is an existing address.
foreach ($addresses as $index => $value) {
if ($address == $value) {
$key = $index;
break;
}
}
}
else {
// This is a new address.
$addresses[++$last_key] = $address;
$key = $last_key;
}
}
if (!isset($product->pkg_qty) || !$product->pkg_qty) {
$product->pkg_qty = 1;
}
$num_of_pkgs = (int) ($product->qty / $product->pkg_qty);
// Grab some product properties directly from the (cached) product
// data. They are not normally available here because the $product
// object is being read out of the $order object rather than from
// the database, and the $order object only carries around a limited
// number of product properties.
$temp = node_load($product->nid);
$product->length = $temp->length;
$product->width = $temp->width;
$product->height = $temp->height;
$product->length_units = $temp->length_units;
$product->ups['pkg_type'] = isset($temp->ups) ? $temp->ups['pkg_type'] : '02';
if ($num_of_pkgs) {
$package = 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['pkg_type'];
if ($package->weight) {
$packages[$key][] = $package;
}
}
$remaining_qty = $product->qty % $product->pkg_qty;
if ($remaining_qty) {
$package = 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['pkg_type'];
if ($package->weight) {
$packages[$key][] = $package;
}
}
}
}
if (!count($packages)) {
return array();
}
$dest = (object) $details;
foreach ($packages as $key => $ship_packages) {
$orig = $addresses[$key];
$orig->email = 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(
'method' => 'POST',
'data' => $request,
));
if (user_access('configure quotes') && variable_get('uc_quote_display_debug', FALSE)) {
if (!isset($debug_data[$ups_service]['debug'])) {
$debug_data[$ups_service]['debug'] = '';
}
$debug_data[$ups_service]['debug'] .= htmlentities($request) . ' <br /><br /> ' . htmlentities($resp->data);
}
$response = new SimpleXMLElement($resp->data);
if (isset($response->Response->Error)) {
foreach ($response->Response->Error as $error) {
if (user_access('configure quotes') && variable_get('uc_quote_display_debug', FALSE)) {
$debug_data[$ups_service]['error'][] = (string) $error->ErrorSeverity . ' ' . (string) $error->ErrorCode . ': ' . (string) $error->ErrorDescription;
}
if (strpos((string) $error->ErrorSeverity, 'Hard') !== FALSE) {
// 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->RatedShipment)) {
$charge = $response->RatedShipment->TotalCharges;
if (isset($response->RatedShipment->NegotiatedRates)) {
$charge = $response->RatedShipment->NegotiatedRates->NetSummaryCharges->GrandTotal;
}
if (!isset($charge->CurrencyCode) || (string) $charge->CurrencyCode == variable_get('uc_currency_code', "USD")) {
// Markup rate before customer sees it.
if (!isset($quotes[$ups_service]['rate'])) {
$quotes[$ups_service]['rate'] = 0;
}
$rate = uc_ups_rate_markup((string) $charge->MonetaryValue);
$quotes[$ups_service]['rate'] += $rate;
}
}
}
}
// Sort quotes by price, lowest to highest.
uasort($quotes, 'uc_quote_price_sort');
foreach ($quotes as $key => $quote) {
if (isset($quote['rate'])) {
$quotes[$key]['rate'] = $quote['rate'];
$quotes[$key]['label'] = $method['quote']['accessorials'][$key];
$quotes[$key]['option_label'] = theme('uc_ups_option_label', array(
'service' => $method['quote']['accessorials'][$key],
'packages' => $packages,
));
}
}
// Merge debug data into $quotes. This is necessary because
// $debug_data is not sortable by a 'rate' key, so it has to be
// kept separate from the $quotes data until this point.
if (isset($debug_data)) {
foreach ($debug_data as $key => $data) {
if (isset($quotes[$key])) {
// This is debug data for successful quotes.
$quotes[$key]['debug'] = $debug_data[$key]['debug'];
if (isset($debug_data[$key]['error'])) {
$quotes[$key]['error'] = $debug_data[$key]['error'];
}
}
else {
// This is debug data for quotes that returned error responses from UPS.
$quotes[$key] = $debug_data[$key];
}
}
}
return $quotes;
}