Index: uc_fedex.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uc_fedex/uc_fedex.admin.inc,v
retrieving revision 1.1
diff -u -r1.1 uc_fedex.admin.inc
--- uc_fedex.admin.inc	13 Apr 2009 00:45:05 -0000	1.1
+++ uc_fedex.admin.inc	24 Apr 2009 23:34:45 -0000
@@ -186,16 +186,34 @@
     '#description'   => t('Markup FedEx shipping weight before quote by weight amount, percentage, or multiplier.'),
   );
 
-  /* Form to select packaging type */
-  $form['uc_fedex_all_in_one'] = array(
-    '#type'          => 'radios',
-    '#title'         => t('Number of Packages'),
-    '#default_value' => variable_get('uc_fedex_all_in_one', 1),
+  // Container for packaging method fields
+  $form['uc_fedex_packaging_methods'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Packaging Methods'),
+    '#description' => t('Specifies available packaging methods and optional paramenters.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+
+  // List of available packaging methods
+  $form['uc_fedex_packaging_methods']['uc_fedex_packaging_method'] = array(
+    '#type' => 'radios',
+    '#title' => t('Packaging Methods'),
+    '#default_value' => variable_get('uc_fedex_packaging_method', 2),
     '#options' => array(
       0 => t('Each product in its own package'),
-      1 => t('All products in one package'),
+      1 => t('Break packages by FedEx Max Weight'),
+      2 => t('Break packages by specified weight'),
     ),
-    '#description' => t('Indicate whether each product is quoted as shipping separately or all in one package.'),
+    '#description' => t('Select the packaging method that most closely matches how you actualy package products.'),
+  );
+
+  // Weight to break packages by
+  $form['uc_fedex_packaging_methods']['uc_fedex_max_package_weight'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Max package weight'),
+    '#default_value' => variable_get('uc_fedex_max_package_weight', 70),
+    '#description' => t('Specify the max package weight.  Package weight will be the total product weight plus the weight markup if any.  Only effective if the "Break packages by specified weight" packaging method is selected.'),
   );
 
   $form['#validate'][] = 'uc_fedex_admin_settings_validate';
Index: uc_fedex.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uc_fedex/uc_fedex.module,v
retrieving revision 1.19
diff -u -r1.19 uc_fedex.module
--- uc_fedex.module	13 Apr 2009 14:21:29 -0000	1.19
+++ uc_fedex.module	24 Apr 2009 23:34:46 -0000
@@ -690,75 +690,133 @@
   $packages = array();
 
   // Determine maximum weight of products we can put into one
-  // package while staying below PACKAGE_WEIGHT_LIMIT.  This number
+  // package while staying below PACKAGE_WEIGHT_LIMIT. This number
   // depends on the package weight markup set in the FedEx module
   // administration menu.
-  $products_max_weight = PACKAGE_WEIGHT_LIMIT / uc_fedex_weight_markup(1);
+  $fedex_max_weight = PACKAGE_WEIGHT_LIMIT - uc_fedex_weight_markup(1);
 
-//if (variable_get('uc_fedex_all_in_one', TRUE)) {
-//}
-//else {
-//}
-
-  // Create first package
-  $package = new stdClass();
-  $package->quantity = 0;
-  $package->price    = 0.0;
-  $package->weight   = 0.0;
+  // If the user specified a package weight
+  switch (variable_get('uc_fedex_packaging_method', 2)) {
+    // User does not wish to specify a max package weight
+    case 0:
+    case 1:
+      $user_max_weight = $fedex_max_weight;
+      break;
+    // User would like to specify a max package weight
+    case 2:
+      // Determine the maximum weight of products we can put into one
+      // package while staying below uc_fedex_max_package_weight. This number
+      // depends on the package weight markup set in the FedEx module
+      // administration menu.
+      $user_max_weight = variable_get('uc_fedex_max_package_weight', 70) - uc_fedex_weight_markup(1);
+      break;
+  }
+
+  // Create a cumulative product package
+  $grouped_products = new stdClass();
+  $grouped_products->quantity = 0;
+  $grouped_products->price = 0.0;
+  $grouped_products->weight = 0.0;
 
   // Loop over products
   foreach ($products as $product) {
     // Get item weight
     $item_weight = $product->weight * uc_weight_conversion($product->weight_units, 'lb');
 
-    if ($item_weight >= $products_max_weight) {
+    if ($item_weight >= $fedex_max_weight) {
       // This product is too heavy to ship via FexEx Ground or FedEx Express -
       // quit with error
       return array();
     }
 
-    // Loop over qty of each product
-    for ($item=0; $item<$product->qty; $item++) {
-      // Test to see if putting this item into the current package put us
-      // over the weight limit
-      if (($package->weight + $item_weight) < $products_max_weight) {
-        // No?  Then update the package information and continue
-        $package->quantity += 1;
-        $package->price    += $product->price;
-        $package->weight   += $item_weight;
-      }
-      else {
-        // If weight >= maximum allowed weight, save current package to
-        // array and start a new package:
+    // If the item can be packaged with other items
+    if ($item_weight < $user_max_weight) {
+      // Group the product to be packaged later
+      $grouped_products->quantity += $product->qty;
+      $grouped_products->price    += $product->price * $product->qty;
+      $grouped_products->weight   += $item_weight * $product->qty;
+    }
+    // If the product cannot be packaged with other items
+    else {
+      // Loop over qty of each product
+      for ($item=0; $item<$product->qty; $item++) {
+        // Place each product in its own package
+        $package = new stdClass();
+        $package->quantity = 1;
+        $package->price    = $product->price;
+        $package->weight   = $item_weight;
 
         // First markup weight on a per-package basis
         $package->shipweight = uc_fedex_weight_markup($package->weight);
 
         // Save current package to array
         $packages[] = $package;
-
-        // Finally, start a new package
-        $package = new stdClass();
-        $package->quantity = 1;
-        $package->price    = $product->price;
-        $package->weight   = $item_weight;
       }
     }
   }
 
-  // No more products left to package.
-  // Take care of the partially-filled package we were working on
+  // Calculate the number of packages our grouped products will need
+  $num_packages = ceil($grouped_products->weight / $user_max_weight);
 
-  // Markup weight on a per-package basis
-  $package->shipweight = uc_fedex_weight_markup($package->weight);
+  // Calculate the average package values
+  $avg_quantity = $grouped_products->quantity / $num_packages;
+  $avg_price = $grouped_products->price / $num_packages;
+  $avg_weight = $grouped_products->weight / $num_packages;
+
+  // Keep track of remainders
+  $quantity_remainder = 0.0;
+  $price_remainder = 0.0;
+  $weight_remainder = 0.0;
+
+  // Loop over grouped products
+  for ($i = 0; $i < $num_packages; $i++) {
+    // Create a new package with averaged values
+    $package = new stdClass();
+
+    // Get the remainder amounts
+    $quantity_remainder += fmod($avg_quantity, 1);
+    $price_remainder += fmod($avg_price, 1);
+    $weight_remainder += fmod($avg_weight, 1);
+
+    // Round all values down, don't have to be precise
+    $package->quantity = floor($avg_quantity);
+    $package->price    = floor($avg_price);
+    $package->weight   = floor($avg_weight);
+
+    // If this is not the last package
+    if ($i != $num_packages - 1) {
+       // If remainders are >= 1, add them to the package
+      if ($quantity_remainder >= 1) {
+        $package->quantity += 1;
+        $quantity_remainder -= 1;
+      }
+      if ($price_remainder >= 1) {
+        $package->price += 1;
+        $price_remainder -= 1;
+      }
+      if ($weight_remainder >= 1) {
+        $package->weight += 1;
+        $weight_remainder -= 1;
+      }
+    }
+    // Last package
+    else {
+      // Add remainders to package
+      $package->quantity += $quantity_remainder;
+      $package->price += $price_remainder;
+      $package->weight += $weight_remainder;
+    }
 
-  // Save the partially-filled package to the array then exit
-  $packages[] = $package;
+    // First markup weight on a per-package basis
+    $package->shipweight = uc_fedex_weight_markup($package->weight);
 
+    // Save current package to array
+    $packages[] = $package;
+  }
+  
   return $packages;
 }
 
-
 /**
  * Convenience function to get FedEx codes for their package types.
  *
Index: uc_fedex.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uc_fedex/uc_fedex.install,v
retrieving revision 1.3
diff -u -r1.3 uc_fedex.install
--- uc_fedex.install	12 Apr 2009 05:58:57 -0000	1.3
+++ uc_fedex.install	24 Apr 2009 23:34:45 -0000
@@ -17,7 +17,6 @@
   variable_del('uc_fedex_server_role');
 
   variable_del('uc_fedex_services');
-  variable_del('uc_fedex_all_in_one');
   variable_del('uc_fedex_quote_type');
   variable_del('uc_fedex_dropoff_type');
   variable_del('uc_fedex_package_type');
@@ -28,4 +27,18 @@
   variable_del('uc_fedex_rate_markup_type');
   variable_del('uc_fedex_weight_markup');
   variable_del('uc_fedex_weight_markup_type');
+
+  variable_del('uc_fedex_packaging_method');
+  variable_del('uc_fedex_max_package_weight');
+}
+
+/**
+ * Implementation of hook_update_index
+ * 
+ * Delete unused variables
+ */
+function uc_fedex_update_6200() {
+  variable_set('uc_fedex_packaging_method', variable_get('uc_fedex_all_in_one', 1));
+  variable_del('uc_fedex_all_in_one');
+  return array();
 }
