=== modified file 'payment/uc_payment/uc_payment.js'
--- payment/uc_payment/uc_payment.js	2009-02-19 15:55:26 +0000
+++ payment/uc_payment/uc_payment.js	2009-09-14 14:08:25 +0000
@@ -1,5 +1,21 @@
 // $Id$
 
+/**
+ * Calculate the number of bytes of a Unicode string.
+ *
+ * Gratefully stolen from http://dt.in.th/2008-09-16.string-length-in-bytes.html.
+ * Javascript String.length returns the number of characters, but PHP strlen()
+ * returns the number of bytes. When building serialize()d strings in JS,
+ * use this function to get the correct string length.
+ */
+String.prototype.bytes = function() {
+  // Drupal.encodeURIComponent() gets around some weirdness in
+  // encodeURIComponent(), but encodes some characters twice. The first
+  // replace takes care of those while the second lets String.length count
+  // the multi-byte characters.
+  return Drupal.encodeURIComponent(this).replace(/%252[36F]/g, 'x').replace(/%../g, 'x').length;
+};
+
 // Arrays for order total preview data.
 var li_titles = {};
 var li_values = {};
@@ -47,6 +63,74 @@
   $(id).empty().append(progress.element);
 }
 
+function serializeOrder() {
+  var products = $("[@name=cart_contents]").val();
+  if (!products) {
+    return false;
+  }
+
+  var p_email = $("input[@name*=primary_email]").val() || '';
+  var s_f_name = $("input[@name*=delivery_first_name]").val() || '';
+  var s_l_name = $("input[@name*=delivery_last_name]").val() || '';
+  var s_street1 = $("input[@name*=delivery_street1]").val() || '';
+  var s_street2 = $("input[@name*=delivery_street2]").val() || '';
+  var s_city = $("input[@name*=delivery_city]").val() || '';
+  var s_zone = $("select[@name*=delivery_zone]").val() || '0';
+  var s_code = $("input[@name*=delivery_postal_code]").val() || '';
+  var s_country = $("select[@name*=delivery_country]").val() || '0';
+
+  var b_f_name = $("input[@name*=billing_first_name]").val() || '';
+  var b_l_name = $("input[@name*=billing_last_name]").val() || '';
+  var b_street1 = $("input[@name*=billing_street1]").val() || '';
+  var b_street2 = $("input[@name*=billing_street2]").val() || '';
+  var b_city = $("input[@name*=billing_city]").val() || '';
+  var b_zone = $("select[@name*=billing_zone]").val() || '0';
+  var b_code = $("input[@name*=billing_postal_code]").val() || '';
+  var b_country = $("select[@name*=billing_country]").val() || '0';
+
+  var line_item = '';
+  var key;
+  var type;
+  var i = 0;
+  for (key in li_titles) {
+    temp = key.split('_', 2);
+    if (temp[1] != undefined && temp[1].match(/^\d+$/)) {
+      type = temp[0];
+    }
+    else {
+      type = key;
+    }
+    line_item = line_item + 'i:' + i + ';a:5:{s:5:"title";s:' + li_titles[key].bytes() + ':"' + li_titles[key] + '";s:4:"type";s:'+ type.bytes() + ':"'+ type + '";s:6:"amount";d:' + li_values[key] + ';s:6:"weight";d:' + li_weight[key] + ';s:6:"summed";i:' + li_summed[key] + ';}';
+    i++;
+  }
+  line_item = 's:10:"line_items";a:' + i + ':{' + line_item + '}';
+
+  var order_size = 21;
+  var order = 'O:8:"stdClass":' + order_size + ':{s:8:"products";' + products
+    + 's:8:"order_id";i:0;'
+    + 's:3:"uid";i:0;'
+    + 's:13:"primary_email";s:' + p_email.bytes() + ':"' + p_email
+    + '";s:19:"delivery_first_name";s:' + s_f_name.bytes() + ':"' + s_f_name
+    + '";s:18:"delivery_last_name";s:' + s_l_name.bytes() + ':"' + s_l_name
+    + '";s:16:"delivery_street1";s:' + s_street1.bytes() + ':"' + s_street1
+    + '";s:16:"delivery_street2";s:' + s_street2.bytes() + ':"' + s_street2
+    + '";s:13:"delivery_city";s:' + s_city.bytes() + ':"' + s_city
+    + '";s:13:"delivery_zone";i:' + s_zone
+    + ';s:20:"delivery_postal_code";s:' + s_code.bytes() +':"' + s_code
+    + '";s:16:"delivery_country";i:' + s_country + ';'
+    + 's:18:"billing_first_name";s:' + b_f_name.bytes() + ':"' + b_f_name
+    + '";s:17:"billing_last_name";s:' + b_l_name.bytes() + ':"' + b_l_name
+    + '";s:15:"billing_street1";s:' + b_street1.bytes() + ':"' + b_street1
+    + '";s:15:"billing_street2";s:' + b_street2.bytes() + ':"' + b_street2
+    + '";s:12:"billing_city";s:' + b_city.bytes() + ':"' + b_city
+    + '";s:12:"billing_zone";i:' + b_zone
+    + ';s:19:"billing_postal_code";s:' + b_code.bytes() +':"' + b_code
+    + '";s:15:"billing_country";i:' + b_country + ';'
+    + line_item + '}';
+
+  return order;
+}
+
 /**
  * Sets a line item in the order total preview.
  */
@@ -88,11 +172,11 @@
   line_update = this_update.getTime();
 
   // Put all the existing line item data into a single array.
-  var li_info = {};
+  //var li_info = {};
   var cur_total = 0;
   $.each(li_titles,
     function(a, b) {
-      li_info[a] = li_weight[a] + ';' + li_values[a] + ';' + li_titles[a] + ';' + li_summed[a];
+      //li_info[a] = li_weight[a] + ';' + li_values[a] + ';' + li_titles[a] + ';' + li_summed[a];
 
       // Tally up the current order total for storage in a hidden item.
       if (li_titles[a] != '' && li_summed[a] == 1) {
@@ -105,7 +189,7 @@
   $('#order-total-throbber').addClass('ubercart-throbber').html('&nbsp;&nbsp;&nbsp;&nbsp;');
 
   // Post the line item data to a URL and get it back formatted for display.
-  $.post(Drupal.settings.basePath + '?q=cart/checkout/line_items', li_info,
+  $.post(Drupal.settings.basePath + '?q=cart/checkout/line_items', {order: serializeOrder()},
     function(contents) {
       // Only display the changes if this was the last requested update.
       if (this_update.getTime() == line_update) {

=== modified file 'payment/uc_payment/uc_payment.module'
--- payment/uc_payment/uc_payment.module	2009-08-17 21:21:34 +0000
+++ payment/uc_payment/uc_payment.module	2009-09-14 14:08:32 +0000
@@ -318,43 +318,44 @@
  ******************************************************************************/
 
 function uc_payment_get_totals() {
+  $output = '';
   if (is_array($_POST)) {
-    foreach ($_POST as $key => $value) {
-      $totals[$key] = explode(';', $value);
-    }
+    $order = unserialize($_POST['order']);
   }
 
-  if (is_array($totals) && count($totals) > 0) {
-    usort($totals, '_total_sort');
+  if ($order) {
+    usort($order->line_items, 'uc_weight_sort');
 
     $output = t('Order total preview:')
              .' <span id="order-total-throbber"></span><table>';
     $grand_total = 0;
 
     $context = array(
-      'revision' => 'themed',
       'type' => 'line_item',
+      'subject' => array(
+        'order' => $order,
+      ),
     );
 
-    foreach ($totals as $line) {
-      if (!empty($line[2])) {
-        $context['subject'] = array(
-          'line_item' => $line,
-        );
-        $output .= '<tr><td align="right"><b>'. $line[2] .':</b></td>'
-                  .'<td align="right">'. uc_price($line[1], $context) .'</td></tr>';
-        if ($line[3]) {
-          $grand_total += round($line[1], 2);
+    foreach ($order->line_items as $line) {
+      if (!empty($line['title'])) {
+        $context['revision'] = 'themed';
+        $context['subject']['line_item'] = $line;
+
+        $output .= '<tr><td align="right"><b>'. $line['title'] .':</b></td>'
+                  .'<td align="right">'. uc_price($line['amount'], $context) .'</td></tr>';
+
+        if ($line['summed']) {
+          $context['revision'] = 'altered';
         }
       }
     }
 
+    $context['revision'] = 'themed';
     $context['type'] = 'amount';
-    $context['subject'] = array(
-      'grand_total' => $grand_total,
-    );
+    unset($context['subject']);
     $output .= '<tr><td align="right"><b>'. t('Order total:') .'</b></td>'
-              .'<td align="right">'. uc_price($grand_total, $context)
+              .'<td align="right">'. uc_price(uc_order_get_total($order), $context)
               .'</td></tr></table>';
   }
 

=== modified file 'payment/uc_payment/uc_payment_checkout_pane.inc'
--- payment/uc_payment/uc_payment_checkout_pane.inc	2009-07-11 19:04:32 +0000
+++ payment/uc_payment/uc_payment_checkout_pane.inc	2009-09-14 14:08:25 +0000
@@ -104,9 +104,12 @@
       $context = array(
         'revision' => 'themed',
         'type' => 'line_item',
+        'subject' => array(
+          'order' => $arg1,
+        ),
       );
       foreach ($line_items as $line_item) {
-        $context['subject'] = array('line_item' => $line_item);
+        $context['subject']['line_item'] = $line_item;
         $review[] = array('title' => $line_item['title'], 'data' => uc_price($line_item['amount'], $context));
       }
       $review_data = _payment_method_data($arg1->payment_method, 'review');

=== modified file 'shipping/uc_quote/uc_quote.pages.inc'
--- shipping/uc_quote/uc_quote.pages.inc	2009-08-25 18:12:07 +0000
+++ shipping/uc_quote/uc_quote.pages.inc	2009-09-14 14:08:25 +0000
@@ -108,6 +108,14 @@
     }
   }
 
+  $context = array(
+    'revision' => 'formatted',
+    'type' => 'line_item',
+    'subject' => array(
+      'order' => $order,
+    ),
+  );
+
   //drupal_set_message('<pre>'. print_r($products, TRUE) .'</pre>');
   $quote_data = array();
   $arguments = array(
@@ -133,6 +141,19 @@
     $predicate = array_shift($predicates);
     if ($predicate && ca_evaluate_conditions($predicate, $arguments)) {
       $data = uc_quote_action_get_quote($order, $method, $user);
+
+      foreach ($data as &$quote) {
+        if (isset($quote['rate'])) {
+          $context['subject']['line_item'] = array(
+            'type' => 'shipping',
+            'name' => $quote['option_label'],
+            'amount' => $quote['rate'],
+            'weight' => 1,
+          );
+
+          $quote['format'] = uc_price($quote['rate'], $context);
+        }
+      }
       $quote_data[$method['id']] = $data;
     }
   }

=== modified file 'uc_cart/uc_cart.module'
--- uc_cart/uc_cart.module	2009-08-27 18:21:42 +0000
+++ uc_cart/uc_cart.module	2009-09-14 14:08:32 +0000
@@ -684,7 +684,7 @@
 
     $context = array(
       'revision' => 'themed',
-      'field' => 'price',
+      'type' => 'price',
     );
 
     // Loop through each item.

=== modified file 'uc_cart/uc_cart.pages.inc'
--- uc_cart/uc_cart.pages.inc	2009-08-14 19:10:32 +0000
+++ uc_cart/uc_cart.pages.inc	2009-09-14 14:08:25 +0000
@@ -215,27 +215,7 @@
   }
   unset($_SESSION['expanded_panes']);
 
-  $context = array(
-    'revision' => 'altered',
-    'type' => 'cart_item',
-  );
   $contents = uc_cart_get_contents();
-  foreach ($contents as $key => $item) {
-    $price_info = array(
-      'price' => $item->price,
-      'qty' => $item->qty,
-    );
-    $context['subject'] = array(
-      'cart' => $contents,
-      'cart_item' => $item,
-      'node' => node_load($item->nid),
-    );
-
-    // Get the altered price per unit, as ordered products have a locked-in
-    // price. Price altering rules may change over time, but the amount paid
-    // by the customer does not after the fact.
-    $contents[$key]->price = uc_price($price_info, $context) / $item->qty;
-  }
 
   $form['cart_contents'] = array(
     '#type' => 'hidden',
@@ -306,6 +286,30 @@
 
   $order->products = unserialize($form_state['values']['cart_contents']);
 
+  $context = array(
+    'revision' => 'original',
+    'type' => 'order_product',
+  );
+  foreach ($order->products as $key => $item) {
+    $price_info = array(
+      'price' => $item->price,
+      'qty' => $item->qty,
+    );
+    $context['subject'] = array(
+      'order' => $order,
+      'product' => $item,
+      'node' => node_load($item->nid),
+    );
+
+    // Get the altered price per unit, as ordered products have a locked-in
+    // price. Price altering rules may change over time, but the amount paid
+    // by the customer does not after the fact.
+    $price = uc_price($price_info, $context) / $item->qty;
+    if ($order->products[$key]->price != $price) {
+      $order->products[$key]->data['altered_price'] = $price;
+    }
+  }
+
   $order->order_total = uc_order_get_total($order, TRUE);
 
   // Validate/process the cart panes.  A FALSE value results in failed checkout.

=== modified file 'uc_order/templates/customer.itpl.php'
--- uc_order/templates/customer.itpl.php	2009-07-24 17:06:02 +0000
+++ uc_order/templates/customer.itpl.php	2009-09-14 14:39:52 +0000
@@ -158,6 +158,7 @@
                     <?php
                     $context = array(
                       'revision' => 'themed',
+                      'type' => 'line_item',
                       'subject' => array(
                         'order' => $order,
                       ),
@@ -204,6 +205,7 @@
                           <?php if (is_array($order->products)) {
                             $context = array(
                               'revision' => 'formatted',
+                              'type' => 'order_product',
                               'subject' => array(
                                 'order' => $order,
                               ),
@@ -214,6 +216,7 @@
                                 'qty' => $product->qty,
                               );
                               $context['subject']['order_product'] = $product;
+                              $context['subject']['node'] = node_load($product->nid);
                               ?>
                           <tr>
                             <td valign="top" nowrap="nowrap">

=== modified file 'uc_order/uc_order.admin.inc'
--- uc_order/uc_order.admin.inc	2009-08-20 19:22:37 +0000
+++ uc_order/uc_order.admin.inc	2009-09-14 14:08:32 +0000
@@ -1285,7 +1285,7 @@
         'qty' => 1,
       );
       $context = array(
-        'revision' => 'altered',
+        'revision' => 'original',
         'type' => 'order_product',
         'subject' => array(
           'order' => $order,

=== modified file 'uc_order/uc_order.line_item.inc'
--- uc_order/uc_order.line_item.inc	2009-07-24 17:06:02 +0000
+++ uc_order/uc_order.line_item.inc	2009-09-14 14:08:25 +0000
@@ -24,25 +24,45 @@
       );
       return $lines;
     case 'cart-preview':
-      $context = array(
-        'revision' => 'altered',
-        'type' => 'cart_item',
-      );
-      $subtotal = 0;
-      foreach ($arg1 as $item) {
-        $price_info = array(
-          'price' => $item->price,
-          'qty' => ($item->qty) ? $item->qty : 1,
-        );
-        $context['subject'] = array(
-          'cart_item' => $item,
-          'node' => node_load($item->nid),
-        );
-        $total = uc_price($price_info, $context);
-        $subtotal += $total;
-      }
       if (module_exists('uc_payment') && variable_get('uc_pane_payment_enabled', TRUE)) {
-        drupal_add_js("if (Drupal.jsEnabled) { \$(document).ready( function() { set_line_item('subtotal', '". t('Subtotal') ."', ". $subtotal .", -10); } )};", 'inline');
+        $context = array(
+          'revision' => 'altered',
+          'type' => 'cart_item',
+        );
+        $subtotal = 0;
+        foreach ($arg1 as $item) {
+          $price_info = array(
+            'price' => $item->price,
+            'qty' => ($item->qty) ? $item->qty : 1,
+          );
+          $context['subject'] = array(
+            'cart_item' => $item,
+            'node' => node_load($item->nid),
+          );
+          $total = uc_price($price_info, $context);
+          $subtotal += $total;
+        }
+
+        $line_item = array(
+          'type' => 'subtotal',
+          'name' => t('Subtotal'),
+          'amount' => $subtotal,
+          'weight' => -10,
+        );
+
+        $order = new stdClass();
+        $order->products = $arg1;
+
+        $context = array(
+          'revision' => 'altered',
+          'type' => 'line_item',
+          'subject' => array(
+            'order' => $order,
+            'line_item' => $line_item,
+          ),
+        );
+
+        drupal_add_js("if (Drupal.jsEnabled) { \$(document).ready( function() { set_line_item('subtotal', '". $line_item['name'] ."', ". uc_price($line_item['amount'], $context) .", ". $line_item['weight'] ."); } )};", 'inline');
       }
       break;
   }
@@ -69,10 +89,19 @@
 function uc_line_items_calculate($order) {
   $total = 0;
 
+  $context = array(
+    'revision' => 'altered',
+    'type' => 'line_item',
+    'subject' => array(
+      'order' => $order,
+    ),
+  );
+
   if (is_array($order->line_items)) {
     foreach ($order->line_items as $item) {
+      $context['subject']['line_item'] = $item;
       if (_line_item_data($item['type'], 'calculated') == TRUE) {
-        $total += $item['amount'];
+        $total += uc_price($item['amount'], $context);
       }
     }
   }
@@ -136,6 +165,9 @@
     $items[$i]['enabled'] = variable_get('uc_li_'. $items[$i]['id'] .'_enabled', (!isset($items[$i]['enabled']) ? TRUE : $items[$i]['enabled']));
     $items[$i]['weight'] = variable_get('uc_li_'. $items[$i]['id'] .'_weight', (!isset($items[$i]['weight']) ? 1 : $items[$i]['weight']));
   }
+
+  drupal_alter('line_item_data', $items);
+
   usort($items, 'uc_weight_sort');
 
   return $items;

=== modified file 'uc_order/uc_order.module'
--- uc_order/uc_order.module	2009-08-17 21:21:34 +0000
+++ uc_order/uc_order.module	2009-09-14 14:08:32 +0000
@@ -1263,13 +1263,20 @@
         $result = $type['callback']('load', $order);
         if ($result !== FALSE && is_array($result)) {
           foreach ($result as $line) {
+            $line = (object)$line;
+            $line->type = $type['id'];
+            if (!isset($line->weight)) {
+              $line->weight = $type['weight'];
+            }
+            drupal_alter('line_item', $line, $order);
+
             $items[] = array(
-              'line_item_id' => $line['id'],
-              'type' => $type['id'],
-              'title' => $line['title'],
-              'amount' => $line['amount'],
-              'weight' => isset($line['weight']) ? $line['weight'] : $type['weight'],
-              'data' => isset($line['data']) ? $line['data'] : NULL,
+              'line_item_id' => $line->id,
+              'type' => $line->type,
+              'title' => $line->title,
+              'amount' => $line->amount,
+              'weight' => $line->weight,
+              'data' => $line->data,
             );
           }
         }
@@ -1414,8 +1421,22 @@
   $total = 0;
 
   if (is_array($order->products)) {
+    $context = array(
+      'revision' => 'altered',
+      'type' => 'order_product',
+    );
+
     foreach ($order->products as $product) {
-      $total += $product->price * $product->qty;
+      $price_info = array(
+        'price' => $product->price,
+        'qty' => ($product->qty) ? $product->qty : 1,
+      );
+      $context['subject'] = array(
+        'order' => $order,
+        'product' => $product,
+        'node' => node_load($product->nid),
+      );
+      $total += uc_price($price_info, $context);
     }
   }
 

=== modified file 'uc_taxes/uc_taxes.js'
--- uc_taxes/uc_taxes.js	2009-08-11 21:07:20 +0000
+++ uc_taxes/uc_taxes.js	2009-09-14 14:08:25 +0000
@@ -5,22 +5,6 @@
  * Handle asynchronous requests to calculate taxes.
  */
 
-/**
- * Calculate the number of bytes of a Unicode string.
- *
- * Gratefully stolen from http://dt.in.th/2008-09-16.string-length-in-bytes.html.
- * Javascript String.length returns the number of characters, but PHP strlen()
- * returns the number of bytes. When building serialize()d strings in JS,
- * use this function to get the correct string length.
- */
-String.prototype.bytes = function() {
-  // Drupal.encodeURIComponent() gets around some weirdness in
-  // encodeURIComponent(), but encodes some characters twice. The first
-  // replace takes care of those while the second lets String.length count
-  // the multi-byte characters.
-  return Drupal.encodeURIComponent(this).replace(/%252[36F]/g, 'x').replace(/%../g, 'x').length;
-};
-
 var pane = '';
 if ($("input[name*=delivery_]").length) {
   pane = 'delivery'
@@ -47,68 +31,9 @@
  * Get tax calculations for the current cart and line items.
  */
 function getTax() {
-  var products = $("[name=cart_contents]").val();
-
-  var p_email = $("input[name*=primary_email]").val() || '';
-  var s_f_name = $("input[name*=delivery_first_name]").val() || '';
-  var s_l_name = $("input[name*=delivery_last_name]").val() || '';
-  var s_street1 = $("input[name*=delivery_street1]").val() || '';
-  var s_street2 = $("input[name*=delivery_street2]").val() || '';
-  var s_city = $("input[name*=delivery_city]").val() || '';
-  var s_zone = $("select[name*=delivery_zone]").val() || '0';
-  var s_code = $("input[name*=delivery_postal_code]").val() || '';
-  var s_country = $("select[name*=delivery_country]").val() || '0';
-
-  var b_f_name = $("input[name*=billing_first_name]").val() || '';
-  var b_l_name = $("input[name*=billing_last_name]").val() || '';
-  var b_street1 = $("input[name*=billing_street1]").val() || '';
-  var b_street2 = $("input[name*=billing_street2]").val() || '';
-  var b_city = $("input[name*=billing_city]").val() || '';
-  var b_zone = $("select[name*=billing_zone]").val() || '0';
-  var b_code = $("input[name*=billing_postal_code]").val() || '';
-  var b_country = $("select[name*=billing_country]").val() || '0';
-
-  var order_size = 21;
-  var line_item = '';
-  var key;
-  var type;
-  var i = 0;
-  for (key in li_titles) {
-    if (key != 'subtotal') {
-      temp = key.split('_', 2);
-      if (temp[1] != undefined && temp[1].match(/^\d+$/)) {
-        type = temp[0];
-      }
-      else {
-        type = key;
-      }
-      line_item = line_item + 'i:' + i + ';a:3:{s:5:"title";s:' + li_titles[key].bytes() + ':"' + li_titles[key] + '";s:4:"type";s:'+ type.bytes() + ':"'+ type + '";s:6:"amount";d:' + li_values[key] + ';}';
-      i++;
-    }
-  }
-  line_item = 's:10:"line_items";a:' + i + ':{' + line_item + '}';
-  var order = 'O:8:"stdClass":' + order_size + ':{s:8:"products";' + products
-    + 's:8:"order_id";i:0;'
-    + 's:3:"uid";i:0;'
-    + 's:13:"primary_email";s:' + p_email.bytes() + ':"' + p_email
-    + '";s:19:"delivery_first_name";s:' + s_f_name.bytes() + ':"' + s_f_name
-    + '";s:18:"delivery_last_name";s:' + s_l_name.bytes() + ':"' + s_l_name
-    + '";s:16:"delivery_street1";s:' + s_street1.bytes() + ':"' + s_street1
-    + '";s:16:"delivery_street2";s:' + s_street2.bytes() + ':"' + s_street2
-    + '";s:13:"delivery_city";s:' + s_city.bytes() + ':"' + s_city
-    + '";s:13:"delivery_zone";i:' + s_zone
-    + ';s:20:"delivery_postal_code";s:' + s_code.bytes() +':"' + s_code
-    + '";s:16:"delivery_country";i:' + s_country + ';'
-    + 's:18:"billing_first_name";s:' + b_f_name.bytes() + ':"' + b_f_name
-    + '";s:17:"billing_last_name";s:' + b_l_name.bytes() + ':"' + b_l_name
-    + '";s:15:"billing_street1";s:' + b_street1.bytes() + ':"' + b_street1
-    + '";s:15:"billing_street2";s:' + b_street2.bytes() + ':"' + b_street2
-    + '";s:12:"billing_city";s:' + b_city.bytes() + ':"' + b_city
-    + '";s:12:"billing_zone";i:' + b_zone
-    + ';s:19:"billing_postal_code";s:' + b_code.bytes() +':"' + b_code
-    + '";s:15:"billing_country";i:' + b_country + ';'
-    + line_item + '}';
-  if (!!products) {
+  var order = serializeOrder();
+
+  if (!!order) {
     $.ajax({
       type: "POST",
       url: Drupal.settings.basePath + "?q=taxes/calculate",
@@ -123,16 +48,7 @@
           key = 'tax_' + taxes[j].id;
           // Check that this tax is a new line item, or updates its amount.
           if (li_values[key] == undefined || li_values[key] != taxes[j].amount) {
-            // The "Subtotal before taxes" line item is not added into the
-            // Total line item.
-            if (taxes[j].id == 'subtotal') {
-              summed = 0;
-            }
-            else {
-              summed = 1;
-            }
-
-            set_line_item(key, taxes[j].name, taxes[j].amount, Drupal.settings.ucTaxWeight + taxes[j].weight / 10, summed, false);
+            set_line_item(key, taxes[j].name, taxes[j].amount, Drupal.settings.ucTaxWeight + taxes[j].weight / 10, taxes[j].summed, false);
 
             // Set flag to render all line items at once.
             render = true;

=== modified file 'uc_taxes/uc_taxes.module'
--- uc_taxes/uc_taxes.module	2009-08-25 18:12:07 +0000
+++ uc_taxes/uc_taxes.module	2009-09-14 14:08:25 +0000
@@ -216,7 +216,7 @@
       $taxes = uc_taxes_calculate($order);
       foreach ($taxes as $tax) {
         $lines[] = array(
-          'id' => 'tax',
+          'id' => ($tax->summed ? 'tax' : 'tax_included'),
           'title' => $tax->name,
           'amount' => $tax->amount,
           'weight' => variable_get('uc_li_tax_weight', 9) + $tax->weight / 10,
@@ -239,6 +239,9 @@
   }
   if (is_array($order->line_items)) {
     foreach ($order->line_items as $key => $line_item) {
+      if ($line_item['type'] == 'subtotal') {
+        continue;
+      }
       if (substr($line_item['type'], 0, 3) != 'tax') {
         $amount += $line_item['amount'];
         $different = TRUE;
@@ -451,9 +454,18 @@
   $order = $_POST['order'];
   if ($order = unserialize(rawurldecode($order))) {
     $taxes = module_invoke_all('calculate_tax', $order);
-    $subtotal = uc_line_item_tax_subtotal('load', $order);
-    if (is_array($subtotal) && !empty($taxes)) {
-      $taxes['subtotal'] = array('id' => 'subtotal', 'name' => $subtotal[0]['title'], 'amount' => $subtotal[0]['amount'], 'weight' => -10);
+    $callback = _line_item_data('tax_subtotal', 'callback');
+    if (function_exists($callback)) {
+      $subtotal = $callback('load', $order);
+      if (is_array($subtotal) && !empty($taxes)) {
+        $taxes['subtotal'] = (object)array(
+          'id' => 'subtotal',
+          'name' => $subtotal[0]['title'],
+          'amount' => $subtotal[0]['amount'],
+          'weight' => -10,
+          'summed' => 0,
+        );
+      }
     }
   }
   drupal_json((array) $taxes);
@@ -517,7 +529,13 @@
   }
   $amount = $taxable_amount * $tax->rate;
   if ($amount) {
-    $line_item = (object)array('id' => $tax->id, 'name' => $tax->name, 'amount' => $amount, 'weight' => $tax->weight);
+    $line_item = (object)array(
+      'id' => $tax->id,
+      'name' => $tax->name,
+      'amount' => $amount,
+      'weight' => $tax->weight,
+      'summed' => 1,
+    );
     $line_item->data = array(
       'tax_id' => $tax->id,
       'tax_rate' => $tax->rate,

