'admin/store/settings/quotes', 'access' => user_access('configure quotes'), 'title' => t('Shipping quote settings'), 'description' => t('Configure the shipping quote settings.'), 'callback' => 'uc_quote_overview', 'type' => MENU_NORMAL_ITEM, ); $items[] = array('path' => 'admin/store/settings/quotes/overview', 'access' => user_access('configure quotes'), 'title' => t('Overview'), 'description' => t('View general shipping quote settings.'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items[] = array('path' => 'admin/store/settings/quotes/edit', 'access' => user_access('configure quotes'), 'title' => t('Edit'), 'callback' => 'drupal_get_form', 'callback arguments' => 'uc_quote_admin_settings', 'type' => MENU_LOCAL_TASK, 'weight' => -8, ); $items[] = array('path' => 'admin/store/settings/quotes/methods', 'access' => user_access('configure quotes'), 'title' => t('Quote methods'), 'callback' => 'drupal_get_form', 'callback arguments' => array('uc_quote_method_settings'), 'type' => MENU_LOCAL_TASK, 'weight' => -5, ); $items[] = array('path' => 'admin/store/settings/quotes/methods/general', 'title' => t('General settings'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items[] = array('path' => 'cart/checkout/shipping/quote', 'access' => user_access('access content'), 'callback' => 'uc_quote_request_quotes', 'type' => MENU_CALLBACK, ); } else { drupal_add_css(drupal_get_path('module', 'uc_quote') .'/uc_quote.css', 'module'); } return $items; } /** * Implementation of hook_taxonomy(). * * Save and delete manufacturer shipping locations. */ function uc_quote_taxonomy($op, $type, $object = null) { switch ($type) { case 'term': switch ($op) { case 'insert': case 'update': db_query("DELETE FROM {uc_quote_manufacturer_locations} WHERE tid = %d", $object['tid']); if ($object['street1']) { db_query("INSERT INTO {uc_quote_manufacturer_locations} (tid, first_name, last_name, company, street1, street2, city, zone, postal_code, country, phone) VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', %d, '%s')", $object['tid'], $object['first_name'], $object['last_name'], $object['company'], $object['street1'], $object['street2'], $object['city'], $object['zone'], $object['postal_code'], $object['country'], $object['phone'] ); } uc_quote_set_shipping_type('manufacturer', $object['tid'], $object['shipping_type']); break; case 'delete': db_query("DELETE FROM {uc_quote_shipping_types} WHERE id_type = 'manufacturer' AND id = %d", $object['tid']); db_query("DELETE FROM {uc_quote_manufacturer_locations} WHERE tid = %d", $object['tid']); break; } break; } } /** * Implementation of hook_nodeapi(). * * Load, save, and delete the shipping type and default shipping address of products. */ function uc_quote_nodeapi(&$node, $op, $arg3 = NULL, $arg4 = NULL) { if (in_array($node->type, module_invoke_all('product_types'))) { switch ($op) { case 'insert': case 'update': if (isset($node->shipping_type)) { uc_quote_set_shipping_type('product', $node->nid, $node->shipping_type); } db_query("DELETE FROM {uc_quote_product_locations} WHERE nid = %d", $node->nid); if ($node->street1) { db_query("INSERT INTO {uc_quote_product_locations} (nid, first_name, last_name, company, street1, street2, city, zone, postal_code, country, phone) VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', %d, '%s')", $node->nid, $node->first_name, $node->last_name, $node->company, $node->street1, $node->street2, $node->city, $node->zone, $node->postal_code, $node->country, $node->phone ); } break; case 'load': // Can't just use uc_product_get_shipping_type() because $node->manufacturer doesn't necessarily exist yet. if (module_exists('uc_manufacturer')) { $manufacturer = uc_product_get_manufacturer($node->nid); } $shipping_type = db_result(db_query("SELECT shipping_type FROM {uc_quote_shipping_types} WHERE id_type = 'product' AND id = %d", $node->nid)); if (!$shipping_type) { if (isset($manufacturer)) { $shipping_type = db_result(db_query("SELECT shipping_type FROM {uc_quote_shipping_types} WHERE id_type = 'manufacturer' AND id = %d", $manufacturer->tid)); } if (!$shipping_type) { $shipping_type = variable_get('uc_store_shipping_type', 'small_package'); } } $address = db_fetch_object(db_query("SELECT first_name, last_name, company, street1, street2, city, zone, postal_code, country, phone FROM {uc_quote_product_locations} WHERE nid = %d", $node->nid)); if ($address === false) { if (module_exists('uc_manufacturer')) { $address = db_fetch_object(db_query("SELECT first_name, last_name, company, street1, street2, city, zone, postal_code, country, phone FROM {uc_quote_manufacturer_locations} WHERE tid = %d", $manufacturer->tid)); } if ($address === false) { $address = variable_get('uc_quote_store_default_address', new stdClass()); } } return array('shipping_type' => $shipping_type, 'shipping_address' => $address); break; case 'delete': db_query("DELETE FROM {uc_quote_shipping_types} WHERE id_type = 'product' AND id = %d", $node->nid); db_query("DELETE FROM {uc_quote_product_locations} WHERE nid = %d", $node->nid); break; } } } /** * Implementation of hook_form_alter(). * * Add a default shipping address for products and manufacturers. If it is left * blank, products default to their manufacturers', which default to the store's. */ function uc_quote_form_alter($form_id, &$form) { $node = $form['#node']; $product_types = uc_product_node_info(); if (($form_id == 'taxonomy_form_term' && $form['vid']['#value'] == variable_get('uc_manufacturer_vid', 0)) || $form_id == 'uc_manufacturer_form' || ($form_id == $node->type .'_node_form' && isset($form['base']['dimensions']) && in_array($node->type, module_invoke_all('product_types')))) { if (strpos($form_id, 'node_form')) { $type = 'product'; $id = $form['nid']['#value']; $weight = 1; $address = $node->shipping_address; } else { $type = 'manufacturer'; $id = $form['tid']['#value']; $weight = 0; if (module_exists('uc_manufacturer')) { $address = db_fetch_object(db_query("SELECT first_name, last_name, company, street1, street2, city, zone, postal_code, country FROM {uc_quote_manufacturer_locations} WHERE tid = %d", $id)); } } if (empty($address)) { $address = variable_get('uc_quote_store_default_address', new stdClass()); } if (!isset($form['shipping'])) { $form['shipping'] = array(); } $form['shipping'] += array('#type' => 'fieldset', '#title' => t('Shipping settings'), '#collapsible' => true, '#weight' => $weight, '#attributes' => array('class' => 'product-shipping'), ); $form['shipping']['default_address'] = array('#type' => 'fieldset', '#title' => t('Default product pickup address'), '#description' => t("When delivering products to customers, the original location of the product must be known in order to accurately quote the shipping cost and set up a delivery. This form provides the default location for products, either individually or an entire manufacturer's line. If a product's individual pickup address is blank, Übercart looks for the manufacturer's. If that is also blank, it uses the store's default pickup address, which can be set here.", array('!here' => url('admin/store/settings/quotes'))), '#collapsible' => true, '#collapsed' => true, '#weight' => -6, ); $form['shipping']['default_address']['first_name'] = uc_textfield(uc_get_field_name('first_name'), $address->first_name, FALSE); $form['shipping']['default_address']['last_name'] = uc_textfield(uc_get_field_name('last_name'), $address->last_name, FALSE); $form['shipping']['default_address']['company'] = uc_textfield(uc_get_field_name('company'), $address->company, FALSE); $form['shipping']['default_address']['street1'] = uc_textfield(uc_get_field_name('street1'), $address->street1, FALSE, NULL, 64); $form['shipping']['default_address']['street2'] = uc_textfield(uc_get_field_name('street2'), $address->street2, FALSE, NULL, 64); $form['shipping']['default_address']['city'] = uc_textfield(uc_get_field_name('city'), $address->city, FALSE); if (isset($_POST['country'])) { $country = $_POST['country']; } else { $country = $address->country; } $form['shipping']['default_address']['zone'] = uc_zone_select(uc_get_field_name('zone'), $address->zone, null, $country); $form['shipping']['default_address']['postal_code'] = uc_textfield(uc_get_field_name('postal_code'), $address->postal_code, FALSE, NULL, 10, 10); $form['shipping']['default_address']['country'] = uc_country_select(uc_get_field_name('country'), $address->country); $types = uc_quote_shipping_type_options(); if (is_array($types)) { $types = array_merge(array('' => t('')), $types); } else { $types = array('' => t('')); } $form['shipping']['shipping_type'] = array('#type' => 'select', '#title' => t('Default product shipping type'), '#default_value' => uc_quote_get_shipping_type($type, $id), '#options' => $types, '#weight' => -7, ); } else if ($form_id == 'uc_cart_checkout_form' && isset($form['panes']['quotes'])) { $form['#validate']['uc_quote_save_choice'] = array(); $form['#pre_render'][] = 'uc_quote_cache_quotes'; } } /****************************************************************************** * Workflow-ng Hooks * ******************************************************************************/ /** * Implementation of hook_event_info(). * * Register an event for each shipping method. Enabled methods have active * configurations. */ function uc_quote_event_info() { $methods = module_invoke_all('shipping_method'); $events = array(); foreach ($methods as $id => $method) { $events['get_quote_from_'. $id] = array( '#label' => t('Getting shipping quote via !method', array('!method' => $method['title'])), '#module' => t('Quote'), '#arguments' => array( 'order' => array('#entity' => 'order', '#label' => t('Order')), 'method' => array('#entity' => 'quote_method', '#label' => t('Quote method')), 'account' => array('#entity' => 'user', '#label' => t('User account')), ), ); } return $events; } /** * Implementation of hook_condition_info(). */ function uc_quote_condition_info() { return array( 'uc_quote_condition_product_shipping_type' => array( '#label' => t("Order has a product of a particular shipping type"), '#arguments' => array( 'order' => array('#entity' => 'order', '#label' => t('Order')), ), '#module' => t('Order: Product'), ), 'uc_quote_condition_order_shipping_method' => array( '#label' => t("Order has a shipping quote from a particular method"), '#arguments' => array( 'order' => array('#entity' => 'order', '#label' => t('Order')), ), '#module' => t('Order: Shipping Quote'), ), ); } /** * Returns true if the order has a product of the chosen shipping type. * * @see uc_quote_condition_product_shipping_type_form */ function uc_quote_condition_product_shipping_type($order, $settings) { $result = false; foreach ($order->products as $product) { if ($product->nid && uc_product_get_shipping_type($product) == $settings['type']) { $result = true; break; } } return $result; } /** * Settings form for uc_quote_condition_product_shipping_type(). * * @ingroup forms * @see uc_quote_condition_product_shipping_type * @see uc_quooe_condition_product_shipping_type_submit */ function uc_quote_condition_product_shipping_type_form($settings = array()) { $form = array(); $options = array(); $types = module_invoke_all('shipping_type'); foreach ($types as $id => $type) { $options[$id] = $type['title']; } $form['type'] = array('#type' => 'select', '#title' => t('Shipping type'), '#options' => $options, '#default_value' => $settings['type'], ); return $form; } /** * Submit handler for uc_quote_condition_product_shipping_type_form(). */ function uc_quote_condition_product_shipping_type_submit($form_id, $form_values) { return array( 'type' => $form_values['type'], ); } function uc_quote_condition_order_shipping_method($order, $settings) { // Check the easy way first. if (is_array($order->quote)) { return $order->quote['method'] == $settings['method']; } // Otherwise, look harder. if (is_array($order->line_items)) { foreach ($order->line_items as $line_item) { if ($line_item['type'] == 'shipping' && in_array($line_item['title'], $settings['accessorials'])) { return TRUE; } } } return FALSE; } function uc_quote_condition_order_shipping_method_form($settings = array()) { $form = array(); $methods = module_invoke_all('shipping_method'); $enabled = variable_get('uc_quote_enabled', array()); $options = array(); foreach ($methods as $id => $method) { $options[$id] = $method['title']; if (!$enabled[$id]) { $options[$id] .= ' '. t('(disabled)'); } } $form['method'] = array( '#type' => 'select', '#title' => t('Shipping quote method'), '#default_value' => $settings['method'], '#options' => $options, ); return $form; } function uc_quote_condition_order_shipping_method_submit($form_id, $form_values) { $methods = module_invoke_all('shipping_method'); return array( 'method' => $form_values['method'], 'accessorials' => $methods[$form_values['method']]['quote']['accessorials'], ); } /** * Implementation of hook_action_info(). */ function uc_quote_action_info() { return array( 'uc_quote_action_get_quote' => array( '#label' => t('Fetch a shipping quote'), '#arguments' => array( 'order' => array('#entity' => 'order', '#label' => t('Order')), 'method' => array('#entity' => 'quote_method', '#label' => t('Quote method')), ), '#module' => t('Quote'), ), ); } /** * Retrive shipping quote and print JSON data. * * @param $order * The order the quote is for. * @param $method * The shipping method to generate the quote. */ function uc_quote_action_get_quote($order, $method) { $details = array(); foreach ($order as $key => $value) { if (substr($key, 0, 9) == 'delivery_') { $field = substr($key, 9); $details[$field] = $value; } } ob_start(); if (function_exists($method['quote']['callback'])) { // This feels wrong, but it's the only way I can ensure that shipping // methods won't mess up the products in their methods. $products = array(); foreach ($order->products as $key => $item) { if (uc_cart_product_is_shippable($item)) { $products[$key] = drupal_clone($item); } } $quote_data = call_user_func($method['quote']['callback'], $products, $details, $method); } $messages = ob_get_contents(); ob_end_clean(); //drupal_set_message('
'. print_r($quote_data, true) .'
'); if ($messages && variable_get('uc_quote_log_errors', false)) { watchdog('quote', $messages, WATCHDOG_WARNING); watchdog('quote', '
'. print_r($quote_data, true) .'
', WATCHDOG_WARNING); } print serialize($quote_data); } /****************************************************************************** * Ubercart Hooks * ******************************************************************************/ /** * Implementation of Übercart's hook_cart_pane. */ function uc_quote_cart_pane($items) { if (!variable_get('uc_cap_quotes_enabled', FALSE) || (variable_get('uc_cart_delivery_not_shippable', TRUE) && !uc_cart_is_shippable())) { return array(); } $panes[] = array('id' => 'quotes', 'title' => t('Shipping quotes'), 'enabled' => FALSE, 'weight' => 5, 'body' => drupal_get_form('uc_cart_pane_quotes', $items), ); return $panes; } /** * Defines the shipping quote checkout pane. */ function uc_quote_checkout_pane() { $panes[] = array('id' => 'quotes', 'callback' => 'uc_checkout_pane_quotes', 'title' => t('Calculate shipping cost'), 'desc' => t('Extra information necessary to ship.'), 'weight' => 5, 'shippable' => TRUE, ); return $panes; } /** * Defines the shipping quote order pane. */ function uc_quote_order_pane() { $panes = array(); $panes[] = array( 'id' => 'quotes', 'callback' => 'uc_order_pane_quotes', 'title' => t('Shipping quote'), 'desc' => t('Get a shipping quote for the order from a quoting module.'), 'class' => 'abs-left', 'weight' => 7, 'show' => array('edit'), ); return $panes; } function uc_quote_add_to_cart() { unset($_SESSION['quote']); } function uc_quote_update_cart_item() { unset($_SESSION['quote']); } /** * Implementation of hook_order(). */ function uc_quote_order($op, &$arg1, $arg2) { switch ($op) { case 'submit': unset($_SESSION['quote']); break; case 'save': db_query("DELETE FROM {uc_order_quotes} WHERE oid = %d", $arg1->order_id); db_query("INSERT INTO {uc_order_quotes} (oid, method, accessorials, rate, quote_form) VALUES (%d, '%s', '%s', %f, '%s')", $arg1->order_id, $arg1->quote['method'], $arg1->quote['accessorials'], $arg1->quote['rate'], $arg1->quote['quote_form']); break; case 'load': $quote = db_fetch_array(db_query("SELECT method, accessorials, rate, quote_form FROM {uc_order_quotes} WHERE oid = %d", $arg1->order_id)); $arg1->quote = $quote; $arg1->quote['accessorials'] = strval($quote['accessorials']); break; case 'delete': db_query("DELETE FROM {uc_order_quotes} WHERE oid = %d", $arg1->order_id); break; } } /** * Defines the shipping quote line item. */ function uc_quote_line_item() { $items[] = array( 'id' => 'shipping', 'title' => t('Shipping'), 'weight' => 1, 'default' => false, 'stored' => true, 'calculated' => true, 'display_only' => false, 'add_list' => true, ); return $items; } /** * Implementation of Übercart's hook_shipping_type(). */ function uc_quote_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 package'), 'weight' => $weight['small_package'], ); return $types; } /****************************************************************************** * Menu Callbacks * ******************************************************************************/ /** * Display a summary of the shipping quote settings. */ function uc_quote_overview() { $sections = array(); $address = variable_get('uc_quote_store_default_address', new stdClass()); $sections[] = array( 'edit' => 'admin/store/settings/quotes/edit', 'title' => t('Quote settings'), 'items' => array( variable_get('uc_quote_log_errors', false) ? t('Quote errors are submitted to watchdog.') : t('Quote errors are not submitted to watchdog.'), variable_get('uc_quote_display_debug', false) ? t('Debugging information is displayed to administrators when quotes are generated.') : t('Debugging information is not displayed to administrators when quotes are generated.'), t('The default store shipping address is:
!address', array('!address' => uc_address_format( $address->first_name, $address->last_name, $address->company, $address->street1, $address->street2, $address->city, $address->zone, $address->postal_code, $address->country))) ), ); $items = array(); $methods = array_filter(module_invoke_all('shipping_method'), '_uc_quote_method_enabled'); uasort($methods, '_uc_quote_type_sort'); foreach ($methods as $method) { $items[] = l(t('@method is enabled.', array('@method' => $method['title'])), 'admin/store/settings/quotes/methods/'. $method['id']); } $sections[] = array( 'edit' => 'admin/store/settings/quotes/methods', 'title' => t('Quote methods'), 'items' => $items, ); $types = uc_quote_shipping_type_options(); $default = variable_get('uc_store_shipping_type', 'small_package'); $types[$default] .= theme('item_list', array(t('Default'))); $sections[] = array( 'edit' => 'admin/store/settings/quotes/methods', 'title' => t('Shipping types'), 'items' => $types, ); return theme('uc_settings_overview', $sections); } /** * Default shipping settings. * * Sets the default shipping location of the store. Allows the user to * determine which quotin methods are enabled and which take precedence over * the others. Also sets the default quote and shipping types of all products * in the store. Individual products may be configured differently. * * @ingroup forms * @see uc_quote_admin_settings_submit */ function uc_quote_admin_settings() { $address = variable_get('uc_quote_store_default_address', new stdClass()); $form = array(); $form['uc_quote_log_errors'] = array('#type' => 'checkbox', '#title' => t('Log errors during checkout to watchdog'), '#default_value' => variable_get('uc_quote_log_errors', false), ); $form['uc_quote_display_debug'] = array('#type' => 'checkbox', '#title' => t('Display debug information to administrators.'), '#default_value' => variable_get('uc_quote_display_debug', false), ); $form['uc_quote_require_quote'] = array('#type' => 'checkbox', '#title' => t('Prevent the customer from completing an order if a shipping quote is not selected.'), '#default_value' => variable_get('uc_quote_require_quote', true), ); $form['uc_quote_pane_description'] = array( '#type' => 'fieldset', '#title' => t('Shipping quote pane description'), '#summary callback ' => 'summarize_form', '#tree' => TRUE, '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['uc_quote_pane_description']['text'] = array( '#type' => 'textarea', '#title' => t('Message text'), '#default_value' => variable_get('uc_quote_pane_description', t('Shipping quotes are generated automatically when you enter your address and may be updated manually with the button below.')), ); $form['uc_quote_pane_description']['format'] = filter_form(variable_get('uc_quote_desc_format', FILTER_FORMAT_DEFAULT), NULL, array('uc_quote_pane_description', 'format')); $form['uc_quote_pane_description']['format']['#summary callback'] = 'summarize_null'; $form['uc_quote_err_msg'] = array('#type' => 'fieldset', '#title' => t('Shipping quote error message'), '#tree' => TRUE, '#collapsible' => true, '#collapsed' => true, ); $form['uc_quote_err_msg']['text'] = array('#type' => 'textarea', '#title' => t('Message text'), '#default_value' => variable_get('uc_quote_err_msg', t("There were problems getting a shipping quote. Please verify the delivery and product information and try again.\nIf this does not resolve the issue, please call in to complete your order.")), ); $form['uc_quote_err_msg']['format'] = filter_form(variable_get('uc_quote_msg_format', FILTER_FORMAT_DEFAULT), NULL, array('uc_quote_err_msg', 'format')); $form['default_address'] = array('#type' => 'fieldset', '#title' => t('Default pickup address'), '#description' => t("When delivering products to customers, the original location of the product must be known in order to accurately quote the shipping cost and set up a delivery. This form provides the default location for products across the entire store. If a product's individual pickup address is blank, Übercart looks for the manufacturer's. If that is also blank, it uses the store's default pickup address."), '#collapsible' => true, '#collapsed' => false, ); $form['default_address']['first_name'] = uc_textfield(uc_get_field_name('first_name'), $address->first_name, FALSE); $form['default_address']['last_name'] = uc_textfield(uc_get_field_name('last_name'), $address->last_name, FALSE); $form['default_address']['company'] = uc_textfield(uc_get_field_name('company'), $address->company, FALSE); $form['default_address']['phone'] = uc_textfield(uc_get_field_name('phone'), $address->phone, FALSE, NULL, 32, 16); $form['default_address']['street1'] = uc_textfield(uc_get_field_name('street1'), $address->street1, FALSE, NULL, 64); $form['default_address']['street2'] = uc_textfield(uc_get_field_name('street2'), $address->street2, FALSE, NULL, 64); $form['default_address']['city'] = uc_textfield(uc_get_field_name('city'), $address->city, FALSE); if (isset($_POST['country'])) { $country = $_POST['country']; } else { $country = $address->country; } $form['default_address']['country'] = uc_country_select(uc_get_field_name('country'), $address->country); $form['default_address']['zone'] = uc_zone_select(uc_get_field_name('zone'), $address->zone, null, $country); $form['default_address']['postal_code'] = uc_textfield(uc_get_field_name('postal_code'), $address->postal_code, FALSE, NULL, 10, 10); $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') ); return $form; } /** * Submit function for uc_quote_admin_settings() in lieu of system_settings_form(). */ function uc_quote_admin_settings_submit($form_id, $form_values) { $address = new stdClass(); $address->first_name = $form_values['first_name']; $address->last_name = $form_values['last_name']; $address->company = $form_values['company']; $address->phone = $form_values['phone']; $address->street1 = $form_values['street1']; $address->street2 = $form_values['street2']; $address->city = $form_values['city']; $address->zone = $form_values['zone']; $address->postal_code = $form_values['postal_code']; $address->country = $form_values['country']; variable_set('uc_quote_store_default_address', $address); variable_set('uc_quote_log_errors', $form_values['uc_quote_log_errors']); variable_set('uc_quote_display_debug', $form_values['uc_quote_display_debug']); variable_set('uc_quote_require_quote', $form_values['uc_quote_require_quote']); variable_set('uc_quote_pane_description', $form_values['uc_quote_pane_description']['text']); variable_set('uc_quote_desc_format', $form_values['uc_quote_pane_description']['format']); variable_set('uc_quote_err_msg', $form_values['uc_quote_err_msg']['text']); variable_set('uc_quote_msg_format', $form_values['uc_quote_err_msg']['format']); drupal_set_message(t('The configuration options have been saved.')); } /** * Settings for the shipping quote methods. * * Enable and reorder shipping quote methods. Set the default shipping type. * * @ingroup forms * @see theme_uc_quote_method_settings * @see uc_quote_method_settings_validate * @see uc_quote_method_settings_submit */ function uc_quote_method_settings() { $form = array(); $form['methods'] = array( '#tree' => true ); $enabled = variable_get('uc_quote_enabled', array()); $weight = variable_get('uc_quote_method_weight', array()); $methods = uc_quote_shipping_method_options(); if (is_array($methods)) { foreach ($methods as $id => $title) { $form['methods'][$id]['uc_quote_enabled'] = array('#type' => 'checkbox', '#default_value' => $enabled[$id], ); $form['methods'][$id]['uc_quote_method_weight'] = array('#type' => 'weight', '#delta' => 5, '#default_value' => $weight[$id], ); } } $shipping_types = uc_quote_shipping_type_options(); if (is_array($shipping_types)) { $form['uc_quote_type_weight'] = array('#type' => 'fieldset', '#title' => t('Type ordering'), '#description' => t('Determines which shipping methods are quoted at checkout when products of different shipping types are ordered. Lighter weights are chosen first.'), '#collapsible' => true, '#tree' => true, ); $weight = variable_get('uc_quote_type_weight', array()); $shipping_methods = module_invoke_all('shipping_method'); $method_types = array(); foreach ($shipping_methods as $method) { $method_types[$method['quote']['type']][] = $method['title']; } if (is_array($method_types['order'])) { $form['uc_quote_type_weight']['#description'] .= t('
The %list methods are compatible with any shipping type.', array('%list' => implode(', ', $method_types['order']))); } foreach ($shipping_types as $id => $title) { $form['uc_quote_type_weight'][$id] = array('#type' => 'weight', '#title' => $title . (is_array($method_types[$id]) ? ' ('. implode(', ', $method_types[$id]) .')' : ''), '#delta' => 5, '#default_value' => $weight[$id], ); } } $form['uc_store_shipping_type'] = array('#type' => 'select', '#title' => t('Default order fulfillment type for products'), '#options' => $shipping_types, '#default_value' => variable_get('uc_store_shipping_type', 'small_package'), ); $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') ); return $form; } /** * Display a formatted list of shipping quote methods and form elements. * * @ingroup themeable * @see uc_quote_method_settings */ function theme_uc_quote_method_settings($form) { $methods = uc_quote_shipping_method_options(); $output = ''; $header = array(t('Enable'), t('Shipping method'), t('Weight')); $rows = array(); foreach (element_children($form['methods']) as $method) { $row = array(); $row[] = drupal_render($form['methods'][$method]['uc_quote_enabled']); $row[] = $methods[$method]; $row[] = drupal_render($form['methods'][$method]['uc_quote_method_weight']); $rows[] = $row; } $output .= theme('table', $header, $rows); $output .= drupal_render($form); return $output; } /** * Validation handler for uc_quote_method_settings(). * * Must enable at least one shipping method. */ function uc_quote_method_settings_validate($form_id, $form_values) { $none_enabled = true; if (is_array($form_values['methods'])) { foreach ($form_values['methods'] as $method) { if ($method['uc_quote_enabled']) { $none_enabled = false; } } } if ($none_enabled) { form_set_error('uc_quote_enabled', t('At least one shipping quote method must be enabled.')); } } /** * Submit handler for uc_quote_method_settings(). */ function uc_quote_method_settings_submit($form_id, $form_values) { $enabled = array(); $method_weight = array(); foreach ($form_values['methods'] as $id => $method) { $enabled[$id] = $method['uc_quote_enabled']; $method_weight[$id] = $method['uc_quote_method_weight']; } variable_set('uc_quote_enabled', $enabled); variable_set('uc_quote_method_weight', $method_weight); variable_set('uc_quote_type_weight', $form_values['uc_quote_type_weight']); variable_set('uc_store_shipping_type', $form_values['uc_store_shipping_type']); workflow_ng_clear_cache(); drupal_set_message(t('The configuration options have been saved.')); } /****************************************************************************** * Module Functions * ******************************************************************************/ /** * Store the shipping type of products and manufacturers. * * Fulfillment modules are invoked for products that match their shipping type. * This function stores the shipping type of a product or a manufacturer. * * @param $id_type * product | manufacturer * @param $id * Either the node id or term id of the object receiving the shipping type. * @param $shipping_type * The type of product that is fulfilled by various fulfillment modules. */ function uc_quote_set_shipping_type($id_type, $id, $shipping_type) { db_query("DELETE FROM {uc_quote_shipping_types} WHERE id_type = '%s' AND id = %d", $id_type, $id); if ($shipping_type !== '') { db_query("INSERT INTO {uc_quote_shipping_types} (id_type, id, shipping_type) VALUES ('%s', %d, '%s')", $id_type, $id, $shipping_type); } } /** * Retrieve a product's or manufacturer's shipping type from the database. * * @param $id_type * product | manufacturer * @param $id * Either the node id or term id of the object that was assigned the shipping type. * @return The shipping type. */ function uc_quote_get_shipping_type($id_type, $id) { static $types = array(); if (!isset($types[$id_type][$id])) { $types[$id_type][$id] = db_result(db_query("SELECT shipping_type FROM {uc_quote_shipping_types} WHERE id_type = '%s' AND id = %d", $id_type, $id)); } return $types[$id_type][$id]; } /** * Get a product's shipping type, defaulting to its manufacturer's or the store's if it doesn't exist. * * @param $product * The product object. * @return The shipping type. */ function uc_product_get_shipping_type($product) { $shipping_type = variable_get('uc_store_shipping_type', 'small_package'); if (module_exists('uc_manufacturer') && $product->manufacturer) { $m = taxonomy_get_term_by_name($product->manufacturer); if ($type = uc_quote_get_shipping_type('manufacturer', $m->tid)) { $shipping_type = $type; } } if ($type = uc_quote_get_shipping_type('product', $product->nid)) { $shipping_type = $type; } return $shipping_type; } /** * Get a product's default shipping address. * * Load the default shipping address of a product, it's manufacturer's, or the * store's, whichever is available. * * @param $nid * A product node id. * @return * An address object. */ function uc_quote_get_default_shipping_address($nid) { $address = db_fetch_object(db_query("SELECT first_name, last_name, company, street1, street2, city, zone, postal_code, country, phone FROM {uc_quote_product_locations} WHERE nid = %d", $nid)); if (empty($address)) { if (module_exists('uc_manufacturer')) { $manufacturer = uc_product_get_manufacturer($nid); $address = db_fetch_object(db_query("SELECT first_name, last_name, company, street1, street2, city, zone, postal_code, country, phone FROM {uc_quote_manufacturer_locations} WHERE tid = %d", $manufacturer->tid)); } if (empty($address)) { $address = variable_get('uc_quote_store_default_address', new stdClass()); } } return $address; } /** * Cart pane callback. * * @ingroup forms * @see theme_uc_cart_pane_quotes */ function uc_cart_pane_quotes($items) { global $user; // Get all quote types neccessary to fulfill order. $shipping_types = array(); foreach ($items as $product) { $shipping_types[] = uc_product_get_shipping_type($product); } $shipping_types = array_unique($shipping_types); $all_types = module_invoke_all('shipping_type'); $shipping_type = ''; $type_weight = 1000; // arbitrary large number foreach ($shipping_types as $type) { if ($all_types[$type]['weight'] < $type_weight) { $shipping_type = $all_types[$type]['id']; $type_weight = $all_types[$type]['weight']; } } $methods = array_filter(module_invoke_all('shipping_method'), '_uc_quote_method_enabled'); uasort($methods, '_uc_quote_type_sort'); $method_choices = array(); foreach ($methods as $method) { if ($method['quote']['type'] == 'order' || $method['quote']['type'] == $shipping_type) { $method_choices[$method['id']] = $method['title']; } } $form['delivery_country'] = uc_country_select(uc_get_field_name('country'), uc_store_default_country(), NULL, 'name', TRUE); $country_id = isset($_POST['delivery_country']) ? intval($_POST['delivery_country']) : uc_store_default_country(); $form['delivery_zone'] = uc_zone_select(uc_get_field_name('zone'), null, null, $country_id, 'name', true); $form['delivery_postal_code'] = uc_textfield(uc_get_field_name('postal_code'), '', TRUE, NULL, 10, 10); $form['quote_method'] = array('#type' => 'hidden', '#value' => key($method_choices), ); $form['get_quote'] = array('#type' => 'button', '#value' => t('Calculate'), ); $form['page'] = array('#type' => 'hidden', '#value' => 'cart', ); $form['uid'] = array('#type' => 'hidden', '#value' => $user->uid, ); $form['quote'] = array('#type' => 'markup', '#value' => '
', ); uc_add_js(array( 'uc_quote' => array( 'progress_msg' => t('Receiving quotes:'), 'err_msg' => check_markup(variable_get('uc_quote_err_msg', t("There were problems getting a shipping quote. Please verify the delivery and product information and try again.\nIf this does not resolve the issue, please call in to complete your order.")), variable_get('uc_quote_msg_format', FILTER_FORMAT_DEFAULT), false), ) ), 'setting'); uc_add_js('misc/progress.js'); uc_add_js(drupal_get_path('module', 'uc_quote') .'/uc_quote.js'); $prod_string = ''; foreach (uc_cart_get_contents() as $item) { $prod_string .= '|'. $item->nid; $prod_string .= '^'. $item->title; $prod_string .= '^'. $item->model; $prod_string .= '^'. $item->manufacturer; $prod_string .= '^'. $item->qty; $prod_string .= '^'. $item->cost; $prod_string .= '^'. $item->price; $prod_string .= '^'. $item->weight; $prod_string .= '^'. serialize($item->data); } $prod_string = substr($prod_string, 1); // If a previous quote gets loaded, make sure it gets saved again. // Also, make sure the previously checked option is checked by default. uc_add_js('$(function() { setQuoteCallbacks("'. urlencode($prod_string) .'"); $("#uc-cart-pane-quotes").submit(function() { quoteCallback("'. urlencode($prod_string) .'"); return false; }); })', 'inline'); return $form; } /** * Display the formatted quote cart pane. */ function theme_uc_cart_pane_quotes($form) { $output = '
'; $output .= ''. t('Estimated shipping cost:') .''; $output .= drupal_render($form['delivery_country']); $output .= drupal_render($form['delivery_zone']); $output .= drupal_render($form['delivery_postal_code']); $output .= drupal_render($form['get_quote']); $output .= drupal_render($form); $output .= '
'; return $output; } /** * Shipping quote checkout pane callback. * * Selects a quoting method based on the enabled methods' weight and the types * of products in the cart. The "Get Quotes" button fires a callback that returns * a form for the customer to select a rate based on their needs and preferences. * * Adds a line item to the order that records the chosen shipping quote. */ function uc_checkout_pane_quotes($op, &$arg1, $arg2) { global $user; switch ($op) { case 'view': $description = check_markup(variable_get('uc_quote_pane_description', t('Shipping quotes are generated automatically when you enter your address and may be updated manually with the button below.')), variable_get('uc_quote_desc_format', FILTER_FORMAT_DEFAULT)); // Let Javascript know where we are. $contents['page'] = array('#type' => 'hidden', '#value' => 'checkout', ); $contents['uid'] = array('#type' => 'hidden', '#value' => $user->uid, ); $contents['quote_button'] = array( '#type' => 'button', '#value' => t('Click to calculate shipping'), '#weight' => 0, ); uc_add_js(array( 'uc_quote' => array( 'progress_msg' => t('Receiving quotes:'), 'err_msg' => check_markup(variable_get('uc_quote_err_msg', t("There were problems getting a shipping quote. Please verify the delivery address and product information and try again.\nIf this does not resolve the issue, please call @phone to complete your order.", array('@phone' => variable_get('uc_store_phone', null)))), variable_get('uc_quote_msg_format', FILTER_FORMAT_DEFAULT), false), ) ), 'setting'); uc_add_js('misc/progress.js'); uc_add_js(drupal_get_path('module', 'uc_quote') .'/uc_quote.js'); $default = $arg1->quote['method'] .'---'. ($arg1->quote['accessorials'] ? $arg1->quote['accessorials'] : 0); $prod_string = ''; foreach (uc_cart_get_contents() as $item) { $prod_string .= '|'. $item->nid; $prod_string .= '^'. $item->title; $prod_string .= '^'. $item->model; $prod_string .= '^'. $item->manufacturer; $prod_string .= '^'. $item->qty; $prod_string .= '^'. $item->cost; $prod_string .= '^'. $item->price; $prod_string .= '^'. $item->weight; $prod_string .= '^'. serialize($item->data); } $prod_string = substr($prod_string, 1); // If a previous quote gets loaded, make sure it gets saved again. // Also, make sure the previously checked option is checked by default. uc_add_js('$(function() { setQuoteCallbacks("'. urlencode($prod_string) .'"); var quoteButton = $("input:radio[@name=quote-option]").click(function() { var quoteButton = $(this); var label = quoteButton.parent("label").text().split(":", 2)[0]; quoteButton.end(); var rate = $("input:hidden[@name=\'rate[" + quoteButton.val() + "]\']").val(); set_line_item("shipping", label, rate, 1, 1, false); if (window.getTax) { getTax(); } else if (window.render_line_items) { render_line_items(); } }).filter("[@value='. $default .']").click(); var quoteDiv = $("#quote"); if (quoteDiv.length && $("#quote input[@name=quote-form]").length == 0) { quoteDiv.append(""); } });', 'inline'); return array('description' => $description, 'contents' => $contents); case 'process': if (!isset($_POST['quote-option'])) { if (variable_get('uc_quote_require_quote', true)) { drupal_set_message(t('You must select a shipping option before continuing.'), 'error'); return false; } else { return true; } } $details = array(); foreach ($arg1 as $key => $value) { if (strpos($key, 'delivery_') !== false) { $details[substr($key, 9)] = $value; } } $products = array(); foreach ($arg1->products as $id => $product) { $node = (array)node_load($product->nid); foreach ($node as $key => $value) { if (!isset($product->$key)) { $product->$key = $value; } } $arg1->products[$id] = $product; } $quote_option = explode('---', $_POST['quote-option']); $arg1->quote['method'] = $quote_option[0]; $arg1->quote['accessorials'] = $quote_option[1]; $_SESSION['quote']['quote_form'] = rawurldecode($_POST['quote-form']); $methods = array_filter(module_invoke_all('shipping_method'), '_uc_quote_method_enabled'); $method = $methods[$quote_option[0]]; $quote_data = array(); ob_start(); workflow_ng_invoke_event('get_quote_from_'. $method['id'], $arg1, $method, $user); $quote_string = ob_get_contents(); ob_end_clean(); $quote_data = unserialize($quote_string); if (!isset($quote_data[$quote_option[1]])) { drupal_set_message(t('Invalid option selected. Recalculate shipping quotes to continue.'), 'error'); return false; } $label = $method['quote']['accessorials'][$quote_option[1]]; $arg1->quote['rate'] = $quote_data[$quote_option[1]]['rate']; $result = db_query("SELECT line_item_id FROM {uc_order_line_items} WHERE order_id = %d AND type = 'shipping'", $arg1->order_id); if ($lid = db_result($result)) { uc_order_update_line_item($lid, $label, $arg1->quote['rate'] ); } else { uc_order_line_item_add($arg1->order_id, 'shipping', $label, $arg1->quote['rate'] ); } return true; case 'review': $result = db_query("SELECT * FROM {uc_order_line_items} WHERE order_id = %d AND type = '%s'", $arg1->order_id, 'shipping'); if ($line_item = db_fetch_object($result)) { $review[] = array('title' => $line_item->title, 'data' => uc_currency_format($line_item->amount)); } return $review; } } /** * Shipping quote order pane callback. */ function uc_order_pane_quotes($op, $arg1) { switch ($op) { case 'edit-form': // Let Javascript know where we are. $form['quotes']['page'] = array( '#type' => 'hidden', '#value' => 'order-edit', ); $form['quotes']['quote_button'] = array( '#type' => 'submit', '#value' => t('Get shipping quotes'), ); $form['quotes']['add_quote'] = array( '#type' => 'submit', '#value' => t('Apply to order'), '#attributes' => array('class' => 'save-button'), '#disabled' => TRUE, ); $form['quotes']['quote'] = array( '#type' => 'markup', '#value' => '
', ); uc_add_js(array( 'uc_quote' => array( 'progress_msg' => t('Receiving quotes:'), 'err_msg' => check_markup(variable_get('uc_quote_err_msg', t("There were problems getting a shipping quote. Please verify the delivery and product information and try again.\nIf this does not resolve the issue, please call in to complete your order.")), variable_get('uc_quote_msg_format', FILTER_FORMAT_DEFAULT), false), ) ), 'setting'); uc_add_js('misc/progress.js'); uc_add_js(drupal_get_path('module', 'uc_quote') .'/uc_quote.js'); $default = $arg1->quote['accessorials'] ? $arg1->quote['accessorials'] : 0; // If a previous quote gets loaded, make sure it gets saved again. // Also, make sure the previously checked option is checked by default. uc_add_js('$(function() { setQuoteCallbacks(); $("input:radio[@name=quote-option]").filter("[@value='. $default .']").attr("checked", "checked"); var quoteDiv = $("#quote"); if (quoteDiv.length && $("#quote input[@name=quote-form]").length == 0) { quoteDiv.append(""); } })', 'inline'); return $form; case 'edit-theme': return drupal_render($arg1['quotes']); case 'edit-process': //drupal_set_message('
'. print_r($_POST, true) .'
'); if (isset($_POST['quote-option'])) { list($changes['quote']['method'], $changes['quote']['accessorials']) = explode('---', $_POST['quote-option']); } $changes['quote']['rate'] = $_POST['rate'][$_POST['quote-option']]; $changes['quote']['quote_form'] = rawurldecode($_POST['quote-form']); return $changes; case 'edit-ops': return array(t('Apply to order')); case t('Apply to order'): if (isset($_POST['quote-option'])) { if ($order = uc_order_load($arg1['order_id'])) { $user = user_load(array('uid' => $order->uid)); $details = array(); foreach ($order as $key => $value) { if (strpos($key, 'delivery_') !== false) { $details[substr($key, 9)] = $value; } } $products = array(); foreach ($order->products as $product) { if ($product->nid) { $node = (array)node_load($product->nid); foreach ($node as $key => $value) { if (!isset($product->$key)) { $product->$key = $value; } } } $products[] = $product; } //drupal_set_message('
'. print_r($order, true) .'
'); $quote_option = explode('---', $_POST['quote-option']); $order->quote['method'] = $quote_option[0]; $order->quote['accessorials'] = $quote_option[1]; $order->quote['quote_form'] = rawurldecode($_POST['quote-form']); $methods = array_filter(module_invoke_all('shipping_method'), '_uc_quote_method_enabled'); $method = $methods[$quote_option[0]]; $quote_data = array(); ob_start(); workflow_ng_invoke_event('get_quote_from_'. $method['id'], $order, $method, $user); $quote_string = ob_get_contents(); ob_end_clean(); $quote_data = unserialize($quote_string); //drupal_set_message('Chosen quote method:
'. print_r($method, true) .'
'); //drupal_set_message('Chosen quote data:
'. print_r($quote_data, true) .'
'); if (!isset($quote_data[$quote_option[1]])) { drupal_set_message(t('Invalid option selected. Recalculate shipping quotes to continue.'), 'error'); break; } $label = $method['quote']['accessorials'][$quote_option[1]]; $order->quote['rate'] = $quote_data[$quote_option[1]]['rate']; $result = db_query("SELECT line_item_id FROM {uc_order_line_items} WHERE order_id = %d AND type = 'shipping'", $arg1['order_id']); if ($lid = db_result($result)) { uc_order_update_line_item($lid, $label, $order->quote['rate'] ); } else { uc_order_line_item_add($order->order_id, 'shipping', $label, $order->quote['rate'] ); } } } break; } } function uc_quote_save_choice($form_values) { $quote_option = explode('---', $_POST['quote-option']); $_SESSION['quote'] = array('method' => $quote_option[0], 'accessorials' => $quote_option[1], 'rate' => $_POST['rate'][$_POST['quote-option']], 'quote_form' => $_POST['quote-form'], ); } function uc_quote_cache_quotes($form_id, &$form) { if ($form_id == 'uc_cart_checkout_form') { if (isset($_SESSION['quote']) && $_SESSION['quote']['rate']) { $quote = $_SESSION['quote']; $form['panes']['quotes']['quote'] = array('#type' => 'markup', '#value' => '
'. rawurldecode($_SESSION['quote']['quote_form']) .'
', '#weight' => 1, ); $methods = module_invoke_all('shipping_method'); $method = $methods[$quote['method']]; uc_add_js('$(document).ready(function() { $("#quote").find("input:radio[@value='. $quote['method'] . '---'. $quote['accessorials'] .']").eq(0).change().attr("checked", "checked"); if (window.set_line_item) { set_line_item("shipping", "'. $method['quote']['accessorials'][$quote['accessorials']] .'", '. $quote['rate'] .', 1, 1, false); } if (window.getTax) { getTax(); setTaxCallbacks(); } else if (window.render_line_items) { render_line_items(); } });', 'inline'); } else { $form['panes']['quotes']['quote'] = array('#type' => 'markup', '#value' => '
', '#weight' => 1, ); } } } /** * Callback to return the shipping quote(s) of the appropriate quoting method(s). */ function uc_quote_request_quotes() { /* print '
';
  print_r($_POST);
  print '
'; */ $products = array(); foreach (explode('|', urldecode($_POST['products'])) as $item) { $props = explode('^', $item); $product = new stdClass(); $product->nid = $props[0]; $product->title = $props[1]; $product->model = $props[2]; $product->manufacturer = $props[3]; $product->qty = $props[4]; $product->cost = $props[5]; $product->price = $props[6]; $product->weight = $props[7]; if ($data = unserialize($props[8])) { $product->data = $data; } else { $product->data = $props[8]; } if ($product->nid) { $node = (array)node_load($product->nid); foreach ($node as $key => $value) { if (!isset($product->$key)) { $product->$key = $value; } } } $products[] = $product; } $fake_order = new stdClass(); $fake_order->uid = $_POST['uid']; $fake_order->products = $products; foreach ((array) $_POST['details'] as $type => $address) { foreach ($address as $key => $value) { if ($key == 'country' AND $value == '') { $value = variable_get('uc_store_country', 840); } $field = $type .'_'. $key; $fake_order->$field = $value; } } // Consider the total to be from products only, because line items are // mostly non-existent at this point. $fake_order->order_total = uc_order_get_total($fake_order, true); // Get all quote types neccessary to fulfill order. $quote_data = _uc_quote_assemble_quotes($fake_order); //drupal_set_message('
'. print_r($methods, true) .'
'); //drupal_set_message('
'. print_r($quote_data, true) .'
'); $return_quotes = array(); foreach ($quote_data as $method_id => $options) { foreach ($options as $accsrl => $data) { $return_quotes[$method_id .'---'. $accsrl] = $data; } } drupal_set_header("Content-Type: text/javascript; charset=utf-8"); print drupal_to_js($return_quotes); exit(); } function _uc_quote_assemble_quotes($order) { global $user; $account = user_load(array('uid' => $order->uid)); if (!$account) { $account = $user; } $products = $order->products; $shipping_types = array(); foreach ($products as $product) { $shipping_types[] = uc_product_get_shipping_type($product); } $shipping_types = array_unique($shipping_types); $all_types = module_invoke_all('shipping_type'); $shipping_type = ''; // Use the most prominent shipping type (lightest weight). $type_weight = 1000; // arbitrary large number foreach ($shipping_types as $type) { if ($all_types[$type]['weight'] < $type_weight) { $shipping_type = $all_types[$type]['id']; $type_weight = $all_types[$type]['weight']; } } $methods = array_filter(module_invoke_all('shipping_method'), '_uc_quote_method_enabled'); uasort($methods, '_uc_quote_type_sort'); foreach ($methods as $id => $method) { if ($method['quote']['type'] != 'order' && $method['quote']['type'] != $shipping_type) { unset($methods[$id]); } } ob_start(); //drupal_set_message('
'. print_r($products, true) .'
'); $quote_data = array(); foreach ($methods as $method) { workflow_ng_invoke_event('get_quote_from_'. $method['id'], $order, $method, $account); $data = ob_get_contents(); if ($data = unserialize($data)) { $quote_data[$method['id']] = $data; } ob_clean(); } ob_end_clean(); return $quote_data; } /** * Callback for array_filter(). */ function _uc_quote_method_enabled($method) { return $method['enabled']; } /** * Callback for uasort(). */ function _uc_quote_type_sort($a, $b) { $aw = $a['weight']; $bw = $b['weight']; if ($aw == $bw) { return strcasecmp($a['id'], $b['id']); } else { return ($aw < $bw) ? -1 : 1; } } /** * Callback for uasort(). * * Sort service rates by increasing price. */ function uc_quote_price_sort($a, $b) { $ar = $a['rate']; $br = $b['rate']; if ($ar == $br) { return 0; } else { return ($ar < $br) ? -1 : 1; } } /** * Returns an array of quote types to be selected in a form. */ function uc_quote_type_options() { $methods = module_invoke_all('shipping_method'); foreach ($methods as $method) { if (isset($method['quote'])) { $types[$method['id']] = $method['title']; } } return $types; } /** * Returns an array of shipping types to be selected in a form. */ function uc_quote_shipping_type_options() { $ship_types = module_invoke_all('shipping_type'); uasort ($ship_types, '_uc_quote_type_sort'); $types = array(); foreach ($ship_types as $ship_type) { $types[$ship_type['id']] = $ship_type['title']; } if (!count($types)) { $types['small_package'] = t('Small package'); } return $types; } /** * Returns an array of shipping methods to be selected in a form. */ function uc_quote_shipping_method_options() { $methods = module_invoke_all('shipping_method'); uasort($methods, '_uc_quote_type_sort'); $types = array(); foreach ($methods as $method) { $types[$method['id']] = $method['title']; } return $types; }