=== modified file 'docs/hooks.php'
--- docs/hooks.php	2009-06-16 21:01:56 +0000
+++ docs/hooks.php	2009-06-17 08:10:11 +0000
@@ -1146,6 +1146,8 @@ function hook_ucga_display() {
  */
 function hook_uc_price_handler() {
   return array(
+    // Locations that this alterer cares about.
+    'locations' => array('customer-orders', 'customer-orders-total'),
     'alter' => array(
       'title' => t('My price handler'),
       'description' => t('Handles my price alteration needs.'),

=== modified file 'payment/uc_2checkout/uc_2checkout.module'
--- payment/uc_2checkout/uc_2checkout.module	2009-05-09 17:44:11 +0000
+++ payment/uc_2checkout/uc_2checkout.module	2009-06-16 23:58:59 +0000
@@ -243,3 +243,10 @@ function _2checkout_post_url($type) {
       return 'https://www.2checkout.com/2co/buyer/purchase';
   }
 }
+
+function uc_2checkout_uc_price_locations() {
+  return array(
+    '2checkout-form' => t("The price(s) on the 2checkout form."),
+  );
+}
+

=== modified file 'payment/uc_authorizenet/uc_authorizenet.module'
--- payment/uc_authorizenet/uc_authorizenet.module	2009-04-28 16:54:42 +0000
+++ payment/uc_authorizenet/uc_authorizenet.module	2009-06-16 23:58:59 +0000
@@ -1203,3 +1203,12 @@ function _uc_authorizenet_login_data() {
 
   return $data;
 }
+
+function uc_authorizenet_uc_price_locations() {
+  return array(
+    'cim-profile-charge' => t("Price of a charge against a CIM profile."),
+    'authorize.net-charge' => t("Price of a charge handled by authorize.net."),
+    'authorize.net-charge-comment' => t("Price on a comment on a charge handled by authorize.net."),
+  );
+}
+

=== modified file 'payment/uc_credit/test_gateway.module'
--- payment/uc_credit/test_gateway.module	2009-04-18 01:03:01 +0000
+++ payment/uc_credit/test_gateway.module	2009-06-16 23:58:59 +0000
@@ -67,3 +67,10 @@ function test_gateway_charge($order_id, 
 
   return $result;
 }
+
+function test_gateway_uc_price_locations() {
+  return array(
+    'test-gateway-charge-comment' => t("Price on a test gateway charge's comment."),
+  );
+}
+

=== modified file 'payment/uc_credit/uc_credit.module'
--- payment/uc_credit/uc_credit.module	2009-04-04 13:44:28 +0000
+++ payment/uc_credit/uc_credit.module	2009-06-16 23:58:59 +0000
@@ -1569,3 +1569,10 @@ function uc_credit_gateway_txn_types($ga
   return $types;
 }
 
+function uc_credit_uc_price_locations() {
+  return array(
+    'credit-card-form' => t("Price(s) for order total and balance on the credit card terminal page."),
+    'credit-card-terminal' => t("Price(s) for charge amount and authorized transactions on the credit card terminal page."),
+  );
+}
+

=== modified file 'uc_store/includes/uc_price.inc'
--- uc_store/includes/uc_price.inc	2009-05-08 19:14:30 +0000
+++ uc_store/includes/uc_price.inc	2009-06-17 08:55:06 +0000
@@ -1,5 +1,8 @@
 <?php
 
+define('UC_PRICE_LOCATIONS_FLAT', 1);
+define('UC_PRICE_LOCATIONS_INDEXED', 2);
+
 /**
  * The heart of the price modification/displaying system,
  * this function handles price alteration, formatting, theming, and caching.
@@ -88,6 +91,8 @@ function uc_price($price_info, $context,
     'revision' => 'themed'
   );
 
+  $location = isset($context['location']) ? $context['location'] : '';
+  
   // Clamp to allowed revisions.
   $revisions = array('original', 'altered', 'formatted-original', 'formatted', 'themed-original', 'themed');
 
@@ -124,8 +129,10 @@ function uc_price($price_info, $context,
     $values['original'] = $price_info['price'] * $price_info['qty'];
 
     // Alter the price, context, and options.
-    foreach ($handlers['alterers'] as $alterer) {
-      $alterer($price_info, $context, $options);
+    foreach ($handlers['alterers'] as $module => $alterer) {
+      if (uc_price_module_handles_location($module, $location)) {
+        $alterer($price_info, $context, $options);
+      }
     }
 
     // If a price placeholder was specified in the price info array...
@@ -232,12 +239,12 @@ function _uc_price_get_handlers($options
       'label' => TRUE,
     );
 
-    foreach ($hooks as $hook) {
+    foreach ($hooks as $module => $hook) {
       if (isset($hook['alter']['callback']) && function_exists($hook['alter']['callback'])) {
-        $handlers['alterers'][] = $hook['alter']['callback'];
+        $handlers['alterers'][$module] = $hook['alter']['callback'];
       }
       if (isset($hook['format']['callback']) && function_exists($hook['format']['callback'])) {
-        $handlers['formatters'][] = $hook['format']['callback'];
+        $handlers['formatters'][$module] = $hook['format']['callback'];
       }
 
       if (is_array($hook['options'])) {
@@ -254,6 +261,7 @@ function _uc_price_get_handlers($options
  */
 function uc_store_uc_price_handler() {
   return array(
+    'locations' => array('customer-orders'),
     'alter' => array(
       'title' => t('Default price handler'),
       'description' => t('The default handler alterer is simply responsible for prefixing various product prices for display.'),
@@ -322,3 +330,106 @@ function uc_store_price_handler_format($
   return $output;
 }
 
+/**
+ * Return a list of all price locations present.
+ * 
+ * @param $list_type
+ *   The type of location list to return. Accepted values are 
+ *   UC_PRICE_LOCATIONS_FLAT and UC_PRICE_LOCATIONS_INDEXED.
+ *   
+ * @return (array)
+ *   Returns a single dimensional array of locations if $list_type is
+ *   UC_PRICE_LOCATIONS_FLAT, otherwise, if it's UC_PRICE_LOCATIONS_INDEXED, a
+ *   multidimensional array or locations sorted by module will be returned.
+ */
+function uc_price_locations($list_type = UC_PRICE_LOCATIONS_FLAT) {
+  static $locations = array();
+  if (empty($locations[$list_type])) {
+    switch ($list_type) {
+      // Flat list, good for fast searching.
+      case UC_PRICE_LOCATIONS_FLAT:
+        $locations[$list_type] =  module_invoke_all('uc_price_locations');
+        break;
+      
+      // Indexed list, good for building pretty forms. 
+      case UC_PRICE_LOCATIONS_INDEXED:
+        foreach (module_implements('uc_price_locations') as $module) {
+          $l = module_invoke($module, 'uc_price_locations');
+          $locations[$list_type][$module] = $l;
+        }
+        break;
+    }
+  }
+  return $locations[$list_type];
+}
+
+/**
+ * Set the location configuration for one or all modules.
+ * 
+ * @param $config
+ *   The configuration data. If $module is NULL, then a multidimensional array
+ *   of data, the first dimension being modules, and the next being the
+ *   locations that each module cares about. If $module is populated with an
+ *   alterer module, a single dimension array of locations for that module.
+ * @param $module
+ *   The module whose configuration to set. Defaults to NULL (all modules).
+ */
+function uc_price_set_location_configuration($config, $module = NULL) {
+  $current = uc_price_get_location_configuration($module);
+  // Are we setting one module's list or all lists?
+  $config = $module ? array($module => $config) : $config;
+  foreach ($config as $alter_name => $alter) {
+    $current[$alter_name] = $alter;
+  }
+  // Store it in the database.
+  variable_set('uc_price_location_config', $current);
+}
+
+/**
+ * Get the current location configuration for one or all modules. If a variable
+ * record exists, retrieve it, otherwise use the defaults specified in the 
+ * module's hook_uc_price_handler(), in the 'locations' key. If that key isn't 
+ * present, then default to this module handling every location.
+ * 
+ * @param $module
+ *   The module whose configuration to retrieve. Defaults to NULL (all modules).
+ */
+function uc_price_get_location_configuration($module = NULL) {
+  static $config = array();
+  if (empty($config)) {
+    // Get the current location state.
+    $config = variable_get('uc_price_location_config', array());
+    // Even if it's been set, make sure all the modules have a representation. 
+    // This could get out of sync if there's a saved configuration and a new
+    // module with locations is enabled. 
+    foreach (module_implements('uc_price_handler') as $m) {
+      if (!isset($config[$m])) {
+        $info = module_invoke($m, 'uc_price_handler');
+        
+        // If there's a locations element use that, otherwise assume this module
+        // handles every location.
+        $config[$m] = isset($info['locations']) 
+          ? $info['locations'] 
+          : array_keys(uc_price_locations());
+      }
+    }
+  }
+  // Return either one module's list or all lists.
+  return $module ? (isset($config[$module]) ? $config[$module] : array()) : $config;
+}
+
+/**
+ * Check if a module's alterer handles a given location.
+ * 
+ * @param $module
+ *   The module of the price alterer to check.
+ * @param $location
+ *   The location.
+ * @return (bool)
+ *   Does this module's alterer handle this location?
+ */
+function uc_price_module_handles_location($module, $location) {
+  // Just get this module's configuration, and see if the location is present.
+  $config = uc_price_get_location_configuration($module);
+  return $config === TRUE ? TRUE : in_array($location, $config);
+}

=== modified file 'uc_store/uc_store.admin.inc'
--- uc_store/uc_store.admin.inc	2009-05-15 14:05:26 +0000
+++ uc_store/uc_store.admin.inc	2009-06-17 08:56:26 +0000
@@ -1095,9 +1095,18 @@ function uc_price_settings_form() {
   $options = array();
   $form = array();
 
+  // Empty out any cached price data.
+  cache_clear_all('*', 'cache_uc_price', TRUE);
+  
   // Get all the handlers available.
   $handlers = _uc_price_get_handlers(array('rebuild_handlers' => TRUE, 'all_handlers' => TRUE));
 
+  $form['uc_price_alterers_fieldset'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Price alterers'),
+    '#description' => t('Prices will be altered by enabled price alterers in their order in the table below.'),
+  );
+  
   // Build a draggable price alterer table.
   $form['uc_price_alterers']['#tree'] = TRUE;
 
@@ -1137,28 +1146,83 @@ function uc_price_settings_form() {
     }
   }
 
-  $form['price_alterers_description'] = array(
-    '#value' => '<div class="description">'. t('Prices will be altered by enabled price alterers in their order in the table above.') .'</div>',
+  $form['uc_price_formatter_fieldset'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Price formatter'),
   );
-
-  $form['uc_price_format_callback'] = array(
+  
+  $form['uc_price_formatter_fieldset']['uc_price_format_callback'] = array(
     '#type' => 'radios',
-    '#title' => t('Price formatter'),
     '#options' => $options,
     '#default_value' => variable_get('uc_price_format_callback', 'uc_store_price_handler_format'),
   );
 
-  $form['uc_price_caching'] = array(
+  $form['uc_price_caching_fieldset'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Caching'),
+  );
+  
+  $form['uc_price_caching_fieldset']['uc_price_caching'] = array(
     '#type' => 'checkbox',
     '#title' => t('Cache generated price values until the next cron run.'),
     '#description' => t('It may be helpful to disable caching when configuring modules that alter prices or price displays.<br />For high traffic sites with multiple price handlers, disabling this may hurt your performance.'),
     '#default_value' => variable_get('uc_price_caching', TRUE),
   );
 
+  $location_index = uc_price_locations(UC_PRICE_LOCATIONS_INDEXED);
+  $modules = module_implements('uc_price_handler');
+  
+  $form['uc_price_locations_fieldset'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Location overrides'),
+    '#description' => t('Everywhere a price is able to be altered on your site should contain a location. The matrix below allows you to override the locations that each alteration hook affects.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  
+  $form['uc_price_locations']['#tree'] = TRUE;
+  
+  $form['uc_price_locations']['#locations'] = $locations;
+  $form['uc_price_locations']['#modules'] = $modules;
+  
+  foreach ($location_index as $location_module => $locations) {
+    $form['uc_price_locations'][$location_module]['module'] = array(
+      '#value' => $location_module,
+      '#location' => 'module',
+    );
+    for ($i = 0; $i < count($modules); $i++) {
+      $form['uc_price_locations'][$location_module][] = array(
+        '#value' => ' ',
+      );
+    }
+    
+    foreach ($locations as $location => $description) {
+      $form['uc_price_locations'][$location]['location'] = array(
+        '#value' => $description,
+        '#location' => 'location',
+      );
+      
+      foreach ($modules as $module) {
+        $form['uc_price_locations'][$location][$module] = array(
+          '#type' => 'checkbox',
+          '#default_value' => uc_price_module_handles_location($module, $location),
+        ); 
+      }
+    }
+  }
+  
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Save configuration'),
-    '#suffix' => l(t('Cancel changes'), 'admin/store/settings/price-handlers'),
+  );
+  
+  $form['reset'] = array(
+    '#type' => 'submit',
+    '#value' => t('Reset locations'),
+  );
+  
+  $form['cancel'] = array(
+    '#value' => l(t('Cancel changes'), 'admin/store/settings/price-handlers'),
   );
 
   // Rebuild the handler cache!
@@ -1173,10 +1237,12 @@ function uc_price_settings_form() {
  * @ingroup themeable
  */
 function theme_uc_price_settings_form($form) {
+  $output = '';
+  
   // Add the tabledrag to the alterer table.
   drupal_add_tabledrag('uc-price-handler-table', 'order', 'sibling', 'uc-price-handler-table-weight');
 
-  $header = array(t('Price alterers'), t('Enabled'), t('Weight'));
+  $header = array('', t('Enabled'), t('Weight'));
 
   if (count(element_children($form['uc_price_alterers'])) > 0) {
     foreach (element_children($form['uc_price_alterers']) as $module) {
@@ -1192,30 +1258,97 @@ function theme_uc_price_settings_form($f
       );
     }
   }
+  $table = theme('table', $header, $rows, array('id' => 'uc-price-handler-table'));
+  
+  $form['uc_price_alterers_fieldset']['table'] = array(
+    '#value' => $table,
+  );
+  $output .= drupal_render($form['uc_price_alterers_fieldset']);
+  
+  $output .= drupal_render($form['uc_price_formatter_fieldset']);
+  $output .= drupal_render($form['uc_price_caching_fieldset']);
+  
+  $header = array(t('Location'));
+  foreach ($form['uc_price_locations']['#modules'] as $module) {
+    $header[] = $module;
+  }
 
-  $output = theme('table', $header, $rows, array('id' => 'uc-price-handler-table'))
-          . drupal_render($form);
+  $rows = array();
+  if (count(element_children($form['uc_price_locations'])) > 0) {
+    foreach (element_children($form['uc_price_locations']) as $child) {
+      $row = array();
 
+      foreach (element_children($form['uc_price_locations'][$child]) as $field) {
+        // Brain melt go away.
+        $child_field = &$form['uc_price_locations'][$child][$field];
+        $class = isset($child_field['#location']) ? $child_field['#location'] : '';
+          
+        $row[] = array(
+          'data' => drupal_render($child_field),
+          'class' => $class,
+        );
+      }
+
+      $rows[] = array(
+        'data' => $row,
+      );
+    }
+  }
+  $table = theme('table', $header, $rows, array('id' => 'uc-price-location-table'));
+  
+  $form['uc_price_locations_fieldset']['table'] = array(
+    '#value' => $table . drupal_render($form['reset']),
+  );
+  $output .= drupal_render($form['uc_price_locations_fieldset']);
+  
+  $output .= drupal_render($form);
+  
   return $output;
 }
 
 function uc_price_settings_form_submit($form, &$form_state) {
-  // Save the selected price formatter and price caching setting.
-  variable_set('uc_price_format_callback', $form_state['values']['uc_price_format_callback']);
-  variable_set('uc_price_caching', $form_state['values']['uc_price_caching']);
-
-  // Save the alterer configuration based on the table form.
-  $config = array();
+  switch ($form_state['values']['op']) {
 
-  foreach ($form_state['values']['uc_price_alterers'] as $module => $alterer) {
-    $config[$module] = $alterer;
+    case t('Save configuration'):
+      // Save the selected price formatter and price caching setting.
+      variable_set('uc_price_format_callback', $form_state['values']['uc_price_format_callback']);
+      variable_set('uc_price_caching', $form_state['values']['uc_price_caching']);
+    
+      // Save the alterer configuration based on the table form.
+      $config = array();
+    
+      foreach ($form_state['values']['uc_price_alterers'] as $module => $alterer) {
+        $config[$module] = $alterer;
+      }
+    
+      variable_set('uc_price_handler_config', $config);
+      
+      // Flip the array around, using module names as keys instead of locations.
+      $config = array();
+      foreach ($form_state['values']['uc_price_locations'] as $location => $modules) {
+        foreach ($modules as $module_name => $value) {
+          // Need to ensure the array, as if there were no locations set for a
+          // module, the module array would be non-existent.
+          if (!isset($config[$module_name])) $config[$module_name] = array();
+          
+          // Checked.
+          if ($value) {
+            $config[$module_name][] = $location;
+          }
+        }
+      }
+      uc_price_set_location_configuration($config);
+      
+      drupal_set_message(t('Price handler configuration saved.'));
+    
+      break;
+    
+    case t('Reset locations'):
+      variable_del('uc_price_location_config');
+      
+      drupal_set_message(t('The location configuration was reset.'));
+    
+      break;
   }
-
-  variable_set('uc_price_handler_config', $config);
-
-  // Empty out any cached price data.
-  cache_clear_all('*', 'cache_uc_price', TRUE);
-
-  drupal_set_message(t('Price handler configuration saved.'));
 }
 

=== modified file 'uc_store/uc_store.css'
--- uc_store/uc_store.css	2009-04-13 14:32:10 +0000
+++ uc_store/uc_store.css	2009-06-17 07:38:27 +0000
@@ -123,3 +123,12 @@ table.section-items td {
   background-repeat: no-repeat;
   background-position: 100% -20px;
 }
+
+#uc-price-location-table .module {
+  font-weight: bold;
+} 
+
+#uc-price-location-table .location {
+  padding-left:1.5em;
+} 
+

=== modified file 'uc_store/uc_store.module'
--- uc_store/uc_store.module	2009-06-07 05:15:51 +0000
+++ uc_store/uc_store.module	2009-06-17 06:59:49 +0000
@@ -2043,3 +2043,10 @@ function uc_store_image_widget_lightbox2
   return ' rel="'. $img_index .'"';
 }
 
+function uc_store_uc_price_locations() {
+  return array(
+    'currency-format-form' => t("The sample price on the currency format settings page."),
+    'customer-orders' => t("Prices of a customer's orders."),
+    'customer-orders-total' => t("Total price of a customer's orders."),
+  );
+}

