'UPS', 'page callback' => 'drupal_get_form', 'page arguments' => array('uc_ups_admin_settings'), 'access arguments' => array('configure quotes'), 'type' => MENU_LOCAL_TASK, 'file' => 'uc_ups.admin.inc', ); $items['admin/store/orders/%uc_order/shipments/ups'] = array( 'title' => 'UPS shipment', 'page callback' => 'drupal_get_form', 'page arguments' => array('uc_ups_confirm_shipment', 3), 'access arguments' => array('fulfill orders'), 'type' => MENU_CALLBACK, 'file' => 'uc_ups.admin.inc', ); $items['admin/store/orders/%uc_order/shipments/labels/ups'] = array( 'page callback' => 'theme', 'page arguments' => array('uc_ups_label_image'), 'access arguments' => array('fulfill orders'), 'type' => MENU_CALLBACK, 'file' => 'uc_ups.admin.inc', ); return $items; } /** * Implementation of hook_init(). */ function uc_ups_init() { drupal_add_css(drupal_get_path('module', 'uc_ups') .'/uc_ups.css'); } /** * Implementation of hook_theme(). */ function uc_ups_theme() { return array( 'uc_ups_confirm_shipment' => array( 'arguments' => array('form' => NULL), 'file' => 'uc_ups.admin.inc', ), 'uc_ups_label_image' => array( 'arguments' => array(), 'file' => 'uc_ups.admin.inc', ), 'uc_ups_option_label' => array( 'arguments' => array('service' => NULL), ), ); } /** * Implementation of hook_form_alter(). * * Add package type to products. * * @see uc_product_form() * @see uc_ups_product_alter_validate() */ function uc_ups_form_alter(&$form, $form_state, $form_id) { if (uc_product_is_product_form($form)) { $node = $form['#node']; $enabled = variable_get('uc_quote_enabled', array()); $weight = variable_get('uc_quote_method_weight', array('ups' => 0)); $ups = array( '#type' => 'fieldset', '#title' => t('UPS product description'), '#collapsible' => TRUE, '#collapsed' => ($enabled['ups'] == FALSE || uc_product_get_shipping_type($node) != 'small_package'), '#weight' => $weight['ups'], '#tree' => TRUE, ); $ups['pkg_type'] = array( '#type' => 'select', '#title' => t('Package type'), '#options' => _uc_ups_pkg_types(), '#default_value' => $node->ups['pkg_type'] ? $node->ups['pkg_type'] : variable_get('uc_ups_pkg_type', '02'), ); $form['shipping']['ups'] = $ups; if ($enabled['ups']) { $form['#validate'][] = 'uc_ups_product_alter_validate'; } } } /** * Validation handler for UPS product fields. * * @see uc_ups_form_alter() */ function uc_ups_product_alter_validate($form, &$form_state) { $enabled = variable_get('uc_quote_enabled', array()); if ($form_state['values']['shippable'] && ($form_state['values']['shipping_type'] == 'small_package' || (empty($form_state['values']['shipping_type']) && variable_get('uc_store_shipping_type', 'small_package') == 'small_package'))) { if ($form_state['values']['ups']['pkg_type'] == '02' && (empty($form_state['values']['dim_length']) || empty($form_state['values']['dim_width']) || empty($form_state['values']['dim_height']))) { form_set_error('base][dimensions', t('Dimensions are required for custom packaging.')); } } } /** * Implementation of hook_nodeapi(). */ function uc_ups_nodeapi(&$node, $op) { if (uc_product_is_product($node->type)) { switch ($op) { case 'insert': case 'update': if (isset($node->ups)) { $ups_values = $node->ups; if (!$node->revision) { db_query("DELETE FROM {uc_ups_products} WHERE vid = %d", $node->vid); } db_query("INSERT INTO {uc_ups_products} (vid, nid, pkg_type) VALUES (%d, %d, '%s')", $node->vid, $node->nid, $ups_values['pkg_type']); } break; case 'load': if (uc_product_get_shipping_type($node) == 'small_package') { return array('ups' => db_fetch_array(db_query("SELECT * FROM {uc_ups_products} WHERE vid = %d", $node->vid))); } break; case 'delete': db_query("DELETE FROM {uc_ups_products} WHERE nid = %d", $node->nid); break; case 'delete revision': db_query("DELETE FROM {uc_ups_products} WHERE vid = %d", $node->vid); break; } } } /****************************************************************************** * Conditional Actions Hooks * ******************************************************************************/ /** * Implementation of hook_ca_predicate(). * * Connect the UPS quote action and event. */ function uc_ups_ca_predicate() { $enabled = variable_get('uc_quote_enabled', array()); $predicates = array( 'uc_ups_get_quote' => array( '#title' => t('Shipping quote from UPS'), '#trigger' => 'get_quote_from_ups', '#class' => 'uc_ups', '#status' => $enabled['ups'], '#actions' => array( array( '#name' => 'uc_quote_action_get_quote', '#title' => t('Fetch a shipping quote'), '#argument_map' => array( 'order' => 'order', 'method' => 'method', ), ), ), ), ); return $predicates; } /****************************************************************************** * Ubercart Hooks * ******************************************************************************/ /** * Implementation of hook_shipping_type(). */ function uc_ups_shipping_type() { $weight = variable_get('uc_quote_type_weight', array('small_package' => 0)); $types = array(); $types['small_package'] = array( 'id' => 'small_package', 'title' => t('Small packages'), 'weight' => $weight['small_package'], ); return $types; } /** * Implementation of hook_shipping_method(). */ function uc_ups_shipping_method() { $methods = array(); $enabled = variable_get('uc_quote_enabled', array()); $weight = variable_get('uc_quote_method_weight', array('ups' => 0)); $methods['ups'] = array( 'id' => 'ups', 'module' => 'uc_ups', 'title' => t('UPS'), 'enabled' => $enabled['ups'], 'quote' => array( 'type' => 'small_package', 'callback' => 'uc_ups_quote', 'accessorials' => _uc_ups_service_list(), ), 'ship' => array( 'type' => 'small_package', 'callback' => 'uc_ups_fulfill_order', 'pkg_types' => _uc_ups_pkg_types(), ), 'cancel' => 'uc_ups_void_shipment', 'weight' => $weight['ups'], ); return $methods; } /** * Implementation of hook_store_status(). * * Let the administrator know that the UPS account information has not been * filled out. */ function uc_ups_store_status() { $messages = array(); $access = variable_get('uc_ups_access_license', '') != ''; $account = variable_get('uc_ups_shipper_number', '') != ''; $user = variable_get('uc_ups_user_id', '') != ''; $password = variable_get('uc_ups_password', '') != ''; if ($access && $account && $user && $password) { $messages[] = array('status' => 'ok', 'title' => t('UPS Online Tools'), 'desc' => t('Information needed to access UPS Online Tools has been entered.'), ); } else { $messages[] = array('status' => 'error', 'title' => t('UPS Online Tools'), 'desc' => t('More information is needed to access UPS Online Tools. Please enter it here.', array('!url' => url('admin/store/settings/quotes/methods/ups'))), ); } return $messages; } /****************************************************************************** * Module Functions * ******************************************************************************/ /** * Return XML access request to be prepended to all requests to the UPS webservice. */ function uc_ups_access_request() { $access = variable_get('uc_ups_access_license', ''); $user = variable_get('uc_ups_user_id', ''); $password = variable_get('uc_ups_password', ''); return " $access $user $password "; } /** * Construct an XML quote request. * * @param $packages * Array of packages received from the cart. * @param $origin * Delivery origin address information. * @param $destination * Delivery destination address information. * @param $ups_service * UPS service code (refers to UPS Ground, Next-Day Air, etc.). * @return * RatingServiceSelectionRequest XML document to send to UPS */ function uc_ups_shipping_quote($packages, $origin, $destination, $ups_service) { $store['name'] = variable_get('uc_store_name', NULL); $store['owner'] = variable_get('uc_store_owner', NULL); $store['email'] = variable_get('uc_store_email', NULL); $store['email_from'] = variable_get('uc_store_email', NULL); $store['phone'] = variable_get('uc_store_phone', NULL); $store['fax'] = variable_get('uc_store_fax', NULL); $store['street1'] = variable_get('uc_store_street1', NULL); $store['street2'] = variable_get('uc_store_street2', NULL); $store['city'] = variable_get('uc_store_city', NULL); $store['zone'] = variable_get('uc_store_zone', NULL); $store['postal_code'] = variable_get('uc_store_postal_code', NULL); $store['country'] = variable_get('uc_store_country', 840); $account = variable_get('uc_ups_shipper_number', ''); $ua = explode(' ', $_SERVER['HTTP_USER_AGENT']); $user_agent = $ua[0]; $services = _uc_ups_service_list(); $service = array('code' => $ups_service, 'description' => $services[$ups_service]); $pkg_types = _uc_ups_pkg_types(); $shipper_zone = uc_get_zone_code($store['zone']); $shipper_country = uc_get_country_data(array('country_id' => $store['country'])); $shipper_country = $shipper_country[0]['country_iso_code_2']; $shipper_zip = $store['postal_code']; $shipto_zone = uc_get_zone_code($destination->zone); $shipto_country = uc_get_country_data(array('country_id' => $destination->country)); $shipto_country = $shipto_country[0]['country_iso_code_2']; $shipto_zip = $destination->postal_code; $shipfrom_zone = uc_get_zone_code($origin->zone); $shipfrom_country = uc_get_country_data(array('country_id' => $origin->country)); $shipfrom_country = $shipfrom_country[0]['country_iso_code_2']; $shipfrom_zip = $origin->postal_code; $ups_units = variable_get('uc_ups_unit_system', variable_get('uc_length_unit', 'in')); switch ($ups_units) { case 'in': $units = 'LBS'; $unit_name = 'Pounds'; break; case 'cm': $units = 'KGS'; $unit_name = 'Kilograms'; break; } $shipment_weight = 0; $package_schema = ''; foreach ($packages as $package) { $qty = $package->qty; for ($i = 0; $i < $qty; $i++) { $package_type = array('code' => $package->pkg_type, 'description' => $pkg_types[$package->pkg_type]); $package_schema .= ""; $package_schema .= ""; $package_schema .= "". $package_type['code'] .""; //$package_schema .= "". $package_type['description'] .""; $package_schema .= ""; if ($package->pkg_type == '02' && $package->length && $package->width && $package->height) { if ($package->length < $package->width) { list($package->length, $package->width) = array($package->width, $package->length); } $package_schema .= ""; $package_schema .= ""; $conversion = uc_length_conversion($package->length_units, variable_get('uc_ups_unit_system', variable_get('uc_length_unit', 'in'))); $package_schema .= "". strtoupper(variable_get('uc_ups_unit_system', variable_get('uc_length_unit', 'in'))) .""; $package_schema .= ""; $package_schema .= "". number_format($package->length * $conversion, 2, '.', '') .""; $package_schema .= "". number_format($package->width * $conversion, 2, '.', '') .""; $package_schema .= "". number_format($package->height * $conversion, 2, '.', '') .""; $package_schema .= ""; } $size = $package->length * $conversion + 2 * $conversion * ($package->width + $package->height); switch ($ups_units) { case 'in': $conversion = uc_weight_conversion($package->weight_units, 'lb'); break; case 'cm': $conversion = uc_weight_conversion($package->weight_units, 'kg'); break; } $weight = max(1, $package->weight * $conversion); $shipment_weight += $weight; $package_schema .= ""; $package_schema .= ""; $package_schema .= "$units"; $package_schema .= "$unit_name"; $package_schema .= ""; $package_schema .= "". number_format($weight, 1, '.', '') .""; $package_schema .= ""; if ($size > 130 && $size <= 165) { $package_schema .= ""; } if (variable_get('uc_ups_insurance', TRUE)) { $package_schema .= ""; $package_schema .= ""; $package_schema .= "". variable_get('uc_currency_code', 'USD') .""; $package_schema .= "". $package->price .""; $package_schema .= ""; $package_schema .= ""; } $package_schema .= ""; } } $schema = uc_ups_access_request() ." Complex Rate Request 1.0001 Rate rate ". variable_get('uc_ups_pickup_type', '01') ." ". variable_get('uc_ups_classification', '04') ." ". variable_get('uc_ups_shipper_number', '') ."
". $store['city'] ." $shipper_zone $shipper_zip $shipper_country
$shipto_zone $shipto_zip $shipto_country "; if (variable_get('uc_ups_residential_quotes', 0)) { $schema .= " "; } $schema .= "
$shipfrom_zone $shipfrom_zip $shipfrom_country
$units $unit_name ". number_format($shipment_weight, 1, '.', '') ." {$service[code]} {$service[description]} "; $schema .= $package_schema; if (variable_get('uc_ups_negotiated_rates', FALSE)) { $schema .= " "; } $schema .= "
"; return $schema; } /** * Construct an XML shippment request. * * @param $packages * Array of packages received from the cart. * @param $origin * Delivery origin address information. * @param $destination * Delivery destination address information. * @param $ups_service * UPS service code (refers to UPS Ground, Next-Day Air, etc.). * @return * ShipConfirm XML document to send to UPS */ function uc_ups_shipment_request($packages, $origin, $destination, $ups_service) { $store['name'] = variable_get('uc_store_name', NULL); $store['owner'] = variable_get('uc_store_owner', NULL); $store['email'] = variable_get('uc_store_email', NULL); $store['email_from'] = variable_get('uc_store_email', NULL); $store['phone'] = variable_get('uc_store_phone', NULL); $store['fax'] = variable_get('uc_store_fax', NULL); $store['street1'] = variable_get('uc_store_street1', NULL); $store['street2'] = variable_get('uc_store_street2', NULL); $store['city'] = variable_get('uc_store_city', NULL); $store['zone'] = variable_get('uc_store_zone', NULL); $store['postal_code'] = variable_get('uc_store_postal_code', NULL); $store['country'] = variable_get('uc_store_country', 840); $account = variable_get('uc_ups_shipper_number', ''); $ua = explode(' ', $_SERVER['HTTP_USER_AGENT']); $user_agent = $ua[0]; $services = _uc_ups_service_list(); $service = array('code' => $ups_service, 'description' => $services[$ups_service]); $pkg_types = _uc_ups_pkg_types(); $shipper_zone = uc_get_zone_code($store['zone']); $shipper_country = uc_get_country_data(array('country_id' => $store['country'])); $shipper_country = $shipper_country[0]['country_iso_code_2']; $shipper_zip = $store['postal_code']; $shipto_zone = uc_get_zone_code($destination->zone); $shipto_country = uc_get_country_data(array('country_id' => $destination->country)); $shipto_country = $shipto_country[0]['country_iso_code_2']; $shipto_zip = $destination->postal_code; $shipfrom_zone = uc_get_zone_code($origin->zone); $shipfrom_country = uc_get_country_data(array('country_id' => $origin->country)); $shipfrom_country = $shipfrom_country[0]['country_iso_code_2']; $shipfrom_zip = $origin->postal_code; $ups_units = variable_get('uc_ups_unit_system', variable_get('uc_length_unit', 'in')); $package_schema = ''; foreach ($packages as $package) { $qty = $package->qty; for ($i = 0; $i < $qty; $i++) { $package_type = array('code' => $package->pkg_type, 'description' => $pkg_types[$package->pkg_type]); $package_schema .= ""; $package_schema .= ""; $package_schema .= "". $package_type['code'] .""; $package_schema .= ""; if ($package->pkg_type == '02' && $package->length && $package->width && $package->height) { if ($package->length < $package->width) { list($package->length, $package->width) = array($package->width, $package->length); } $package_schema .= ""; $package_schema .= ""; $conversion = uc_length_conversion($package->length_units, variable_get('uc_ups_unit_system', variable_get('uc_length_unit', 'in'))); $package_schema .= "". strtoupper(variable_get('uc_ups_unit_system', variable_get('uc_length_unit', 'in'))) .""; $package_schema .= ""; $package_schema .= "". (floor($package->length * $conversion) + 1) .""; $package_schema .= "". (floor($package->width * $conversion) + 1) .""; $package_schema .= "". (floor($package->height * $conversion) + 1) .""; $package_schema .= ""; } $size = $package->length * $conversion + 2 * $conversion * ($package->width + $package->height); switch ($ups_units) { case 'in': $conversion = uc_weight_conversion($package->weight_units, 'lb'); break; case 'cm': $conversion = uc_weight_conversion($package->weight_units, 'kg'); break; } $weight = max(1, $package->weight * $conversion); $package_schema .= ""; $package_schema .= ""; $package_schema .= "$units"; $package_schema .= "$unit_name"; $package_schema .= ""; $package_schema .= "". number_format($weight, 1, '.', '') .""; $package_schema .= ""; if ($size > 130 && $size <= 165) { $package_schema .= ""; } $package_schema .= ""; $package_schema .= ""; $package_schema .= "". variable_get('uc_currency_code', 'USD') .""; $package_schema .= "". number_format($package->value, 2, '.', '') .""; $package_schema .= ""; $package_schema .= ""; $package_schema .= ""; } } $schema = uc_ups_access_request() ." Complex Rate Request 1.0001 ShipConfirm validate "; $schema .= ""; $schema .= "". $store['name'] .""; $schema .= "". variable_get('uc_ups_shipper_number', '') .""; if ($store['phone']) { $schema .= "". $store['phone'] .""; } if ($store['fax']) { $schema .= "". $store['fax'] .""; } if ($store['email']) { $schema .= "". $store['email'] .""; } $schema .= "
"; $schema .= "". $store['street1'] .""; if ($store['street2']) { $schema .= "". $store['street2'] .""; } $schema .= "". $store['city'] .""; $schema .= "$shipper_zone"; $schema .= "$shipper_zip"; $schema .= "$shipper_country"; $schema .= "
"; $schema .= "
"; $schema .= ""; $schema .= "". $destination->company .""; $schema .= "". $destination->first_name .' '. $destination->last_name .""; $schema .= "". $destination->phone .""; $schema .= "". $destination->email .""; $schema .= "
"; $schema .= "". $destination->street1 .""; if ($destination->street2) { $schema .= "". $destination->street2 .""; } $schema .= "". $destination->city .""; $schema .= "$shipto_zone"; $schema .= "$shipto_zip"; $schema .= "$shipto_country"; if ($destination->residence) { $schema .= ""; } $schema .= "
"; $schema .= "
"; $schema .= ""; $schema .= "". $origin->company .""; $schema .= "". $origin->first_name .' '. $origin->last_name .""; $schema .= "". $origin->phone .""; $schema .= "". $origin->email .""; $schema .= "
"; $schema .= "". $origin->street1 .""; if ($origin->street2) { $schema .= "". $origin->street2 .""; } $schema .= "". $origin->city .""; $schema .= "$shipfrom_zone"; $schema .= "$shipfrom_zip"; $schema .= "$shipfrom_country"; $schema .= "
"; $schema .= "
"; $schema .= ""; $schema .= ""; $schema .= ""; $schema .= "$account"; $schema .= ""; $schema .= ""; $schema .= ""; if (variable_get('uc_ups_negotiated_rates', FALSE)) { $schema .= " "; } $schema .= ""; $schema .= "{$service[code]}"; $schema .= "{$service[description]}"; $schema .= ""; $schema .= $package_schema; $schema .= "
"; $schema .= ""; $schema .= ""; $schema .= "GIF"; $schema .= ""; $schema .= ""; $schema .= "GIF"; $schema .= ""; $schema .= ""; $schema .= "
"; return $schema; } /** * 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. * * @param $products * Array of cart contents. * @param $details * Order details other than product information. * @return * JSON object containing rate, error, and debugging information. */ function uc_ups_quote($products, $details) { $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_length_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'] .= /* '
'. print_r($ship_packages, TRUE) .'
' . */ htmlentities($request) .'

'. 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)) { $quotes[$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")) { $rate = uc_ups_markup((string)$charge->MonetaryValue); $quotes[$ups_service]['rate'] += $rate; } } } } uasort($quotes, 'uc_quote_price_sort'); $context = array( 'revision' => 'themed', 'type' => 'amount', ); foreach ($quotes as $key => $quote) { if (isset($quote['rate'])) { $context['subject']['quote'] = $quote; $context['revision'] = 'altered'; $quotes[$key]['rate'] = uc_price($quote['rate'], $context); $context['revision'] = 'formatted'; $quotes[$key]['format'] = uc_price($quote['rate'], $context); $quotes[$key]['option_label'] = theme('uc_ups_option_label', $method['ups']['quote']['accessorials'][$key]); } } /** * 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 variables LIKE '%%SSL: fatal protocol error%%'"); // End of ugly hack. return $quotes; } /** * Theme function to format the UPS service name and rate amount line-item shown * to the customer. * * @param $service * The UPS service name. * @ingroup themeable */ function theme_uc_ups_option_label($service) { // Start with logo as required by the UPS terms of service. $output = ' '; // Add the UPS service name. $output .= t('@service Rate', array('@service' => $service)); return $output; } /** * Shipment creation callback. * * Confirm shipment data before requesting a shipping label. * * @param $order_id * The order id for the shipment. * @param $package_ids * Array of package ids to shipped. * @ingroup forms * @see * uc_ups_fulfill_order_validate() * uc_ups_fulfill_order_submit() */ function uc_ups_fulfill_order($form_state, $order, $package_ids) { $form = array(); $pkg_types = _uc_ups_pkg_types(); $form['order_id'] = array('#type' => 'value', '#value' => $order->order_id); $packages = array(); $addresses = array(); $form['packages'] = array('#tree' => TRUE); foreach ($package_ids as $id) { $package = uc_shipping_package_load($id); if ($package) { foreach ($package->addresses as $address) { if (!in_array($address, $addresses)) { $addresses[] = $address; } } // Create list of products and get a representative product for default values $product_list = array(); $declared_value = 0; foreach ($package->products as $product) { $product_list[] = $product->qty .' x '. $product->model; $declared_value += $product->qty * $product->price; } $ups_data = db_fetch_array(db_query("SELECT pkg_type FROM {uc_ups_products} WHERE nid = %d", $product->nid)); $product->ups = $ups_data; $pkg_form = array('#type' => 'fieldset', '#title' => t('Package !id', array('!id' => $id)), ); $pkg_form['products'] = array('#value' => theme('item_list', $product_list)); $pkg_form['package_id'] = array('#type' => 'hidden', '#value' => $id); $pkg_form['pkg_type'] = array('#type' => 'select', '#title' => t('Package type'), '#options' => $pkg_types, '#default_value' => $product->ups['pkg_type'], '#required' => TRUE, ); $pkg_form['declared_value'] = array('#type' => 'textfield', '#title' => t('Declared value'), '#default_value' => $declared_value, '#required' => TRUE, ); $pkg_type['dimensions'] = array('#type' => 'fieldset', '#title' => t('Dimensions'), '#description' => t('Physical dimensions of the package.'), '#theme' => 'uc_ups_dimensions', ); $pkg_form['dimensions']['units'] = array('#type' => 'select', '#title' => t('Units of measurement'), '#options' => array( 'in' => t('Inches'), 'ft' => t('Feet'), 'cm' => t('Centimeters'), 'mm' => t('Millimeters'), ), '#default_value' => $product->length_units ? $product->length_units : variable_get('uc_length_unit', 'in'), ); $pkg_form['dimensions']['length'] = array('#type' => 'textfield', '#title' => t('Length'), '#default_value' => $product->length, ); $pkg_form['dimensions']['width'] = array('#type' => 'textfield', '#title' => t('Width'), '#default_value' => $product->width, ); $pkg_form['dimensions']['height'] = array('#type' => 'textfield', '#title' => t('Height'), '#default_value' => $product->height, ); $form['packages'][$id] = $pkg_form; } } $form = array_merge($form, uc_shipping_address_form($form_state, $addresses, $order)); foreach (array('delivery_email', 'delivery_last_name', 'delivery_street1', 'delivery_city', 'delivery_zone', 'delivery_country', 'delivery_postal_code') as $field) { $form['destination'][$field]['#required'] = TRUE; } $services = _uc_ups_service_list(); $default_service = ''; $method = $order->quote['method']; if ($method == 'ups') { $default_service = $order->quote['accessorials']; $method = $services[$default_service]; } // Inform user of customer's shipping choice $form['shipping_choice'] = array( '#type' => 'markup', '#value' => t('Customer selected @method as the shipping method and paid @rate', array('@method' => $method, '@rate' => uc_currency_format($order->quote['rate']))), ); $form['service'] = array('#type' => 'select', '#title' => t('UPS service'), '#options' => $services, '#default_value' => $default_service, ); $today = getdate(); $form['ship_date'] = array('#type' => 'date', '#title' => t('Ship date'), '#default_value' => array('year' => $today['year'], 'month' => $today['mon'], 'day' => $today['mday']), ); $form['expected_delivery'] = array('#type' => 'date', '#title' => t('Expected delivery'), '#default_value' => array('year' => $today['year'], 'month' => $today['mon'], 'day' => $today['mday']), ); $form['submit'] = array('#type' => 'submit', '#value' => t('Review shipment')); return $form; } /** * Pass final information into shipment object. * * @see * uc_ups_fulfill_order() * uc_ups_confirm_shipment() */ function uc_ups_fulfill_order_validate($form, &$form_state) { $origin = new stdClass(); $destination = new stdClass(); $packages = array(); foreach ($form_state['values'] as $key => $value) { if (substr($key, 0, 7) == 'pickup_') { $field = substr($key, 7); $origin->$field = $value; } elseif (substr($key, 0, 9) == 'delivery_') { $field = substr($key, 9); $destination->$field = $value; } } $_SESSION['ups'] = array(); $_SESSION['ups']['origin'] = $origin; if (empty($destination->company)) { $destination->company = $destination->first_name .' '. $destination->last_name; } $_SESSION['ups']['destination'] = $destination; foreach ($form_state['values']['packages'] as $id => $pkg_form) { $package = uc_shipping_package_load($id); $package->pkg_type = $pkg_form['pkg_type']; $package->value = $pkg_form['declared_value']; $package->length = $pkg_form['dimensions']['length']; $package->width = $pkg_form['dimensions']['width']; $package->height = $pkg_form['dimensions']['height']; $package->length_units = $pkg_form['dimensions']['units']; $package->qty = 1; $_SESSION['ups']['packages'][$id] = $package; } $_SESSION['ups']['service'] = $form_state['values']['service']; $_SESSION['ups']['ship_date'] = $form_state['values']['ship_date']; $_SESSION['ups']['expected_delivery'] = $form_state['values']['expected_delivery']; $_SESSION['ups']['order_id'] = $form_state['values']['order_id']; $request = uc_ups_shipment_request($_SESSION['ups']['packages'], $origin, $destination, $form_state['values']['service']); //print htmlentities($request); $response_obj = drupal_http_request(variable_get('uc_ups_connection_address', 'https://wwwcie.ups.com/ups.app/xml/') .'ShipConfirm', array(), 'POST', $request); $response = new SimpleXMLElement($response_obj->data); //drupal_set_message('
'. htmlentities($response->asXML()) .'
'); if (isset($response->Response->Error)) { $error = $response->Response->Error; $error_msg = (string)$error->ErrorSeverity .' Error '. (string)$error->ErrorCode .': '. (string)$error->ErrorDescription; //drupal_set_message('
'. print_r($_SESSION['ups']['packages'], TRUE) .'
' . htmlentities($request) .'

'. htmlentities($response->data)); if (strpos((string)$error->ErrorSeverity, 'Hard') !== FALSE) { form_set_error('', $error_msg); return FALSE; } else { drupal_set_message($error_msg, 'error'); } } $charge = new stdClass(); // if NegotiatedRates exist, quote based on those, otherwise, use TotalCharges if (isset($response->ShipmentCharges)) { $charge = $response->ShipmentCharges->TotalCharges; $_SESSION['ups']['rate']['type'] = t('Total Charges'); if (isset($response->NegotiatedRates)) { $charge = $response->NegotiatedRates->NetSummaryCharges->GrandTotal; $_SESSION['ups']['rate']['type'] = t('Negotiated Rates'); } } $_SESSION['ups']['rate']['currency'] = (string)$charge->CurrencyCode; $_SESSION['ups']['rate']['amount'] = (string)$charge->MonetaryValue; $_SESSION['ups']['digest'] = (string)$response->ShipmentDigest; } /** * Pass final information into shipment object. * * @see * uc_ups_fulfill_order() * uc_ups_confirm_shipment() */ function uc_ups_fulfill_order_submit($form, &$form_state) { $form_state['redirect'] = 'admin/store/orders/'. $form_state['values']['order_id'] .'/shipments/ups'; } /** * Construct a void shipment request. * * @param $shipment_number * The UPS shipment tracking number. * @param $tracking_numbers * Array of tracking numbers for individual packages in the shipment. * Optional for shipments of only one package, as they have the same tracking * number. * @return * XML VoidShipmentRequest message. */ function uc_ups_void_shipment_request($shipment_number, $tracking_numbers = array()) { $schema = uc_ups_access_request(); $schema .= ''; $schema .= ''; $schema .= ''; $schema .= 'Void'; $schema .= ''; $schema .= ''; $schema .= t('Void shipment @ship_number and tracking numbers @track_list', array('@ship_number' => $shipment_number, '@track_list' => implode(', ', $tracking_numbers))); $schema .= ''; $schema .= '1.0'; $schema .= ''; $schema .= ''; $schema .= ''; $schema .= ''. $shipment_number .''; foreach ($tracking_numbers as $number) { $schema .= ''. $number .''; } $schema .= ''; $schema .= ''; return $schema; } /** * Instruct UPS to cancel (in whole or in part) a shipment. * * @param $shipment_number * The UPS shipment tracking number. * @param $tracking_numbers * Array of tracking numbers for individual packages in the shipment. * Optional for shipments of only one package, as they have the same tracking * number. * @return * TRUE if the shipment or packages were successfully voided. */ function uc_ups_void_shipment($shipment_number, $tracking_numbers = array()) { $success = FALSE; $request = uc_ups_void_shipment_request($shipment_number, $tracking_numbers); $resp = drupal_http_request(variable_get('uc_ups_connection_address', 'https://wwwcie.ups.com/ups.app/xml/') .'Void', array(), 'POST', $request); $response = new SimpleXMLElement($resp->data); if (isset($response->Response)) { if (isset($response->Response->ResponseStatusCode)) { $success = (string)$response->Response->ResponseStatusCode; } if (isset($response->Response->Error)) { foreach ($response->Response->Error as $error) { drupal_set_message((string)$error->ErrorSeverity .' '. (string)$error->ErrorCode .': '. (string)$error->ErrorDescription, 'error'); } } } if (isset($response->Status)) { if (isset($response->Status->StatusType)) { $success = (string)$response->Status->StatusType->Code; } } return (bool)$success; } /** * Modify the rate received from UPS before displaying to the customer. */ function uc_ups_markup($rate) { $markup = variable_get('uc_ups_markup', '0'); $type = variable_get('uc_ups_markup_type', 'percentage'); if (is_numeric(trim($markup))) { switch ($type) { case 'percentage': return $rate + $rate * floatval(trim($markup)) / 100; case 'multiplier': return $rate * floatval(trim($markup)); case 'currency': return $rate + floatval(trim($markup)); } } else { return $rate; } } /** * Convenience function to get UPS codes for their services. */ function _uc_ups_service_list() { return array( // Domestic services '03' => t('UPS Ground'), '01' => t('UPS Next Day Air'), '13' => t('UPS Next Day Air Saver'), '14' => t('UPS Next Day Early A.M.'), '02' => t('UPS 2nd Day Air'), '59' => t('UPS 2nd Day Air A.M.'), '12' => t('UPS 3 Day Select'), // International services '11' => t('UPS Standard'), '07' => t('UPS Worldwide Express'), '08' => t('UPS Worldwide Expedited'), '54' => t('UPS Worldwide Express Plus'), '65' => t('UPS Worldwide Saver'), // Poland to Poland shipments only //'82' => t('UPS Today Standard'), //'83' => t('UPS Today Dedicated Courrier'), //'84' => t('UPS Today Intercity'), //'85' => t('UPS Today Express'), //'86' => t('UPS Today Express Saver'), ); } /** * Convenience function to get UPS codes for their package types. */ function _uc_ups_pkg_types() { return array( '01' => t('UPS Letter'), '02' => t('Customer Supplied Package'), '03' => t('Tube'), '04' => t('PAK'), '21' => t('UPS Express Box'), '24' => t('UPS 25KG Box'), '25' => t('UPS 10KG Box'), '30' => t('Pallet'), '2a' => t('Small Express Box'), '2b' => t('Medium Express Box'), '2c' => t('Large Express Box'), ); } /** * Pseudo-constructor to set default values of a package. */ function _uc_ups_new_package() { $package = new stdClass(); $package->weight = 0; $package->price = 0; $package->length = 0; $package->width = 0; $package->height = 0; $package->length_units = 'in'; $package->weight_units = 'lb'; $package->qty = 1; $package->pkg_type = '02'; return $package; }