From 3316c4601323a5bd363e69a6cdc5b8932854ea0c Mon Sep 17 00:00:00 2001
From: Chris Hood <chris@univate.com.au>
Date: Sat, 22 Sep 2012 20:04:20 +1000
Subject: [PATCH] Rules integration

---
 .../uc_recurring_subscription.rules.inc            |  230 +++++++++++++++++++-
 .../uc_recurring_subscription.rules_defaults.inc   |  112 +++++++++-
 uc_recurring.rules.inc                             |  111 +++++++++-
 uc_recurring.rules_defaults.inc                    |   66 ++++++
 4 files changed, 512 insertions(+), 7 deletions(-)

diff --git a/modules/uc_recurring_subscription/uc_recurring_subscription.rules.inc b/modules/uc_recurring_subscription/uc_recurring_subscription.rules.inc
index 9b403c5..ecc11cc 100644
--- a/modules/uc_recurring_subscription/uc_recurring_subscription.rules.inc
+++ b/modules/uc_recurring_subscription/uc_recurring_subscription.rules.inc
@@ -8,7 +8,7 @@
 
 
 /**
- * Implement hook_rules_data_info().
+ * Implements hook_rules_data_info().
  */
 function uc_recurring_subscription_rules_data_info() {
   $types['uc_recurring_subscription'] = array(
@@ -23,7 +23,8 @@ function uc_recurring_subscription_rules_data_info() {
 /**
  * Implement hook_rules_event_info().
  */
-function uc_recurring_subscription_event_info() {
+//function uc_recurring_subscription_event_info() {
+function uc_recurring_subscription_rules_event_info() {
   $events = array();
   return $events;
 }
@@ -31,15 +32,236 @@ function uc_recurring_subscription_event_info() {
 /**
  * Implement hook_rules_condition_info().
  */
-function uc_recurring_subscription_condition_info() { 
+//function uc_recurring_subscription_condition_info() { 
+function uc_recurring_subscription_rules_condition_info() { 
   $conditions = array();
   return $conditions;
 }
 
 /**
  * Implement hook_rules_action_info().
- */
+ *
 function uc_recurring_subscription_action_info() {
   $actions = array();
   return $actions;
+}/**/
+function uc_recurring_subscription_rules_action_info() {
+  // actions to grant/revoke role on user account.
+  $actions['uc_recurring_subscription_grant_role'] = array(
+    'label' => t('Grant a role on an order.'),
+    'group' => t('Role'),
+    'parameter' => array(
+      'order' => array(
+        'type' => 'uc_order',
+        'label' => t('Order'),
+      ),
+      'role_option' => array(
+        'type' => 'text',
+        'label' => t('Where are the role(s) defined?'),
+        'options list' => '_uc_recurring_subscription_role_options',
+      ),
+      'roles' => array(
+        'type' => 'list<integer>',
+        'label' => t('Role'),
+        'options list' => '_uc_recurring_subscription_user_roles',
+        'optional' => TRUE,
+      ),
+    ),
+  );
+  $actions['uc_recurring_subscription_revoke_role'] = array(
+    'label' => t('Revoke a role on an order.'),
+    'group' => t('Role'),
+    'parameter' => array(
+      'order' => array(
+        'type' => 'uc_order',
+        'label' => t('Order'),
+      ),
+      'role_option' => array(
+        'type' => 'text',
+        'label' => t('Where are the role(s) defined?'),
+        'options list' => '_uc_recurring_subscription_role_options',
+      ),
+      'role_option' => array(
+        'type' => 'text',
+        'label' => t('Where are the role(s) defined?'),
+        'options list' => '_uc_recurring_subscription_role_options',
+      ),
+      'roles' => array(
+        'type' => 'list<integer>',
+        'label' => t('Role'),
+        'options list' => '_uc_recurring_subscription_user_roles',
+        'optional' => TRUE,
+      ),
+    ),
+  );
+
+  if (module_exists('og')) {
+    // actions to subscribe/unsubscribe user from organic group.
+    $actions['uc_recurring_subscription_grant_og'] = array(
+      'label' => t('Grant organic group membership on order.'),
+      'group' => t('Organic Group'),
+      'parameter' => array(
+        'order' => array(
+          'type' => 'uc_order',
+          'label' => t('Order'),
+        ),
+        'group_option' => array(
+          'type' => 'text',
+          'label' => t('Where are the role(s) defined?'),
+          'options list' => '_uc_recurring_subscription_role_options',
+        ),
+        'group' => array(
+          'type' => 'group',
+          'label' => t('Group'),
+        ),
+      ),
+    );
+    $actions['uc_recurring_subscription_revoke_og'] = array(
+      'label' => t('Revoke organic group membership on order.'),
+      'group' => t('Organic Group'),
+      'parameter' => array(
+        'order' => array(
+          'type' => 'uc_order',
+          'label' => t('Order'),
+        ),
+        'group_option' => array(
+          'type' => 'text',
+          'label' => t('Where are the role(s) defined?'),
+          'options list' => '_uc_recurring_subscription_role_options',
+        ),
+        'group' => array(
+          'type' => 'group',
+          'label' => t('Group'),
+        ),
+      ),
+    );
+  }
+   return $actions;
+}
+
+function _uc_recurring_subscription_role_options() {
+  return array(
+    'subscribe_grant' => t('Apply the roles set by the Subscription Manager on creation.'),
+    'expire_grant' => t('Apply the roles set by the Subscription Manager on expiration.'),
+    'expire_revoke' => t('Revoke the roles set by the Subscription Manager on expiration.'),
+    'custom' => t('Custom selected role (select from below)'),
+  );
+}
+
+function _uc_recurring_subscription_group_options() {
+  return array(
+    'subscribe_grant_og' => t('Apply the groups set by the Subscription Manager on creation.'),
+    'expire_grant_og' => t('Apply the groups set by the Subscription Manager on expiration.'),
+    'expire_revoke_og' => t('Revoke the groups set by the Subscription Manager on expiration.'),
+    'custom' => t('Custom selected groups (select from below)'),
+  );
+}
+
+function _uc_recurring_subscription_user_roles() {
+  $roles = user_roles(TRUE);
+  unset($roles[DRUPAL_AUTHENTICATED_RID]);
+  return $roles;
+}
+
+
+/**
+ * Grant a role.
+ */
+function uc_recurring_subscription_grant_role($order, $role_option, $roles) {
+  $account = user_load($order->uid);
+
+  $role_names = user_roles(TRUE);
+  if ($role_option == 'custom') {
+    foreach ($roles as $rid => $role) {
+      $account->roles[$rid] = $role_names[$rid];
+      watchdog('uc_recurring', 'Granted !role role to !user', array('!role' => $role_names[$rid], '!user' => $account->name));
+    }
+  }
+  else {
+    foreach ($order->products as $pid => $product) {
+      $subscription = uc_recurring_subscription_load($product->nid);
+      if (!empty($subscription->access[$role_option])) {
+        $account->roles += $subscription->access[$role_option];
+      }
+    }
+  }
+  user_save($account, array('roles' => $account->roles));
+}
+
+/**
+ * Revoke user role(s).
+ */
+function uc_recurring_subscription_revoke_role($order, $role_option, $roles) {
+  $account = user_load($order->uid);
+
+  $role_names = user_roles(TRUE);
+  if ($role_option == 'custom') {
+    foreach ($roles as $rid => $role) {
+      unset($account->roles[$rid]);
+      watchdog('uc_recurring', 'Revoked !role role from !user', array('!role' => $role_names[$rid], '!user' => $account->name));
+    }
+  }
+  else {
+    foreach ($order->products as $pid => $product) {
+      $subscription = uc_recurring_subscription_load($product->nid);
+      if (!empty($subscription->access[$role_option])) {
+        foreach ($subscription->access[$role_option] as $rid => $role) {
+          // @todo: we need to check other subscriptions to ensure that the role
+          // is no longer required by another subscription.
+          unset($account->roles[$rid]);
+        }
+      }
+    }
+  }
+  user_save($account, array('roles' => $account->roles));
+
+  $account = user_load($order->uid);
+}
+
+/**
+ * Grant user organic groups.
+ */
+function uc_recurring_subscription_grant_og($order, $group_option, $group) {
+  // Load user.
+  if (!$order->uid || !($account = user_load($order->uid))) {
+    return;
+  }
+  if ($group_option == 'custom' && is_array($group) && !empty($group)) {
+    og_subscribe_user_action($account, $group);
+  }
+  else {
+    foreach ($order->products as $pid => $product) {
+      $subscription = uc_recurring_subscription_load($product->nid);
+      $context['groups'] = $subscription->access[$group_option];
+      if (is_array($context['groups']) && !empty($context['groups'])) {
+        og_subscribe_user_action($account, $context);
+        $comment = t('User access granted to group(s): %group.', array('%group' => implode(',', $context['groups'])));
+        uc_order_comment_save($order->order_id, $account->uid, $comment);
+      }
+    }
+  }
+}
+
+/**
+ * Revoke user organic groups.
+ */
+function uc_recurring_subscription_revoke_og($order, $group_option, $group) {
+  // Load user.
+  if (!$order->uid || !($account = user_load($order->uid))) {
+    return;
+  }
+  if ($group_option == 'custom' && is_array($group) && !empty($group)) {
+    og_unsubscribe_user_action($account, $group);
+  }
+  else {
+    foreach ($order->products as $pid => $product) {
+      $subscription = uc_recurring_subscription_load($product->nid);
+      $context['groups'] = $subscription->access[$group_option];
+      if (is_array($context['groups']) && !empty($context['groups'])) {
+        og_unsubscribe_user_action($account, $context);
+        $comment = t('User access revoked for group(s): %group.', array('%group' => implode(',', $context['groups'])));
+        uc_order_comment_save($order->order_id, $account->uid, $comment);
+      }
+    }
+  }
 }
\ No newline at end of file
diff --git a/modules/uc_recurring_subscription/uc_recurring_subscription.rules_defaults.inc b/modules/uc_recurring_subscription/uc_recurring_subscription.rules_defaults.inc
index 3374689..ea85dea 100644
--- a/modules/uc_recurring_subscription/uc_recurring_subscription.rules_defaults.inc
+++ b/modules/uc_recurring_subscription/uc_recurring_subscription.rules_defaults.inc
@@ -6,5 +6,113 @@
  */
 
 /**
- * Implement hook_default_rules_configuration().
- */
\ No newline at end of file
+ * * Implements hook_default_rules_configuration().
+ */
+function uc_recurring_subscription_default_rules_configuration() {
+  $configs = array();
+
+  // Grant user roles to user when checkout is complete.
+  $rule = rules_reaction_rule();
+  $rule->label = t('Grant user roles on subscription created.');
+  $rule->active = TRUE;
+  $rule->weight = 1;
+  $rule->event('uc_order_status_update')
+    // This is the entity way of doing things
+    //->condition('data_is', array('data:select' => 'order:order-status', 'value' => 'completed'))
+    // This is the traditional way of doing things
+    ->condition('uc_order_condition_order_state', array('order:select' => 'order', 'order_state' => 'completed'))
+    ->action('uc_recurring_subscription_grant_role', array(
+      'order:select' => 'order',
+      'role_option' => 'subscribe_grant',
+      'roles' => array(),
+    ));
+  $configs['uc_recurring_subscription_grant_roles'] = $rule;
+
+  // Grant user roles to user when subscription expires.
+  $rule = rules_reaction_rule();
+  $rule->label = t('Grant user roles on subscription created.');
+  $rule->active = TRUE;
+  $rule->weight = 1;
+  $rule->event('uc_recurring_renewal_expired')
+    ->action('uc_recurring_subscription_grant_role', array(
+      'order:select' => 'order',
+      'role_option' => 'expire_grant',
+      'roles' => array(),
+    ));
+  $configs['uc_recurring_subscription_expired_grant_roles'] = $rule;
+
+  // Revoke user roles to user when subscription expires.
+  $rule = rules_reaction_rule();
+  $rule->label = t('Revoke user roles on subscription expired.');
+  $rule->active = TRUE;
+  $rule->weight = 1;
+  $rule->event('uc_recurring_renewal_expired')
+    ->action('uc_recurring_subscription_revoke_role', array(
+      'order:select' => 'order',
+      'role_option' => 'expire_revoke',
+      'roles' => array(),
+    ));
+  $configs['uc_recurring_subscription_expired_revoke_roles'] = $rule;
+  
+  // Revoke user roles to user when subscription is cancelled
+  $rule = rules_reaction_rule();
+  $rule->label = t('Revoke user roles on subscription cancelled. --xomby');
+  $rule->active = TRUE;
+  $rule->weight = 1;
+  $rule->event('uc_recurring_cancel')
+    // This is the entity way of doing things
+    //->condition('data_is', array('data:select' => 'order:order-status', 'value' => 'completed'))
+    // This is the traditional way of doing things
+    //->condition('uc_order_condition_order_state', array('order:select' => 'order', 'order_state' => 'cancelled'))
+    ->action('uc_recurring_subscription_revoke_role', array(
+      'order:select' => 'order',
+      'role_option' => 'expire_revoke',
+      'roles' => array(),
+    ));
+  $configs['uc_recurring_subscription_cancelled_revoke_roles'] = $rule;
+  if (module_exists('og')) {
+    // Grant organic groups to user when checkout is complete.
+    $rule = rules_reaction_rule();
+    $rule->label = t('Grant organic groups on subscription created.');
+    $rule->active = TRUE;
+    $rule->weight = 1;
+    $rule->event('uc_order_status_update')
+      // This is the entity way of doing things
+      //->condition('data_is', array('data:select' => 'updated-order:order-status', 'value' => 'completed'))
+      // This is the traditional way of doing things
+      ->condition('uc_order_condition_order_state', array('order:select' => 'updated-order', 'order_state' => 'completed'))
+      ->action('uc_recurring_subscription_grant_og', array(
+        'order:select' => 'order',
+        'group_option' => 'subscribe_grant_og',
+        'group' => NULL,
+      ));
+    $configs['uc_recurring_subscription_grant_og'] = $rule;
+
+    // Grant organic groups to user when subscription expires.
+    $rule = rules_reaction_rule();
+    $rule->label = t('Grant organic groups on subscription created.');
+    $rule->active = TRUE;
+    $rule->weight = 1;
+    $rule->event('uc_recurring_renewal_expired')
+      ->action('uc_recurring_subscription_grant_og', array(
+        'order:select' => 'order',
+        'group_option' => 'expire_grant_og', // @@@ Was '' in CA -- this rule was broken in 6?
+        'group' => NULL,
+      ));
+    $configs['uc_recurring_subscription_expired_grant_og'] = $rule;
+
+    // Revoke organic groups to user when subscription expires.
+    $rule = rules_reaction_rule();
+    $rule->label = t('Revoke organic groups on subscription expiration.');
+    $rule->active = TRUE;
+    $rule->weight = 1;
+    $rule->event('uc_recurring_renewal_expired')
+      ->action('uc_recurring_subscription_revoke_og', array(
+        'order:select' => 'order',
+        'role_option' => 'expire_revoke_og',
+        'role' => NULL,
+      ));
+    $configs['uc_recurring_subscription_expired_revoke_og'] = $rule;
+  }
+  return $configs;
+}
\ No newline at end of file
diff --git a/uc_recurring.rules.inc b/uc_recurring.rules.inc
index f9f78a6..9222997 100644
--- a/uc_recurring.rules.inc
+++ b/uc_recurring.rules.inc
@@ -18,7 +18,57 @@ function uc_recurring_rules_data_info() {
 }
 
 /**
- * Implement hook_rules_event_info().
+ * Implements hook_rules_action_info().
+ */
+function uc_recurring_rules_action_info() {
+  // Adapted from uc_roles.rules.inc.
+  $email_args = array(
+    'from' => array(
+      'type' => 'text',
+      'label' => t('Sender'),
+    ),
+    'addresses' => array(
+      'type' => 'text',
+      'label' => t('Recipients'),
+    ),
+    'subject' => array(
+      'type' => 'text',
+      'label' => t('Subject'),
+    ),
+    'message' => array(
+      'type' => 'text',
+      'label' => t('Message'),
+    ),
+    'format' => array(
+      'type' => 'text',
+      'label' => t('Message format'),
+      'options list' => 'uc_recurring_message_formats',
+    ),
+  );
+
+  // Send an email to an order with a role expiration
+  $actions['uc_recurring_renewal_email'] = array(
+    'label' => t('Send an order email regarding order renewal.'),
+    'group' => t('Recurring Fee'),
+    'parameter' => array(
+      'order' => array(
+        'type' => 'uc_order',
+        'label' => t('Order'),
+      ),
+      'recurring_fee' => array(
+        'type' => 'uc_recurring_fee',
+        'label' => t('Recurring Fee'),
+        'restriction' => 'selector',
+      ),
+    ) + $email_args,
+  );
+
+  return $actions;
+}
+
+
+/**
+ * Implements hook_rules_event_info().
  */
 function uc_recurring_rules_event_info() {
   $events['uc_recurring_renewal_complete'] = array(
@@ -116,6 +166,23 @@ function uc_recurring_rules_condition_info() {
   return $conditions;
 }
 
+ /**
+ * Options list callback for message formats.
+ */
+function uc_recurring_message_formats() {
+  // Copied from uc_roles.rules.inc.
+  global $user;
+
+  $options = array();
+  $formats = filter_formats($user);
+  foreach ($formats as $format) {
+    $options[$format->format] = $format->name;
+  }
+
+  return $options;
+}
+
+
 /**
  * Check if the order contains a renewal product.
  *
@@ -139,3 +206,45 @@ function uc_recurring_condition_order_contains_renewals($order) {
 function uc_recurring_condition_order_has_expired($recurring_fee, $settings) {
   return ($recurring_fee->remaining_intervals == 0);
 }
+
+/**
+ * Send an email with order and recurring fee replacement tokens.
+ *
+ * The recipients, subject, and message fields take order token replacements.
+ *
+ */
+function uc_recurring_renewal_email($order, $recurring_fee, $from, $addresses, $subject, $message, $format) {
+  $settings = array(
+    'from' => $from,
+    'addresses' => $addresses,
+    'subject' => $subject,
+    'message' => $message,
+    'format' => $format,
+  );
+
+  $account = uc_order_user_load($order);
+
+  // Token replacements for the subject and body
+  $settings['replacements'] = array(
+    'global' => NULL,
+    'order' => $order,
+    'user' => $account,
+    'recurring_fee' => $recurring_fee,
+  );
+
+  // Replace tokens and parse recipients.
+  $recipients = array();
+  $addresses = token_replace($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_order', 'action-mail', $email, uc_store_mail_recipient_language($email), $settings, $settings['from']);
+
+    if (!$sent['result']) {
+      watchdog('uc_recurring', 'Attempt to e-mail @email concerning order @order_id failed.', array('@email' => $email, '@order_id' => $order->order_id), WATCHDOG_ERROR);
+    }
+  }
+}
\ No newline at end of file
diff --git a/uc_recurring.rules_defaults.inc b/uc_recurring.rules_defaults.inc
index 4d17021..cbcc446 100644
--- a/uc_recurring.rules_defaults.inc
+++ b/uc_recurring.rules_defaults.inc
@@ -30,6 +30,72 @@ function uc_recurring_default_rules_configuration() {
       'order_status' => 'completed',
     ));
   $configs['uc_recurring_renewal_paid'] = $rule;
+  
+  $rule = rules_reaction_rule();
+  $rule->label = t('Notify customer when a renewal has occurred.');
+  $rule->weight = 2;
+  $rule->active = FALSE;
+  $rule->event('uc_recurring_renewal_complete')
+    ->condition('uc_recurring_condition_order_contains_renewals', array(
+      'order:select' => 'order',
+    ))
+    ->action('uc_recurring_renewal_email', array(
+      'order:select' => 'order',
+      'recurring_fee:select' => 'recurring_fee',
+      'from' => uc_store_email_from(),
+      'addresses' => '[order:email]',
+      'subject' => uc_get_message('uc_recurring_renewal_completed_subject'),
+      'message' => uc_get_message('uc_recurring_renewal_completed_message'),
+      'format' => filter_fallback_format(),
+    ));
+  $configs['uc_recurring_renewal_email_completed'] = $rule;
+
+  $rule = rules_reaction_rule();
+  $rule->label = t('Notify customer when a renewal has failed.');
+  $rule->weight = 1;
+  $rule->active = FALSE;
+  $rule->event('uc_recurring_renewal_failed')
+    ->condition(rules_and()
+      ->condition('uc_recurring_condition_order_contains_renewals', array(
+        'order:select' => 'order',
+      ))
+      //@@@ Um, rules_and() what exactly? Some way to differentiate between
+      // this and uc_recurring_renewal_email_expired maybe?
+    )
+    ->action('uc_recurring_renewal_email', array(
+      'order:select' => 'order',
+      'recurring_fee:select' => 'recurring_fee',
+      'from' => uc_store_email_from(),
+      'addresses' => '[order:email]',
+      'subject' => uc_get_message('uc_recurring_renewal_failed_subject'),
+      'message' => uc_get_message('uc_recurring_renewal_failed_message'),
+      'format' => filter_fallback_format(),
+    ));
+  $configs['uc_recurring_renewal_email_failed'] = $rule;
+
+  $rule = rules_reaction_rule();
+  $rule->label = t('Notify customer when a renewal has expired due to failed payment.');
+  $rule->weight = 1;
+  $rule->active = FALSE;
+  $rule->event('uc_recurring_renewal_failed')
+    ->condition(rules_and()
+      ->condition('uc_recurring_condition_order_contains_renewals', array(
+        'order:select' => 'order',
+      ))
+      ->condition('uc_recurring_condition_order_has_expired', array(
+        'recurring_fee:select' => 'recurring_fee',
+      ))
+    )
+    ->action('uc_recurring_renewal_email', array(
+      'order:select' => 'order',
+      'recurring_fee:select' => 'recurring_fee',
+      'from' => uc_store_email_from(),
+      'addresses' => '[order:email]',
+      'subject' => uc_get_message('uc_recurring_renewal_expired_subject'),
+      'message' => uc_get_message('uc_recurring_renewal_expired_message'),
+      'format' => filter_fallback_format(),
+    ));
+  $configs['uc_recurring_renewal_email_expired'] = $rule;
 
   return $configs;
 }
-- 
1.7.9.5

