=== modified file 'uc_price_per_role.install'
--- uc_price_per_role.install	2010-02-12 00:36:20 +0000
+++ uc_price_per_role.install	2010-02-12 02:18:50 +0000
@@ -49,14 +49,99 @@
       ),
       'price' => array(
         'type' => 'numeric',
-        'precision' => 10,
-        'scale' => 2,
+        'precision' => 16,
+        'scale' => 5,
         'not null' => TRUE,
-        'default' => 0,
+        'default' => 0.0,
       ),
     ),
     'primary key' => array('rpid'),
   );
 
+  $schema['uc_price_per_role_option_prices'] = array(
+    'description' => t('Ubercart price per role option prices'),
+    'fields' => array(
+      'opid' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'nid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'oid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'price' => array(
+        'type' => 'numeric',
+        'precision' => 16,
+        'scale' => 5,
+        'not null' => TRUE,
+        'default' => 0.0,
+      ),
+    ),
+    'primary key' => array('opid'),
+  );
+
   return $schema;
 }
+
+/**
+ * Add attribute options price table, update price precision. 
+ */
+function uc_price_per_role_update_6000() {
+  $ret = array();
+
+  db_change_field($ret, 'uc_price_per_role_prices', 'price', 'price', array('type' => 'numeric', 'precision' => 16, 'scale' => 5, 'not null' => TRUE, 'default' => 0.0));
+  
+  db_create_table($ret, 'uc_price_per_role_option_prices', array(
+    'description' => t('Ubercart price per role option prices'),
+    'fields' => array(
+      'opid' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'nid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'oid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'price' => array(
+        'type' => 'numeric',
+        'precision' => 16,
+        'scale' => 5,
+        'not null' => TRUE,
+        'default' => 0.0,
+      ),
+    ),
+    'primary key' => array('opid'),
+  ));
+
+  return $ret;
+}
\ No newline at end of file

=== modified file 'uc_price_per_role.module'
--- uc_price_per_role.module	2010-02-12 00:36:20 +0000
+++ uc_price_per_role.module	2010-02-12 05:31:46 +0000
@@ -2,6 +2,13 @@
 // $Id: uc_price_per_role.module,v 1.4 2009/09/18 13:17:06 longwave Exp $
 
 /**
+ * Implementation of hook_perm().
+ */
+function uc_price_per_role_perm() {
+  return array('access price selection block');
+}
+
+/**
  * Implementation of hook_menu().
  */
 function uc_price_per_role_menu() {
@@ -15,11 +22,35 @@
     'page arguments' => array('uc_price_per_role_settings_form'),
     'type' => MENU_NORMAL_ITEM,
   );
+  if (module_exists('uc_attribute')) {
+    $items['node/%node/edit/option_prices'] = array(
+      'title' => 'Option prices',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('uc_price_per_role_option_prices_form', 1),
+      'access callback' => 'uc_attribute_product_option_access',
+      'access arguments' => array(1),
+      'type' => MENU_LOCAL_TASK,
+      'weight' => 3,
+    );
+  }
 
   return $items;
 }
 
 /**
+ * Implementation of hook_menu_alter().
+ */
+function uc_price_per_role_menu_alter(&$items) {
+  // Make room in local menu for the 'Option prices' tab.
+  if (module_exists('uc_attribute')) {
+    $items['node/%node/edit/adjustments']['weight'] = $items['node/%node/edit/adjustments']['weight'] + 1;
+  }
+  if (isset($items['node/%node/edit/features'])) {
+    $items['node/%node/edit/features']['weight'] = $items['node/%node/edit/features']['weight'] + 1;
+  }
+}
+
+/**
  * Implementation of hook_theme().
  */
 function uc_price_per_role_theme() {
@@ -36,6 +67,12 @@
         'prices' => NULL,
       ),
     ),
+    'uc_price_per_role_option_prices_form' => array(
+      'file' => 'uc_price_per_role.module',
+      'arguments' => array(
+        'form' => NULL,
+      ),
+    ),
   );
 }
 
@@ -113,7 +150,6 @@
 function uc_price_per_role_form_alter(&$form, &$form_state, $form_id) {
   if ($form['#id'] == 'node-form' && isset($form['base']['prices'])) {
     $enabled = variable_get('uc_price_per_role_enabled', array());
-    $weights = variable_get('uc_price_per_role_weights', array());
 
     $form['base']['role_prices'] = array(
       '#weight' => 6,
@@ -126,7 +162,7 @@
         $form['base']['role_prices'][$rid] = array(
           '#type' => 'textfield',
           '#title' => t('%role price', array('%role' => $role)),
-          '#default_value' => $form['#node']->role_prices[$rid],
+          '#default_value' => uc_store_format_price_field_value($form['#node']->role_prices[$rid]),
           '#description' => t('Purchase price for %role users.', array('%role' => $role)),
           '#size' => 20,
           '#maxlength' => 35,
@@ -135,6 +171,47 @@
         );
       }
     }
+
+
+  } else if (strpos($form_id, 'add_to_cart_form')) {
+    // Modify product form attribute option prices.
+    $format = variable_get('uc_attribute_option_price_format', 'adjustment');
+    if (module_exists('uc_attribute') && $format != 'none') {
+      $nid = intval($form['nid']['#value']);
+      $product = node_load($nid);
+      $qty = intval($form['qty']['#value']);
+      if (!$qty) {
+        $qty = 1;
+      }
+
+      $priced_attributes = uc_attribute_priced_attributes($nid);
+      $role_prices = uc_price_per_role_load_option_prices($nid);
+
+      foreach (element_children($form['attributes']) as $aid) {
+        if (isset($form['attributes'][$aid]['#options'])) {
+          $attribute = uc_attribute_load($aid, $nid, 'product');
+
+          foreach (array_keys($form['attributes'][$aid]['#options']) as $oid) {
+            $price = uc_price_per_role_find_price($role_prices[$oid]);
+
+            if ($price !== FALSE) {
+              switch ($format) {
+                case 'total':
+                  $display_price = in_array($aid, $priced_attributes) ? ', '. uc_currency_format(($product->sell_price + $price) * $qty) : '';
+                  if (count($priced_attributes) == 1) {
+                    break;
+                  }
+                case 'adjustment':
+                  $display_price = ($price != 0 ? ', '. ($price > 0 ? '+' : '') . uc_currency_format($price * $qty) : '');
+                  break;
+              }
+
+              $form['attributes'][$aid]['#options'][$oid] = $attribute->options[$oid]->name . $display_price;
+            }
+          }
+        }
+      }
+    }
   }
 }
 
@@ -153,7 +230,7 @@
 function uc_price_per_role_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
   global $user;
 
-  if (in_array($node->type, module_invoke_all('product_types'))) {
+  if (in_array($node->type, uc_product_types())) {
     switch ($op) {
       case 'validate':
         if (isset($node->role_prices)) {
@@ -184,15 +261,9 @@
           $prices[$row->rid] = $row->price;
         }
 
-        // Find the price for the current role.
-        $enabled = variable_get('uc_price_per_role_enabled', array());
-        $weights = variable_get('uc_price_per_role_weights', array());
-        asort($weights);
-        foreach ($weights as $rid => $weight) {
-          if (isset($user->roles[$rid]) && $enabled[$rid] && isset($prices[$rid])) {
-            $node->sell_price = $prices[$rid];
-            break;
-          }
+        $price = uc_price_per_role_find_price($prices);
+        if ($price !== FALSE) {
+          $node->sell_price = $price;
         }
 
         return array('role_prices' => $prices);
@@ -212,3 +283,275 @@
     }
   }
 }
+
+/**
+ * Implementation of hook_cart_item().
+ */
+function uc_price_per_role_cart_item($op, &$item) {
+  if (module_exists('uc_attribute')) {
+    switch ($op) {
+      case 'load':
+        $role_prices = uc_price_per_role_load_option_prices($item->nid);
+        foreach (_uc_cart_product_get_options($item) as $option) {
+          $oid = $option['oid'];
+          $price = uc_price_per_role_find_price($role_prices[$oid]);
+          if ($price !== FALSE) {
+            $item->price += $price - $option['price'];
+          }
+        }
+    }
+  }
+}
+
+/**
+ * Form definition to edit a option prices.
+ */
+function uc_price_per_role_option_prices_form($form_state, $product) {
+  drupal_set_title(check_plain($product->title));
+
+  $role_prices = uc_price_per_role_load_option_prices($product->nid);
+  $enabled = array_keys(array_filter(variable_get('uc_price_per_role_enabled', array())));
+  
+  $form['help'] = array(
+    '#value' => t('Leave any box blank to use the standard price for the option.'),
+  );
+
+  foreach (uc_product_get_attributes($product->nid) as $aid => $attribute) {
+    $form['attributes'][$aid]['name'] = array(
+      '#value' => $attribute->name,
+    );
+    $form['attributes'][$aid]['aid'] = array(
+      '#type' => 'hidden',
+      '#value' => $attribute->aid,
+    );
+    $form['attributes'][$aid]['ordering'] = array(
+      '#type' => 'value',
+      '#value' => $attribute->ordering,
+    );
+
+    $form['attributes'][$aid]['options'] = array('#weight' => 2);
+
+    $base_attr = uc_attribute_load($attribute->aid);
+
+    if ($base_attr->options) {
+      $result = db_query("
+        SELECT ao.aid, ao.oid, ao.name, ao.price AS default_price, ao.ordering AS default_ordering, po.price, po.ordering, po.ordering IS NULL AS null_order FROM {uc_attribute_options} AS ao
+        LEFT JOIN {uc_product_options} AS po ON ao.oid = po.oid AND po.nid = %d
+        WHERE aid = %d ORDER BY null_order, po.ordering, default_ordering, ao.name", $product->nid, $attribute->aid);
+      while ($option = db_fetch_object($result)) {
+        $oid = $option->oid;
+
+        $form['attributes'][$aid]['options'][$oid]['name'] = array(
+          '#value' => $option->name,
+        );
+
+        $form['attributes'][$aid]['options'][$oid]['price'] = array(
+          '#value' => uc_currency_format(is_null($option->price) ? $option->default_price : $option->price),
+        );
+
+        foreach ($enabled as $rid) {
+          $form['attributes'][$aid]['options'][$oid]['role_prices'][$rid] = array(
+            '#type' => 'textfield',
+            '#default_value' => isset($role_prices[$oid][$rid]) ? uc_store_format_price_field_value($role_prices[$oid][$rid]) : '',
+            '#size' => 6,
+          );
+        }
+      }
+    }
+    else {
+      $form['attributes'][$aid]['default'] = array(
+        '#value' => t('This attribute does not have any options.'),
+      );
+    }
+  }
+
+  if (!empty($form['attributes'])) {
+    $form['attributes']['#tree'] = TRUE;
+
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Submit'),
+      '#weight' => 10,
+    );
+  }
+
+  $form['nid'] = array(
+    '#type' => 'value',
+    '#value' => $product->nid,
+  );
+
+  return $form;
+}
+
+/**
+ * Theme form to edit option prices.
+ */
+function theme_uc_price_per_role_option_prices_form($form) {
+  $roles = user_roles();
+  $enabled = array_keys(array_filter(variable_get('uc_price_per_role_enabled', array())));
+
+  $header = array(t('Attribute'), t('Option'), t('Standard price'));
+  foreach ($enabled as $rid) {
+    $header[] = t('%role price', array('%role' => $roles[$rid]));
+  }
+
+  foreach (element_children($form['attributes']) as $key) {
+    $row = array();
+    $row[] = array('data' => drupal_render($form['attributes'][$key]['aid']) . drupal_render($form['attributes'][$key]['name']), 'class' => 'attribute');
+
+    if (element_children($form['attributes'][$key]['options'])) {
+      foreach (element_children($form['attributes'][$key]['options']) as $oid) {
+        $row[] = drupal_render($form['attributes'][$key]['options'][$oid]['name']);
+        $row[] = drupal_render($form['attributes'][$key]['options'][$oid]['price']);
+        foreach ($enabled as $rid) {
+          $row[] = drupal_render($form['attributes'][$key]['options'][$oid]['role_prices'][$rid]);
+        }
+
+        $rows[] = $row;
+        $row = array('');
+      }
+      unset($form['attributes'][$key]['default']);
+    }
+    else {
+      $row[] = array('data' => drupal_render($form['attributes'][$key]['default']), 'colspan' => count($enabled) + 3);
+      $rows[] = $row;
+    }
+
+    $rows[] = array(array('data' => '<hr />', 'colspan' => count($enabled) + 3));
+  }
+
+  if (count($rows) == 0) {
+    $rows[] = array(
+      array('data' => t('This product does not have any attributes.'), 'colspan' => count($enabled) + 3),
+    );
+  }
+
+  $output = drupal_render($form['help'])
+          . theme('table', $header, $rows, array('class' => 'product_attributes'))
+          . drupal_render($form);
+
+  return $output;
+}
+
+/**
+ * Form submit handler to save option prices.
+ */
+function uc_price_per_role_option_prices_form_submit($form_id, &$form_state) {
+  foreach ($form_state['values']['attributes'] as $attribute) {
+    if (is_array($attribute['options'])) {
+      foreach ($attribute['options'] as $oid => $option) {
+        db_query("DELETE FROM {uc_price_per_role_option_prices} WHERE nid = %d AND oid = %d", $form_state['values']['nid'], $oid);
+
+        foreach ($option['role_prices'] as $rid => $price) {
+          if (is_numeric($price)) {
+            $data = array(
+              'nid' => $form_state['values']['nid'],
+              'oid' => $oid,
+              'rid' => $rid,
+              'price' => $price,
+            );
+            drupal_write_record('uc_price_per_role_option_prices', $data);
+          }
+        }
+      }
+    }
+  }
+
+  drupal_set_message(t('The option prices have been saved.'));
+}
+
+/**
+ * Load per-role option price data for the supplied node ID.
+ */
+function uc_price_per_role_load_option_prices($nid) {
+  $prices = array();
+  $result = db_query("SELECT oid, rid, price FROM {uc_price_per_role_option_prices} WHERE nid = %d", $nid);
+  while ($row = db_fetch_object($result)) {
+    $prices[$row->oid][$row->rid] = $row->price;
+  }
+  return $prices;
+}
+
+/**
+ * Find the price for the current user from the supplied price array.
+ * 
+ * Will return FALSE if no price was found.
+ */
+function uc_price_per_role_find_price($prices) {
+  global $user;
+
+  $enabled = variable_get('uc_price_per_role_enabled', array());
+  $weights = variable_get('uc_price_per_role_weights', array());
+  asort($weights);
+
+  // Check for a chosen role in the price selection block first.
+  if (user_access('access price selection block') && $_SESSION['price_role'] && isset($prices[$_SESSION['price_role']])) {
+    return $prices[$_SESSION['price_role']];
+  }
+
+  // Otherwise, look for a matching role.
+  foreach ($weights as $rid => $weight) {
+    if (isset($user->roles[$rid]) && $enabled[$rid] && isset($prices[$rid])) {
+      return $prices[$rid];
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+ * Implementation of hook_block().
+ */
+function uc_price_per_role_block($op = 'list', $delta = 0, $edit = array()) {
+  if ($op == 'list') {
+    $blocks[0]['info'] = t('Pricing selection');
+    return $blocks;
+  }
+  else if ($op == 'view' && $delta == 0 && user_access('access price selection block')) {
+    $block = array(
+      'subject' => t('Pricing selection'),
+      'content' => drupal_get_form('uc_price_per_role_switch_form'),
+    );
+    return $block;
+  }
+}
+
+/**
+ * Form to allow authorised users to select which role is used for pricing.
+ */
+function uc_price_per_role_switch_form() {
+  $enabled = variable_get('uc_price_per_role_enabled', array());
+  $weights = variable_get('uc_price_per_role_weights', array());
+  $roles = user_roles();
+  asort($weights);
+
+  $options = array('' => 'Default');
+  foreach ($weights as $rid => $weight) {
+    if ($enabled[$rid]) {
+      $options[$rid] = $roles[$rid];
+    }
+  }
+
+  $form['role'] = array(
+    '#type' => 'select',
+    '#title' => 'Role',
+    '#options' => $options,
+    '#default_value' => $_SESSION['price_role'],
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Select pricing role'),
+  );
+
+  return $form;
+}
+
+/**
+ * Form submit handler to save price role selection.
+ */
+function uc_price_per_role_switch_form_submit($form_id, &$form_state) {
+  if (user_access('access price selection block')) {
+    $_SESSION['price_role'] = $form_state['values']['role'];
+  }
+}
\ No newline at end of file

