I looked at the code in the .module files and couldn't find any cron or queue functions where users would have their subscription based role removed upon subscription expiration.

I modified the current code to achieve that.

In my lm_paypal_subscriptions.module, this is the hook cron rewritten to serve 2 purposes, the original one of sending reminder email but also to remove user role when the subscription is expired. (sorry I don't know how to write patches. Also please note that the code does not incorporate the D7 best practices, such as using db_Select etc.)

/**
 * Implements hook_cron().
 */
function lm_paypal_subscriptions_cron() {
  if (lm_paypal_debug()) {
    watchdog(LM_PAYPAL_SUBSCRIPTIONS, 'cron');
  }

  // Look for any subscriber who is near the end of their subscription

  // Find all live subscriptions
  $subs = db_query('SELECT * FROM {lm_paypal_subscriptions} WHERE status = :status', array(':status' => 1));

  foreach ($subs as $so) {
  
    $item_name = $so->item_name;
    // Should I warn people near the end of this subscription?
    $nearend_days = $so->nearend_days;
    if (! ($nearend_days >= 1)) {
      // Not set, skip this subscription
      //continue;
    }

    // Find how many days the subscription is supposed to last
    $duration = lm_paypal_subscription_days($so);

    if ($duration == 0) {
      // Infinite, skip this subscription
      continue;
    }

    // Find the seconds from start till I should warn
    $from_start = ($duration - $nearend_days) * (24 * 60 * 60);
    /*
     OK: This could be negative because cron wasn't fired off for some reason
     and the email wasn't sent
     if ($from_start < 0) {
     watchdog(LM_PAYPAL_SUBSCRIPTIONS, "cron $item_name from_start $from_start < 0");
     continue;
     }
     */

    $subid = $so->subid;
	//ADD-ON by well mannered squirrel
	$rid = $so->rid;
	
    // Find all the subscribers to this subscription
    $sbs = db_query("SELECT * FROM {lm_paypal_subscribers} WHERE status = :status AND subid = :subid", array(':status' => 1, ':subid' => $subid));

    foreach ($sbs as $sb) {

      // TODO: just use $sb object
      $usid = $sb->usid;
      $nid = $sb->nid;
      $uid = $sb->uid;
      $started = $sb->started;
      $send_after = $started + $from_start;
      $time = REQUEST_TIME;
	
	  //ADD-ON by well mannered squirrel
	  //Remove roles if subscription expired
	  $expiring = $started +($duration * 24 * 60 * 60);

	  if ($expiring < strtotime('now')) {

	  	  $subscriber = new stdClass();
	  $subscriber->status = 5; 
	  $subscriber->usid = $usid;
      lm_paypal_subscriptions_save_subscriber($subscriber);
	  $account = new stdClass();
	  $account->uid = $uid;
	  lm_paypal_subscriptions_user_loose_role($account, $rid);

	  }
	
      if ($sb->email_sent) {
        //watchdog(LM_PAYPAL_SUBSCRIPTIONS, "cron email_sent already");
        continue;
      }

      if ($send_after < $time) {
        //watchdog(LM_PAYPAL_SUBSCRIPTIONS, "cron email $item_name $uid $subid, update email_sent: started " . format_date($started, 'small') . ", duration " . $duration . ", nearend_days" . $nearend_days . ", send_after " . format_date($send_after, 'small') . ", now " . format_date($time, 'small'));

        // Email user to let them know their subscription is near its end
        //  note: t() will be called inside lm_paypal_mail_user
        // Extra variables (in addition to the default ones provided)
        if ($so->kind == 0 || $so->kind == 2) {
          $variables = array(
            '%Subscription' => $so->item_name,
            '%Days' => $nearend_days,
            '%Node' => '',
          );
        }
        elseif ($so->kind == 1) {
          $variables = array(
            '%Subscription' => $so->item_name,
            '%Days' => $nearend_days,
            '%Node' => $node,
          );
        }
        lm_paypal_mail_user(
          $uid,
          $uid,
          $so->send_user_onnearend_subject,
          $so->send_user_onnearend_body,
          $variables);

        // Remember we've sent them an email!
        // TODO Please review the conversion of this statement to the D7 database API syntax.
        /* db_query("UPDATE {lm_paypal_subscribers} SET email_sent = 1 WHERE usid = %d", $usid) */
        $update = db_update('lm_paypal_subscribers')
  ->fields(array(
          'email_sent' => 1,
        ))
  ->condition('usid', $usid)
  ->execute();
        if (!$update) {
          watchdog(LM_PAYPAL_SUBSCRIPTIONS, 'Failed to update to subscribers email_sent', array(), WATCHDOG_ERROR);
        }
      }
    }
  }
}

Comments

fehin’s picture

In a similar post someone mentioned it worked after running cron. I haven't tested this but perhaps a scheduled cron will help.

Jack Ellis’s picture

I came up with a messy workaround after reading this. Still needs testing but it runs on cron.. Oh and I put this in my module that I'm working on ATM, so replace hook_ with your module_name_ ;P

  1. Removes role
  2. Marks the subscription as inactive
function hook_cron()
{
    // Find all live subscriptions
    $subscriptions = db_query('SELECT * FROM {lm_paypal_subscriptions} WHERE status = :status', array(':status' => 1));
    
    // Loop through all subscriptions
    foreach ($subscriptions as $subscription)
    {   
        // Set the subscription ID & role ID
        $subscription_id      = $subscription->subid;
        $subscription_role_id = $subscription->rid;
        
        // Find all the subscribers to this subscription
        $subscribers = db_query("SELECT * FROM {lm_paypal_subscribers} WHERE status = :status AND subid = :subid", array(':status' => 1, ':subid' => $subscription_id));

        // Loop through all the subscribers
        foreach ($subscribers as $subscriber)
        {   
            // Define the user ID and the start date
            $subscriber_user_id = $subscriber->uid;
            $subscriber_start_date = $subscriber->started;
            
            // Handle end date
            $subscriber_end_date = new DateTime('@'.$subscriber_start_date);
            
            // The billing cycle units are represented as single letters in the database
            $t3s = array(
                'D' => 'day',
                'W' => 'week',
                'M' => 'month',
                'Y' => 'year'
            );
            
            // Modify the start date (to work out the end date)
            $subscriber_end_date->modify('+'.$subscription->p3.' '.$t3s[$subscription->t3]);

            // Check to see if the subscription has expired
            if (REQUEST_TIME >= $subscriber_end_date->format('U'))
            {   
                // Remove role from user
                db_delete('users_roles')
                        ->condition('uid', $subscriber_user_id)
                        ->condition('rid', $subscription_role_id)
                        ->execute();
                
                
                // Update status of subscription
                // NOTE: I'm pretty sure that the status is the only thing that gets updated (with the role)
                $subscriber_modify         = lm_paypal_subscriptions_load_subscriber(array('usid' => $subscriber->usid));
                $subscriber_modify->status = LM_PAYPAL_SUBSCRIPTIONS_STATUS_CANCELLED;
                lm_paypal_subscriptions_save_subscriber($subscriber);
                
                if (lm_paypal_subscriptions_menu_rebuild())
                {
                    menu_rebuild();
                }
            }
        }
    }
}

Imho, the table structure needs redoing, I'm actually really keen to join the developers on this module.