diff --git CHANGELOG.txt CHANGELOG.txt
index f946ee6..8dac3d4 100644
--- CHANGELOG.txt
+++ CHANGELOG.txt
@@ -8,6 +8,9 @@ This release is brought to you by univate, who has done a ton of good work on th
 -- add optional feature to allow subsequent orders for a member to credit the commissions back to the previous affiliate.
 -- separate the code for applying the commissions from the hook_order() function
 -- split functionality from *.module to a *.user.inc and *.admin.inc files
+-- add CA support [trigger: commission_applied], [coditions: has_affiliate, check_commission, check_level], [actions: override_commission, commission_email]
+-- add token support for the affiliate email
+-- add 'level' field to the commission table
 
 Version 2.5rc1
 **************
diff --git uc_affiliate2.ca.inc uc_affiliate2.ca.inc
new file mode 100644
index 0000000..8390684
--- /dev/null
+++ uc_affiliate2.ca.inc
@@ -0,0 +1,367 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * This file contains the Conditional Actions hooks and functions necessary to make the
+ * affiliate-related entity, conditions, events, and actions work.
+ */
+
+/******************************************************************************
+ * Conditional Actions Hooks                                                  *
+ ******************************************************************************/
+
+/**
+ * Implementation of hook_ca_entity().
+ *
+ * An entity is defined in order to get the recurring fee down to token in the
+ * email.
+ */
+function uc_affiliate2_ca_entity() {
+  // CA entity for a affiliate commission.
+  $entities['uc_affiliate2_commission'] = array(
+    '#title' => t('Affiliate Commission'),
+    '#type' => 'object',
+  );
+
+  return $entities;
+}
+
+/**
+ * Implementation of hook_ca_predicate().
+ */
+function uc_affiliate2_ca_predicate() {
+  $predicates = array();
+
+  $predicates['uc_affiliate2_apply_commission'] = array(
+    '#title' => t('Send email to affiliate on new commission.'),
+    '#trigger' => 'uc_affiliate2_apply_commission',
+    '#class' => 'notification',
+    '#status' => 0,
+    '#weight' => 2,
+    '#conditions' => array(
+      '#operator' => 'AND',
+      '#conditions' => array(
+        array(
+          '#name' => 'uc_affiliate2_commission_amount',
+          '#title' => t('If the commission amount is greater then zero.'),
+          '#argument_map' => array(
+            'affiliate_commission' => 'affiliate_commission',
+          ),
+          '#settings' => array(
+            'affiliate_commission_value' => 0,
+            'affiliate_commission_comparision' => 'greater',
+          ),
+        ),
+      ),
+    ),
+    '#actions' => array(
+      array(
+        '#name' => 'uc_affiliate2_send_email',
+        '#title' => t('Send affiliate commission email.'),
+        '#argument_map' => array(
+          'order' => 'order',
+          'affiliate_commission' => 'affiliate_commission',
+        ),
+        '#settings' => array(
+          'from' => uc_store_email_from(),
+          'addresses' => '[affiliate-email]',
+          'subject' => uc_get_message('uc_affiliate2_commission_subject'),
+          'message' => uc_get_message('uc_affiliate2_commission_message'),
+          'format' => 1,
+        ),
+      )
+    ),
+  );
+
+  return $predicates;
+}
+
+/**
+ * Implementation of hook_ca_condition().
+ */
+function uc_affiliate2_ca_condition() {
+  $conditions['uc_affiliate2_has_affiliate'] = array(
+    '#title' => t('User has affiliate'),
+    '#description' => t('Check if the user making the purchase has an affiliate.'),
+    '#category' => t('Order: Affiliate2'),
+    '#callback' => 'uc_affiliate2_condition_has_affiliate',
+    '#arguments' => array(
+      'order' => array('#entity' => 'uc_order', '#title' => t('Order')),
+    ),
+  );
+  $conditions['uc_affiliate2_commission_amount'] = array(
+    '#title' => t('Check commission amount'),
+    '#description' => t('Check if the commission amount is within the parameters below.'),
+    '#category' => t('Order: Affiliate2'),
+    '#callback' => 'uc_affiliate2_condition_commission_amount',
+    '#arguments' => array(
+      'affiliate_commission' => array('#entity' => 'uc_affiliate2_commission', '#title' => t('Affiliate Commission')),
+    ),
+  );
+
+  $conditions['uc_affiliate2_affiliate_level'] = array(
+    '#title' => t('Check affiliate level'),
+    '#description' => t('Returns TRUE if the current affiliate level is within the parameters below.'),
+    '#category' => t('Order: Affiliate2'),
+    '#callback' => 'uc_affiliate2_condition_affiliate_level',
+    '#arguments' => array(
+      'affiliate_commission' => array('#entity' => 'uc_affiliate2_commission', '#title' => t('Affiliate Commission')),
+    ),
+  );
+
+  return $conditions;
+}
+
+/**
+ * Implementation of hook_ca_action().
+ */
+function uc_affiliate2_ca_action() {
+  // Send an email to an order with a role expiration
+  $actions['uc_affiliate2_set_commission'] = array(
+    '#title' => t('Override the commission percentage.'),
+    '#category' => t('Affiliate'),
+    '#callback' => 'uc_affiliate2_set_commission',
+    '#arguments' => array(
+      'order' => array(
+        '#entity' => 'uc_order',
+        '#title' => t('Order'),
+      ),
+      'affiliate_commission' => array(
+        '#entity' => 'uc_affiliate2_commission',
+        '#title' => t('Affiliate Commission'),
+      ),
+    ),
+  );
+  $actions['uc_affiliate2_send_email'] = array(
+    '#title' => t('Send an affiliate email.'),
+    '#category' => t('Notification'),
+    '#callback' => 'uc_affiliate2_action_commission_email',
+    '#arguments' => array(
+      'order' => array(
+        '#entity' => 'uc_order',
+        '#title' => t('Order'),
+      ),
+      'affiliate_commission' => array(
+        '#entity' => 'uc_affiliate2_commission',
+        '#title' => t('Affiliate Commission'),
+      ),
+    ),
+  );
+
+
+  return $actions;
+}
+
+/**
+ * Implementation of hook_ca_trigger().
+ */
+function uc_affiliate2_ca_trigger() {
+  $order = array(
+    '#entity' => 'uc_order',
+    '#title' => t('Order'),
+  );
+  $affiliate_commission = array(
+    '#entity' => 'uc_affiliate2_commission',
+    '#title' => t('Affiliate commission'),
+  );
+
+  $triggers['uc_affiliate2_apply_commission'] = array(
+    '#title' => t('Affiliate commission being applied'),
+    '#category' => t('Affiliate2'),
+    '#arguments' => array(
+      'order' => $order,
+      'affiliate_commission' => $affiliate_commission,
+    ),
+  );
+  return $triggers;
+}
+
+/**
+ * Check if the order contains a renewal product.
+ *
+ * @param $order
+ *   The order object.
+ * @param $recurring_fee
+ *   The recurring fee object.
+ * @param $settings
+ *   The order settings.
+ */
+function uc_affiliate2_condition_has_affiliate($order, $settings) {
+  // check session variable and the database for affiliate for the user making
+  // the purchase.
+  if ($_SESSION['affiliate'] > 0) {
+    return TRUE;
+  }
+  if (_uc_affiliate2_get_user($uid) > 0) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Check the affiliate level.
+ *
+ * @see uc_affiliate2_condition_affiliate_level_form()
+ */
+function uc_affiliate2_condition_affiliate_level($affiliate_commision, $settings) {
+  switch ($settings['affiliate_level_comparison']) {
+    case 'less':
+      return $affiliate_commission->level < $settings['affiliate_level_value'];
+    case 'less_equal':
+      return $affiliate_commission->level <= $settings['affiliate_level_value'];
+    case 'equal':
+      return $affiliate_commission->level == $settings['affiliate_level_value'];
+    case 'greater_equal':
+      return $affiliate_commission->level >= $settings['affiliate_level_value'];
+    case 'greater':
+      return $affiliate_commission->level > $settings['affiliate_level_value'];
+  }
+}
+
+/**
+ * @see uc_affiliate2_condition_affiliate_level()
+ */
+function uc_affiliate2_condition_affiliate_level_form($form_state, $settings = array()) {
+  $form['affiliate_level_value'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Affiliate level value'),
+    '#description' => t('Specify a value to compare the affiliate level against.'),
+    '#default_value' => $settings['affiliate_level_value'],
+    '#size' => 16,
+  );
+
+  $options = array(
+    'less' => t('Total is less than specified value.'),
+    'less_equal' => t('Total is less than or equal to specified value.'),
+    'equal' => t('Total is equal to specified value.'),
+    'greater_equal' => t('Total is greater than or equal to specified value.'),
+    'greater' => t('Total is greater than specified value.'),
+  );
+  $form['affiliate_level_comparison'] = array(
+    '#type' => 'radios',
+    '#title' => t('Affiliate level comparison type'),
+    '#options' => $options,
+    '#default_value' => isset($settings['affiliate_level_comparison']) ? $settings['affiliate_level_comparison'] : 'less_equal',
+  );
+
+  return $form;
+}
+
+/**
+ * Check the affiliate commission amount.
+ *
+ * @see uc_affiliate2_condition_commission_amount_form()
+ */
+function uc_affiliate2_condition_commission_amount($affiliate_commision, $settings) {
+  switch ($settings['affiliate_commission_comparison']) {
+    case 'less':
+      return $affiliate_commission->commission < $settings['affiliate_commission_value'];
+    case 'less_equal':
+      return $affiliate_commission->commission <= $settings['affiliate_commission_value'];
+    case 'equal':
+      return $affiliate_commission->commission == $settings['affiliate_commission_value'];
+    case 'greater_equal':
+      return $affiliate_commission->commission >= $settings['affiliate_commission_value'];
+    case 'greater':
+      return $affiliate_commission->commission > $settings['affiliate_commission_value'];
+  }
+}
+
+/**
+ * @see uc_affiliate2_condition_commission_amount_form()
+ */
+function uc_affiliate2_condition_commission_amount_form($form_state, $settings = array()) {
+  $form['affiliate_commission_value'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Affiliate commission value'),
+    '#description' => t('Specify a value to compare the affiliate commission amount against.'),
+    '#default_value' => $settings['affiliate_commission_value'],
+    '#size' => 16,
+  );
+
+  $options = array(
+    'less' => t('Total is less than specified value.'),
+    'less_equal' => t('Total is less than or equal to specified value.'),
+    'equal' => t('Total is equal to specified value.'),
+    'greater_equal' => t('Total is greater than or equal to specified value.'),
+    'greater' => t('Total is greater than specified value.'),
+  );
+  $form['affiliate_commission_comparison'] = array(
+    '#type' => 'radios',
+    '#title' => t('Affiliate commission comparison type'),
+    '#options' => $options,
+    '#default_value' => isset($settings['affiliate_commission_comparison']) ? $settings['affiliate_commission_comparison'] : 'greater',
+  );
+
+  return $form;
+}
+/**
+ *
+ * @see uc_affiliate2_set_commission_form()
+ */
+function uc_affiliate2_set_commission($order, &$affiliate_commission, $settings) {
+  $affiliate_commission->commission = $affiliate_commission->data['total'] * $settings['affiliate_commission_pct'] / 100;
+}
+
+/**
+ *
+ * @see uc_affiliate2_set_commission()
+ */
+function uc_affiliate2_set_commission_form($form_state, $settings = array()) {
+  $form['affiliate_commission_pct'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Affiliate Commission Percent'),
+    '#description' => t('Enter a value to override the default commission percentage.'),
+    '#default_value' => $settings['affiliate_commission_pct']
+  );
+
+  return $form;
+}
+
+/**
+ * Send an email with order and affiliate commission replacement tokens.
+ *
+ * The recipients, subject, and message fields take order token replacements.
+ *
+ * @see uc_affiliate2_action_commission_email_form()
+ */
+function uc_affiliate2_action_commission_email($order, $affiliate_commission, $settings) {
+  $account = uc_order_user_load($order);
+
+  // Token replacements for the subject and body
+  $settings['replacements'] = array(
+    'global' => NULL,
+    'order' => $order,
+    'user' => $account,
+    'affiliate' => $affiliate_commission,
+  );
+
+  // Replace tokens and parse recipients.
+  $recipients = array();
+  $addresses = token_replace_multiple($settings['addresses'], $settings['replacements']);
+  foreach (explode("\n", $addresses) as $address) {
+    $recipients[] = trim($address);
+  }
+
+  // Send to each recipient.
+  foreach ($recipients as $email) {
+    $sent = drupal_mail('uc_affiliate2', 'action-mail', $email, uc_store_mail_recipient_language($email), $settings, $settings['from']);
+
+    if (!$sent['result']) {
+      watchdog('ca', 'Attempt to e-mail @email concerning order @order_id failed.', array('@email' => $email, '@order_id' => $order->order_id), WATCHDOG_ERROR);
+    }
+  }
+}
+
+/**
+ * Email settings form.
+ *
+ * @see uc_affiliate2_action_commission_email()
+ */
+function uc_affiliate2_action_commission_email_form($form_state, $settings = array()) {
+  // ca_build_email_form() function seems to be incorrectly part of uc_roles so
+  // we add this hack to include the uc_roles.ca.inc here.
+  module_load_include('inc', 'uc_roles', 'uc_roles.ca');
+  return ca_build_email_form($form_state, $settings, array('global', 'order', 'user', 'affiliate'));
+}
diff --git uc_affiliate2.install uc_affiliate2.install
index faca204..e4f505f 100644
--- uc_affiliate2.install
+++ uc_affiliate2.install
@@ -111,6 +111,12 @@ function uc_affiliate2_schema() {
         'size' => 'big',
         'not null' => FALSE,
       ),
+      'level' => array(
+        'description' => t('Commission Level'),
+        'type' => 'int',
+        'not null' => FALSE,
+        'default' => 0,
+      ),
       'commission_notes' => array(
         'type' => 'varchar',
         'length' => 255,
@@ -200,3 +206,13 @@ function uc_affiliate2_update_3() {
 
   return $items;
 }
+
+/**
+ * Add level field to commission table.
+ */
+function uc_affiliate2_update_6000() {
+  $ret = array();
+  db_add_field($ret, 'uc_affiliate2_commission', 'level', array('description' => t('Commission Level'), 'type' => 'int', 'not null' => FALSE, 'default' => 0));
+  return $ret;
+  return $ret;
+}
diff --git uc_affiliate2.module uc_affiliate2.module
index 2bd26e1..b2eaebb 100644
--- uc_affiliate2.module
+++ uc_affiliate2.module
@@ -259,6 +259,8 @@ function _uc_affiliate2_user_access($account, $mode = '') {
  * This function sets $_SESSION['affiliate'] and increments click count
  */
 function uc_affiliate2_init() {
+  module_load_include('inc', 'uc_affiliate2', 'uc_affiliate2.ca');
+
   uc_affiliate2_click();
 }
 
@@ -589,6 +591,9 @@ function uc_affiliate2_apply_commission($order, $affiliate_id = NULL) {
     }
     $affcom[$aff]['total'] = isset($affcom[$aff]['total']) ? $affcom[$aff]['total'] + $price : $price;
     $affcom[$aff]['nid'] = $product->nid;
+    $affcom[$aff]['products'][$product->nid]['price'] = $product->price;
+    $affcom[$aff]['products'][$product->nid]['qty'] = $product->qty;
+    $affcom[$aff]['products'][$product->nid]['total'] = $price;
   }
 
   // node ids of each product. If there is only one product, we can use per product commissions
@@ -600,14 +605,25 @@ function uc_affiliate2_apply_commission($order, $affiliate_id = NULL) {
 
     for ($level=1; $level<=count($affs); $level++) {
       $aff = $affs[$level-1];
-      $comm_pct = _uc_affiliate2_get_commission_percentage($level, $data['nid'], $nids);
-      if ($comm_pct > 0) {
-        $comm = new stdClass();
-        $comm->order_id = $order->order_id;
-        $comm->aid = $aff;
-        //TODO should this be rounded to nearest penny???
-        $comm->commission = $data['total'] * $comm_pct;
-        $comm->commission_notes = t('Level @level commission recorded for affiliate uid:@affiliate', array('@affiliate' => $aff, '@percent' => $comm_pct*100, '@level' => $level, '@commission' => uc_currency_format($comm), '@ordertotal' => uc_currency_format($total), '@firstname' => $order->billing_first_name, '@lastname' => $order->billing_last_name));
+
+      // calculate the commission for this affiliate/level
+      $commission = 0;
+      foreach($data['products'] as $pid => $product_data) {
+        $comm_pct = _uc_affiliate2_get_commission_percentage($aff, $level, $pid);
+        $commission += $comm_pct * $product_data['total'];
+      }
+      $comm = new stdClass();
+      $comm->order_id = $order->order_id;
+      $comm->aid = $aff;
+      $comm->commission = $commission; //TODO should this be rounded?
+      $comm->level = $level;
+      $comm->commission_notes = t('Level @level commission recorded for affiliate uid:@affiliate', array('@affiliate' => $aff, '@percent' => $comm_pct*100, '@level' => $level, '@commission' => uc_currency_format($comm), '@ordertotal' => uc_currency_format($total), '@firstname' => $order->billing_first_name, '@lastname' => $order->billing_last_name));
+
+      // data field is not saved, but used in CA
+      $comm->data = $data;
+
+      ca_pull_trigger('uc_affiliate2_apply_commission', $order, $comm);
+      if ($comm->commission > 0) {
         uc_affiliate2_save_commission($comm);
       }
     }
@@ -952,6 +968,87 @@ function uc_affiliate2_click($username = 0) {
   }
 }
 
+/**
+ * Implementation of hook_token_values(). (token.module)
+ */
+function uc_affiliate2_token_values($type, $object = NULL) {
+  $values = array();
+
+  $context = array(
+    'revision' => 'altered',
+    'type' => 'order_product',
+    'subject' => array('order' => $order),
+  );
+
+  switch ($type) {
+    case 'order':
+      $order = $object;
+
+      $values['order-affiliate-commission'] = uc_price(0, $context);
+      $values['order-affiliate-uid'] = '';
+      $values['order-affiliate-name'] = t('No affiliate');
+      $values['order-affiliate-email'] = '';
+
+      $result = db_query('SELECT u.uid, u.name, u.mail, ac.commission
+            FROM {uc_affiliate2_commission} ac
+              INNER JOIN {users} u on ac.aid = u.uid
+              INNER JOIN {uc_affiliate2_users} au on au.aid = ac.aid
+            WHERE ac.order_id = %d AND au.uid = %d', $order->order_id, $order->uid);
+
+      $affiliate = db_fetch_object($result);
+      if (!empty($affiliate)) {
+        $values['order-affiliate-commission'] = uc_price($affiliate->commission, $context);
+        $values['order-affiliate-uid'] = $affiliate->uid;
+        $values['order-affiliate-name'] = $affiliate->name;
+        $values['order-affiliate-email'] = $affiliate->mail;
+      }
+      break;
+    case 'affiliate':
+      $user = user_load($affiliate->aid);
+      $values['affiliate-uid'] = $user->uid;
+      $values['affiliate-name'] = $user->name;
+      $values['affiliate-email'] = $user->mail;
+      $values['affiliate-commission'] = uc_price($affiliate->commission, $context);
+      $values['affiliate-level'] = $affiliate->level;
+      $tokens['affiliate-commissions-url'] = url('user/'.$user->uid.'/affiliate/commissions', array('absolute' => TRUE));
+      break;
+  }
+
+  return $values;
+}
+
+/**
+ * Implementation of hook_token_list(). (token.module)
+ */
+function uc_affiliate2_token_list($type = 'all') {
+  $tokens = array();
+  if ($type == 'order' || $type == 'ubercart' || $type == 'all') {
+    $tokens['order']['order-affiliate-commission'] = t('The affiliate commission amount.');
+    $tokens['order']['order-affiliate-uid'] = t('The referring affiliate user ID.');
+    $tokens['order']['order-affiliate-name'] = t('The referring affiliate name.');
+    $tokens['order']['order-affiliate-email'] = t('The referring affiliate email.');
+  }
+  if ($type == 'affiliate' || $type == 'ubercart' || $type == 'all') {
+    $tokens['affiliate']['affiliate-uid'] = t('Affiliate user ID.');
+    $tokens['affiliate']['affiliate-name'] = t('Affiliate username');
+    $tokens['affiliate']['affiliate-email'] = t('Affiliate email');
+    $tokens['affiliate']['affiliate-commission'] = t('Affiliate commission amount.');
+    $tokens['affiliate']['affiliate-level'] = t('Affiliate level.');
+    $tokens['affiliate']['affiliate-commissions-url'] = t('Link to the affiliate commissions.');
+  }
+  return $tokens;
+}
+
+/**
+ * Implementation of hook_uc_message().
+ */
+function uc_affiliate2_uc_message() {
+  $messages['uc_affiliate2_commission_subject'] = t('[store-name]: Affiliate Commission received');
+  $messages['uc_affiliate2_commission_message'] = t("Hi [affiliate-name], \n\nCongratulations, an affiliate commission has be credited to your account.\n\nYou can see full details from your affiliate center: [affiliate-commissions-url].\n\nThanks again, \n\n[store-name]\n[site-slogan]");
+
+  return $messages;
+}
+
 // Form to associate attributes with products or classes.
 function uc_affiliate2_product_commission($node) {
   $output = "'Product Commission Structure' is only used when the product is alone in the cart. <br />
@@ -1075,14 +1172,25 @@ function _uc_affiliate2_get_user($uid) {
 
 /**
  * Get an affiliates commission percentage for the given level
+ *
+ * @param $aff_id
+     ID of the affiliate.
+ * @param $level
+ *   The affiliate commission being obtained.
+ * @param $nid
+ *   The node ID of the product being purchased.
+ *
+ * @return
+ *   Commission percentate as a value between 0 and 1.
  */
-function _uc_affiliate2_get_commission_percentage($level = 1, $nid = 0, $nids) {
+function _uc_affiliate2_get_commission_percentage($aff_id, $level = 1, $nid = 0) {
   global $user;
 
-  $account = user_load(array('uid' => $_SESSION['affiliate']));
-
-  if ($account->commission) {
-    return $account->commission / 100; // we have a commission percentage defined specially for this affilate
+  if ($level == 1) {
+    $account = user_load(array('uid' => $aff_id));
+    if (is_numeric($account->commission)) {
+      return $account->commission / 100; // we have a commission percentage defined specially for this affilate
+    }
   }
 
   $depth = variable_get('affiliate_hierarchy_depth', 5);
@@ -1092,7 +1200,7 @@ function _uc_affiliate2_get_commission_percentage($level = 1, $nid = 0, $nids) {
   $product_commission_structure = unserialize($result->commission_structure);
 
   // if the commission is defined, and this product is alone in the cart
-  if ($product_commission_structure && (count($nids) === 1)) {
+  if ($product_commission_structure) {
     $default_structure = $product_commission_structure;
   }
   else {
