'admin/store/settings/quotes/methods/ups', 'access' => user_access('configure quotes'), 'title' => t('UPS'), 'callback' => 'drupal_get_form', 'callback arguments' => 'uc_ups_admin_settings', 'type' => MENU_LOCAL_TASK, ); } else { $items[] = array('path' => 'admin/store/orders/'. arg(3) .'/shipments/ups', 'access' => user_access('fulfill orders'), 'title' => t('UPS shipment'), 'callback' => 'drupal_get_form', 'callback arguments' => array('uc_ups_confirm_shipment', arg(3)), 'type' => MENU_CALLBACK, ); $items[] = array('path' => 'admin/store/orders/'. arg(3) .'/shipments/labels/ups', 'access' => user_access('fulfill orders'), 'callback' => 'theme', 'callback arguments' => array('uc_ups_label_image'), 'type' => MENU_CALLBACK, ); drupal_add_css(drupal_get_path('module', 'uc_ups') .'/uc_ups.css'); } return $items; } /** * Implementation of hook_form_alter(). * * Add package type to products. * * @see uc_product_form * @see uc_ups_product_alte_validate */ function uc_ups_form_alter($form_id, &$form) { $node = $form['#node']; if (is_object($node) && $form_id == $node->type .'_node_form' && isset($form['base']['dimensions']) && in_array($node->type, module_invoke_all('product_types'))) { $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'] : '02', ); $form['shipping']['ups'] = $ups; if ($enabled['ups']) { $form['#validate']['uc_ups_product_alter_validate'] = array(); } } } /** * Validation handler for UPS product fields. */ function uc_ups_product_alter_validate($form_id, $form_values) { $enabled = variable_get('uc_quote_enabled', array()); if ($form_values['shippable'] && ($form_values['shipping_type'] == 'small_package' || (empty($form_values['shipping_type']) && variable_get('uc_store_shipping_type', 'small_package') == 'small_package'))) { if ($form_values['ups']['pkg_type'] == '02' && (empty($form_values['length']) || empty($form_values['width']) || empty($form_values['height']))) { form_set_error('base][dimensions', t('Dimensions are required for custom packaging.')); } } } /** * Implementation of hook_nodeapi(). */ function uc_ups_nodeapi(&$node, $op) { if (in_array($node->type, module_invoke_all('product_types'))) { 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; } } } /****************************************************************************** * Workflow-ng Hooks * ******************************************************************************/ /** * Implementation of hook_configuration(). * * Connect the UPS quote action and event. */ function uc_ups_configuration() { $enabled = variable_get('uc_quote_enabled', array()); $configurations = array( 'uc_ups_get_quote' => array( '#label' => t('Shipping quote from UPS'), '#event' => 'get_quote_from_ups', '#module' => 'uc_ups', '#active' => $enabled['ups'], ), ); $action = workflow_ng_use_action('uc_quote_action_get_quote', array( '#label' => t('Fetch a shipping quote'), )); $configurations['uc_ups_get_quote'] = workflow_ng_configure($configurations['uc_ups_get_quote'], $action); return $configurations; } /****************************************************************************** * Übercart Hooks * ******************************************************************************/ /** * Implementation of Übercart's 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 Übercart's 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 Übercart's 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; } /****************************************************************************** * Menu Callbacks * ******************************************************************************/ /** * UPS Online Tool settings. * * Record UPS account information neccessary to use the service. Allow testing * or production mode. Configure which UPS services are quoted to customers. * * @ingroup forms * @see uc_admin_settings_validate */ function uc_ups_admin_settings() { $form = array(); $form['uc_ups_access_license'] = array('#type' => 'textfield', '#title' => t('UPS OnLine Tools XML Access Key'), '#default_value' => variable_get('uc_ups_access_license', ''), '#required' => true, ); $form['uc_ups_shipper_number'] = array('#type' => 'textfield', '#title' => t('UPS Shipper #'), '#description' => t('The 6-character string identifying your UPS account as a shipper.'), '#default_value' => variable_get('uc_ups_shipper_number', ''), '#required' => true, ); $form['uc_ups_user_id'] = array('#type' => 'textfield', '#title' => t('UPS.com user ID'), '#default_value' => variable_get('uc_ups_user_id', ''), '#required' => true, ); $form['uc_ups_password'] = array('#type' => 'password', '#title' => t('Password'), '#default_value' => variable_get('uc_ups_password', ''), ); $form['uc_ups_connection_address'] = array('#type' => 'select', '#title' => t('Mode'), '#description' => t('Quotes and shipments requested in Testing mode will not be picked up or charged to your account.'), '#options' => array('https://wwwcie.ups.com/ups.app/xml/' => t('Testing'), 'https://www.ups.com/ups.app/xml/' => t('Production'), ), '#default_value' => variable_get('uc_ups_connection_address', 'https://wwwcie.ups.com/ups.app/xml/'), ); $form['uc_ups_services'] = array('#type' => 'checkboxes', '#title' => t('UPS services'), '#default_value' => variable_get('uc_ups_services', _uc_ups_service_list()), '#options' => _uc_ups_service_list(), '#description' => t('Select the UPS services that are available to customers.'), ); $form['uc_ups_pickup_type'] = array('#type' => 'select', '#title' => t('Pickup type'), '#options' => array( '01' => 'Daily Pickup', '03' => 'Customer Counter', '06' => 'One Time Pickup', '07' => 'On Call Air', '11' => 'Suggested Retail Rates', '19' => 'Letter Center', '20' => 'Air Service Center', ), '#default_value' => variable_get('uc_ups_pickup_type', '01'), ); $form['uc_ups_classification'] = array('#type' => 'select', '#title' => t('UPS Customer classification'), '#options' => array( '01' => t('Wholesale'), '03' => t('Occasional'), '04' => t('Retail'), ), '#default_value' => variable_get('uc_ups_classification', '04'), '#description' => t('The kind of customer you are to UPS. For daily pickups the default is wholesale; for customer counter pickups the default is retail; for other pickups the default is occasional.'), ); $form['uc_ups_negotiated_rates'] = array('#type' => 'radios', '#title' => t('Negotiated rates'), '#default_value' => variable_get('uc_ups_negotiated_rates', 0), '#options' => array(1 => t('Yes'), 0 => t('No')), '#description' => t('Is your UPS account receiving negotiated rates on shipments?'), ); $form['uc_ups_residential_quotes'] = array('#type' => 'radios', '#title' => t('Assume UPS shipping quotes will be delivered to'), '#default_value' => variable_get('uc_ups_residential_quotes', 0), '#options' => array( 0 => t('Business locations'), 1 => t('Residential locations (extra fees)'), ), ); $form['uc_ups_markup_type'] = array('#type' => 'select', '#title' => t('Markup type'), '#default_value' => variable_get('uc_ups_markup_type', 'percentage'), '#options' => array( 'percentage' => t('Percentage (%)'), 'multiplier' => t('Multiplier (×)'), 'currency' => t('Addition (!currency)', array('!currency' => variable_get('uc_currency_sign', '$'))), ), ); $form['uc_ups_markup'] = array('#type' => 'textfield', '#title' => t('Shipping rate markup'), '#default_value' => variable_get('uc_ups_markup', '0'), '#description' => t('Markup shipping rate quote by currency amount, percentage, or multiplier.'), ); $form['uc_ups_all_in_one'] = array('#type' => 'radios', '#title' => t('Product packages'), '#default_value' => variable_get('uc_ups_all_in_one', 1), '#options' => array( 0 => t('Each in its own package'), 1 => t('All in one'), ), '#description' => t('Indicate whether each product is quoted as shipping separately or all in one package.'), ); $form['uc_ups_unit_system'] = array('#type' => 'select', '#title' => t('System of measurement'), '#default_value' => variable_get('uc_ups_unit_system', variable_get('uc_length_unit', 'in')), '#options' => array( 'in' => t('British'), 'cm' => t('Metric'), ), '#description' => t('Choose the standard system of measurement for your country.'), ); $form['uc_ups_insurance'] = array( '#type' => 'checkbox', '#title' => t('Package insurance'), '#default_value' => variable_get('uc_ups_insurance', TRUE), '#description' => t('When enabled, products are insured for their full value.'), ); return system_settings_form($form); } /** * Validation handler for uc_ups_admin_settings. * * Require password only if it hasn't been set. */ function uc_ups_admin_settings_validate($form_id, $form_values, $form) { $old_password = variable_get('uc_ups_password', ''); if (!$form_values['uc_ups_password']) { if ($old_password) { form_set_value($form['uc_ups_password'], $old_password); } else { form_set_error('uc_ups_password', t('Password field is required.')); } } } /****************************************************************************** * 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_weight_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 = constant(strtoupper($package->length_units) .'_TO_'. strtoupper(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 = $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->price, 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) { 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'] .= /* '
'. print_r($ship_packages, true) .'
' . */ htmlentities($request) .'

'. 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'] = ' '. $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; } /** * 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_submit */ function uc_ups_fulfill_order($order_id, $package_ids) { $form = array(); $pkg_types = _uc_ups_pkg_types(); if ($order = uc_order_load($order_id)) { $form['order_id'] = array('#type' => 'value', '#value' => $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($addresses, $order)); foreach (array('delivery_email', 'delivery_last_name', 'delivery_company', 'delivery_street1', 'delivery_city', 'delivery_zone', 'delivery_country', 'delivery_postal_code') as $field) { $form['destination'][$field]['#required'] = true; } $ups_services = _uc_ups_service_list(); $services = array_filter(variable_get('uc_ups_services', array())); foreach ($services as $ups_id => $service) { $services[$ups_id] = $ups_services[$ups_id]; } if (count($services)) { $form['service'] = array('#type' => 'select', '#title' => t('UPS service'), '#options' => $services, ); } $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')); } else { drupal_set_message(t("What? That's not an order id. You can't create a shipment without an order.")); drupal_goto('admin/store/orders'); } return $form; } /** * Validation handler for uc_ups_fulfill_order(). * * Pass final information into shipment object. * * @see uc_ups_confirm_shipment */ function uc_ups_fulfill_order_validate($form_id, $form_values) { include_once(drupal_get_path('module', 'uc_store') .'/includes/simplexml.php'); $origin = new stdClass(); $destination = new stdClass(); $packages = array(); foreach ($form_values as $key => $value) { if (substr($key, 0, 7) == 'pickup_') { $field = substr($key, 7); $origin->$field = $value; } else if (substr($key, 0, 9) == 'delivery_') { $field = substr($key, 9); $destination->$field = $value; } } $_SESSION['ups'] = array(); $_SESSION['ups']['origin'] = $origin; $_SESSION['ups']['destination'] = $destination; foreach ($form_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_values['service']; $_SESSION['ups']['ship_date'] = $form_values['ship_date']; $_SESSION['ups']['expected_delivery'] = $form_values['expected_delivery']; $_SESSION['ups']['order_id'] = $form_values['order_id']; $request = uc_ups_shipment_request($_SESSION['ups']['packages'], $origin, $destination, $form_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 JSimpleXML(); $response->loadString($response_obj->data); //drupal_set_message('
'. htmlentities($response->document->asXML()) .'
'); if (is_array($response->document->response[0]->error)) { $error = $response->document->response[0]->error[0]; $error_msg = $error->errorseverity[0]->data() .' Error '. $error->errorcode[0]->data() .': '. $error->errordescription[0]->data(); drupal_set_message($error_msg, 'error'); //drupal_set_message('
'. print_r($_SESSION['ups']['packages'], true) .'
' . htmlentities($request) .'

'. htmlentities($response->data)); if ($error->errorseverity[0]->data() == 'Hard') { return null; } } $charge = new stdClass(); // if NegotiatedRates exist, quote based on those, otherwise, use TotalCharges if (is_array($response->document->shipmentcharges)) { $charge = $response->document->shipmentcharges[0]->totalcharges[0]; $_SESSION['ups']['rate']['type'] = t('Total Charges'); if (is_array($response->document->shipmentcharges[0]->negotiatedrates)) { $charge = $response->document->shipmentcharges[0]->negotiatedrates[0]->netsummarycharges[0]->grandtotal[0]; $_SESSION['ups']['rate']['type'] = t('Negotiated Rates'); } } $_SESSION['ups']['rate']['currency'] = $charge->currencycode[0]->data(); $_SESSION['ups']['rate']['amount'] = $charge->monetaryvalue[0]->data(); $_SESSION['ups']['digest'] = $response->document->shipmentdigest[0]->data(); } /** * Submit handler for uc_ups_fulfill_order(). * * Pass final information into shipment object. * * @see uc_ups_confirm_shipment */ function uc_ups_fulfill_order_submit($form_id, $form_values) { return 'admin/store/orders/'. $form_values['order_id'] .'/shipments/ups'; } /** * Last chance for user to review shipment. * * @ingroup forms * @see theme_uc_ups_confirm_shipment * @see uc_ups_confirm_shipment_submit */ function uc_ups_confirm_shipment($order_id) { $form = array(); $form['digest'] = array('#type' => 'hidden', '#value' => $_SESSION['ups']['digest']); $form['submit'] = array('#type' => 'submit', '#value' => t('Request Pickup')); return $form; } /** * Display final shipment information for review. */ function theme_uc_ups_confirm_shipment($form) { $output = ''; $output .= '
'. t('Ship from:') .'
'; $output .= uc_address_format( check_plain($_SESSION['ups']['origin']->first_name), check_plain($_SESSION['ups']['origin']->last_name), check_plain($_SESSION['ups']['origin']->company), check_plain($_SESSION['ups']['origin']->street1), check_plain($_SESSION['ups']['origin']->street2), check_plain($_SESSION['ups']['origin']->city), check_plain($_SESSION['ups']['origin']->zone), check_plain($_SESSION['ups']['origin']->postal_code), check_plain($_SESSION['ups']['origin']->country) ); $output .= '
'. check_plain($_SESSION['ups']['origin']->email); $output .= '
'; $output .= '
'. t('Ship to:') .'
'; $output .= uc_address_format( check_plain($_SESSION['ups']['destination']->first_name), check_plain($_SESSION['ups']['destination']->last_name), check_plain($_SESSION['ups']['destination']->company), check_plain($_SESSION['ups']['destination']->street1), check_plain($_SESSION['ups']['destination']->street2), check_plain($_SESSION['ups']['destination']->city), check_plain($_SESSION['ups']['destination']->zone), check_plain($_SESSION['ups']['destination']->postal_code), check_plain($_SESSION['ups']['destination']->country) ); $output .= '
'. check_plain($_SESSION['ups']['destination']->email); $output .= '
'; $output .= '
'; $method = uc_ups_shipping_method(); $output .= ''. $method['ups']['quote']['accessorials'][$_SESSION['ups']['service']] .'
'; $output .= ''. check_plain($_SESSION['ups']['rate']['type']) .': '. uc_currency_format($_SESSION['ups']['rate']['amount']) .' ('. check_plain($_SESSION['ups']['rate']['currency']) .')
'; $ship_date = $_SESSION['ups']['ship_date']; $output .= 'Ship date: '. format_date(gmmktime(12, 0, 0, $ship_date['month'], $ship_date['day'], $ship_date['year']), 'custom', variable_get('uc_date_format_default', 'm/d/Y')); $exp_delivery = $_SESSION['ups']['expected_delivery']; $output .= '
Expected delivery: '. format_date(gmmktime(12, 0, 0, $exp_delivery['month'], $exp_delivery['day'], $exp_delivery['year']), 'custom', variable_get('uc_date_format_default', 'm/d/Y')); $output .= "
\n
"; $output .= drupal_render($form); return $output; } /** * Submit handler for uc_ups_confirm_shipment(). * * Generate label and schedule pickup of the shipment. */ function uc_ups_confirm_shipment_submit($form_id, $form_values) { include_once(drupal_get_path('module', 'uc_store') .'/includes/simplexml.php'); // Request pickup using parameters in form. $order_id = $_SESSION['ups']['order_id']; $packages = array_keys($_SESSION['ups']['packages']); $request = uc_ups_request_pickup($form_values['digest'], $order_id, $packages); $result = drupal_http_request(variable_get('uc_ups_connection_address', 'https://wwwcie.ups.com/ups.app/xml/') .'ShipAccept', array(), 'POST', $request); $response = new JSimpleXML(); $response->loadString($result->data); $code = $response->document->response[0]->responsestatuscode[0]->data(); if ($code == 0) { // failed request $error = $response->document->response[0]->error[0]; $error_severity = $error->errorseverity[0]->data(); $error_code = $error->errorcode[0]->data(); $error_description = $error->errordescription[0]->data(); drupal_set_message(t('(@severity error @code) @description', array('@severity' => $error_severity, '@code' => $error_code, '@description' => $error_description)), 'error'); if ($error_severity == 'HardError') { return 'admin/store/orders/'. $order_id .'/shipments/ups/'. implode('/', $packages); } } $shipment = new stdClass(); $shipment->order_id = $order_id; $shipment->origin = drupal_clone($_SESSION['ups']['origin']); $shipment->destination = drupal_clone($_SESSION['ups']['destination']); $shipment->packages = $_SESSION['ups']['packages']; $shipment->shipping_method = 'ups'; $shipment->accessorials = $_SESSION['ups']['service']; $shipment->carrier = t('UPS'); // if NegotiatedRates exist, quote based on those, otherwise, use TotalCharges if (is_array($response->document->shipmentresults[0]->shipmentcharges)) { $charge = $response->document->shipmentresults[0]->shipmentcharges[0]->totalcharges[0]; if (is_array($response->document->shipmentresults[0]->negotiatedrates)) { $charge = $response->document->shipmentresults[0]->negotiatedrates[0]->netsummarycharges[0]->grandtotal[0]; } } $cost = $charge->monetaryvalue[0]->data(); $shipment->cost = $cost; $shipment->tracking_number = $response->document->shipmentresults[0]->shipmentidentificationnumber[0]->data(); $ship_date = $_SESSION['ups']['ship_date']; $shipment->ship_date = gmmktime(12, 0, 0, $ship_date['month'], $ship_date['day'], $ship_date['year']); $exp_delivery = $_SESSION['ups']['expected_delivery']; $shipment->expected_delivery = gmmktime(12, 0, 0, $exp_delivery['month'], $exp_delivery['day'], $exp_delivery['year']); foreach ($response->document->shipmentresults[0]->packageresults as $package_results) { $package =& current($shipment->packages); $package->tracking_number = $package_results->trackingnumber[0]->data(); $label_image = $package_results->labelimage[0]->graphicimage[0]->data(); if (file_check_directory(file_create_path('ups_labels'), FILE_CREATE_DIRECTORY)) { $label_path = file_create_path('ups_labels') .'/label'. $package->tracking_number .'.gif'; if ($label_file = fopen($label_path, 'wb')) { fwrite($label_file, base64_decode($label_image)); fclose($label_file); $package->label_image = $label_path; } else { drupal_set_message(t('Could not open a file to save the label image.'), 'error'); } } else { drupal_set_message(t('Could not find or create the directory "ups_labels" in the file system path.'), 'error'); } unset($package); next($shipment->packages); } uc_shipping_shipment_save($shipment); unset($_SESSION['ups']); return 'admin/store/orders/'. $order_id .'/shipments'; } /** * Construct an XML label and pickup request. * * @param $digest * Base-64 encoded shipment request. * @param $order_id * The order id of the shipment. * @param $packages * An array of package ids to be shipped. * @return * ShipmentAcceptRequest XML document to send to UPS. */ function uc_ups_request_pickup($digest, $order_id = 0, $packages = array()) { $packages = (array)$packages; $schema = uc_ups_access_request(); $schema .= " ShipAccept"; if ($order_id || count($packages)) { $schema .= "\n "; if ($order_id) { $schema .= "". $order_id ."\n"; } foreach ($packages as $pkg_id) { $schema .= "". $pkg_id ."\n"; } $schema .= "\n\n"; } $schema .= " ". $digest ." "; //drupal_set_message('
'. htmlentities($schema) .'
'); return $schema; } /** * Display the shipping label for printing. * * Each argument is a component of the file path to the image. * * @ingroup themeable */ function theme_uc_ups_label_image() { $args = func_get_args(); $image_path = implode('/', $args); print ' View/Print Label
View/Print Label  
  1. Print the label:   Select Print from the File menu in this browser window to print the label below.

  2. Fold the printed label at the dotted line.   Place the label in a UPS Shipping Pouch. If you do not have a pouch, affix the folded label using clear plastic shipping tape over the entire label.

  3. GETTING YOUR SHIPMENT TO UPS
    Customers without a Daily Pickup
    • Ground, 3 Day Select, and Standard to Canada shipments must be dropped off at an authorized UPS location, or handed to a UPS driver. Pickup service is not available for these services. To find the nearest drop-off location, select the Drop-off icon from the UPS tool bar.
    • Air shipments (including Worldwide Express and Expedited) can be picked up or dropped off. To schedule a pickup, or to find a drop-off location, select the Pickup or Drop-off icon from the UPS tool bar.

    Customers with a Daily Pickup
    • Your driver will pickup your shipment(s) as usual.
    FOLD HERE

 
'; exit(); } 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; } function uc_ups_void_shipment($shipment_number, $tracking_numbers = array()) { include_once(drupal_get_path('module', 'uc_store') .'/includes/simplexml.php'); $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 JSimpleXML(); $response->loadString($resp->data); if (is_array($response->document->response)) { if (is_array($response->document->response[0]->responsestatuscode)) { $success = $response->document->response[0]->responsestatuscode[0]->data(); } if (is_array($response->document->response[0]->error)) { foreach ($response->document->response[0]->error as $error) { drupal_set_message($error->errorseverity[0]->data() .' '. $error->errorcode[0]->data() .': '. $error->errordescription[0]->data(), 'error'); } } } if (is_array($response->document->status)) { if (is_array($response->document->status[0]->statustype)) { $success = $response->document->status[0]->statustype[0]->code[0]->data(); } } 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( '03' => t('UPS Ground'), '11' => t('UPS Standard'), '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'), ); } /** * 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'), ); } 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; }