/**
  * Redirects expired user to the re-subscription screen.
  * @access private
  * @param  int  $userId
  */
 protected function _redirectExpiredMembership($userId)
 {
     global $_CB_framework;
     $params = cbpaidApp::settingsParams();
     $paidUserExtension = cbpaidUserExtension::getInstance($userId);
     $expiredSubscriptions = $paidUserExtension->getUserSubscriptions('X');
     // check if there is any expired extensions for the text
     if (count($expiredSubscriptions) > 0) {
         $textMessage = $params->get('subscriptionExpiredText', "Your membership has expired.");
         $expiredRedirectLink = $params->get('subscriptionExpiredRedirectLink');
     } else {
         $textMessage = $params->get('subscriptionNeededText', "A membership is needed for access.");
         $expiredRedirectLink = $params->get('subscriptionNeededRedirectLink');
     }
     if (!$expiredRedirectLink) {
         $baseClass = cbpaidApp::getBaseClass();
         if ($baseClass) {
             $expiredRedirectLink = $baseClass->_getAbsURLwithParam(array('Itemid' => 0, 'account' => 'expired', 'user' => (int) $userId), 'pluginclass', false);
         } else {
             // without baseClass, as baseClass is not loaded in case of cbpaidsubsbot:
             $cbpPrefix = 'cbp';
             $expiredRedirectLink = 'index.php?option=com_comprofiler&task=pluginclass&plugin=cbpaidsubscriptions&' . $cbpPrefix . 'account=expired&user='******'index.php?option=com_comprofiler&task=pluginclass&plugin=cbpaidsubscriptions&do=display_subscriptions';		// &Itemid= ???
         }
         if ($userId) {
             $_SESSION['cbsubs']['expireduser'] = $userId;
         }
     }
     if ($_CB_framework->getRequestVar('option') != 'com_comprofiler' || $_CB_framework->getRequestVar('task') != 'pluginclass' || $_CB_framework->getRequestVar('plugin') != 'cbpaidsubscriptions') {
         cbRedirect(cbSef($expiredRedirectLink, false), CBPTXT::T($textMessage), 'warning');
     }
 }
 /**
  * store() function override, instead of storing it imports.
  *
  * @param  boolean  $updateNulls
  * @return boolean
  */
 public function store($updateNulls = false)
 {
     $return = '';
     // Check if file uploads are enabled
     if (!(bool) ini_get('file_uploads')) {
         $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("The importer can't continue before file uploads are enabled in PHP settings.");
         return false;
     }
     if (!$this->import_type) {
         $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No import type selected");
         return false;
     }
     $fromFile = cbStartOfStringMatch($this->import_type, 'file_');
     if ($fromFile) {
         $userfile = $_FILES['userfile'];
         if (!$userfile || $userfile == null) {
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No file selected");
             return false;
         }
         if (isset($userfile['error']) && $userfile['error']) {
             $errors_array = array(1 => CBPTXT::T("The uploaded file exceeds the upload_max_filesize directive in php.ini."), 2 => CBPTXT::T("The uploaded file exceeds the maximum size allowed by this form."), 3 => CBPTXT::T("The uploaded file was only partially uploaded."), 4 => CBPTXT::T("No file was selected and uploaded."), 6 => CBPTXT::T("Missing a temporary folder in php.ini."), 7 => CBPTXT::T("Failed to write file to disk."), 8 => CBPTXT::T("File upload stopped by extension."));
             if (in_array($userfile['error'], $errors_array)) {
                 $fileErrorTxt = $errors_array[$userfile['error']];
             } else {
                 $fileErrorTxt = CBPTXT::T("File upload error number ") . htmlspecialchars($userfile['error']);
             }
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . $fileErrorTxt;
             return false;
         }
         if (!$userfile['tmp_name'] || !is_uploaded_file($userfile['tmp_name'])) {
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No temporary file name");
             return false;
         }
         if ($userfile['size'] == 0) {
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("Empty file");
             return false;
         }
     } else {
         $userfile = null;
     }
     if ($this->import_type == 'cms_acl') {
         if (!$this->usergroup) {
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No usergroup selected");
             return false;
         }
     }
     if ($this->import_type == 'subscription') {
         if (!$this->from_plan) {
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No subscription plan selected");
             return false;
         }
         if (!$this->from_sub_status) {
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No subscription status selected");
             return false;
         }
     }
     if ($this->import_type != 'file_uid_plan_exp') {
         if (!$this->plan) {
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No plan selected");
             return false;
         }
         if (!$this->state) {
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No subscription state selected");
             return false;
         }
         if (!$this->date) {
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No subscription date selected");
             return false;
         }
     }
     if ($fromFile) {
         $tmpName = $userfile['tmp_name'];
         $fileSize = (int) $userfile['size'];
         // $fileType = $userfile['type'];
     } else {
         $tmpName = null;
         $fileSize = null;
     }
     $planStateDate = array();
     switch ($this->import_type) {
         case 'file_uid':
             $fp = fopen($tmpName, 'r');
             $content = fread($fp, $fileSize);
             fclose($fp);
             unlink($tmpName);
             $userIdList = explode(',', trim($content));
             break;
         case 'file_uid_plan_exp':
             $userIdList = array();
             $fp = fopen($tmpName, 'r');
             if ($fp) {
                 $n = 0;
                 while (!feof($fp)) {
                     $line = trim(str_replace('"', '', fgets($fp, 256)));
                     $n += 1;
                     if (strlen($line) > 0) {
                         $matches = null;
                         if (preg_match('/([1-9][0-9]*),([1-9][0-9]*),([AXC]),([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9][0-9]:[0-9][0-9]:[0-9][0-9])/', $line, $matches)) {
                             if (!in_array((int) $matches[1], $userIdList)) {
                                 $userIdList[] = (int) $matches[1];
                             }
                             $planStateDate[(int) $matches[1]][] = array('plan' => (int) $matches[2], 'status' => $matches[3], 'date' => $matches[4]);
                         } else {
                             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . sprintf(CBPTXT::T("Line %s does not match the format userid,planid,status,date, e.g. 63,1,A,2009-01-01 00:00:00, and is instead: %s ."), $n, htmlspecialchars($line));
                             fclose($fp);
                             unlink($tmpName);
                             return false;
                         }
                     }
                 }
             }
             fclose($fp);
             unlink($tmpName);
             break;
         case 'cms_acl':
             if (checkJversion() >= 2) {
                 $sql = 'SELECT id FROM #__users u' . ' JOIN #__user_usergroup_map m ON ( u.id = m.user_id )' . ' WHERE m.group_id = ' . (int) $this->usergroup;
             } else {
                 $sql = 'SELECT id FROM #__users' . ' WHERE gid = ' . (int) $this->usergroup;
             }
             $this->_db->setQuery($sql);
             $userIdList = $this->_db->loadResultArray();
             break;
         case 'subscription':
             $statuses = $this->from_sub_status;
             foreach (array_keys($statuses) as $k) {
                 $statuses[$k] = $this->_db->Quote($statuses[$k][0]);
             }
             $sql = 'SELECT s.user_id FROM #__cbsubs_subscriptions s' . ' JOIN #__users u ON ( u.id = s.user_id AND u.block = 0 )' . ' JOIN #__comprofiler c ON ( c.id = s.user_id AND c.confirmed = 1 AND c.approved = 1 )' . ' WHERE s.plan_id = ' . (int) $this->from_plan . ' AND s.status IN (' . implode(',', $statuses) . ')';
             $this->_db->setQuery($sql);
             $userIdList = $this->_db->loadResultArray();
             break;
         default:
             $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("Import type not implemented!");
             return false;
             break;
     }
     if (count($userIdList) == 0) {
         $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("No user to import");
         return false;
     }
     $plansMgr = cbpaidPlansMgr::getInstance();
     if ($this->import_type != 'file_uid_plan_exp') {
         $plan = $plansMgr->loadPlan((int) $this->plan);
         $subscriptionTime = (int) $plan->strToTime($this->date);
         foreach ($userIdList as $key => $value) {
             if (!is_numeric($value)) {
                 $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("non-numeric userid value: ") . str_replace("\n", ' ', htmlspecialchars($value));
                 return false;
             }
             $userIdList[$key] = (int) $value;
         }
     } else {
         $plan = null;
         $subscriptionTime = null;
     }
     $this->_db->setQuery("SELECT u.id, u.username FROM #__comprofiler c, #__users u WHERE c.id=u.id AND u.block = 0 AND c.approved = 1 AND c.confirmed = 1 AND c.id IN (" . implode(',', $userIdList) . ")");
     $users = $this->_db->loadObjectList('id');
     if (count($userIdList) != count($users)) {
         if (is_array($users)) {
             foreach ($users as $u) {
                 $keys = array_keys($userIdList, $u->id);
                 unset($userIdList[$keys[0]]);
                 unset($planStateDate[(int) $u->id]);
             }
         }
         $idList = implode(', ', $userIdList);
         $this->_error = CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("Not all userId exist, are active (confirmed, approved and enabled) ! innexistant or inactive ids: ") . $idList;
         return false;
     }
     $this->_db->setQuery("SELECT DISTINCT user_id FROM #__cbsubs_subscriptions WHERE user_id IN (" . implode(',', $userIdList) . ")" . " ORDER BY user_id");
     $usersSubscribed = $this->_db->loadResultArray();
     $incompatibleUsersSubs = array();
     if ($this->import_type != 'file_uid_plan_exp') {
         foreach ($users as $user) {
             @set_time_limit(60);
             $incompatible = false;
             if (in_array($user->id, $usersSubscribed)) {
                 if ($plan->get('exclusive') && $plan->get('item_type') == 'usersubscription') {
                     $paidUserExtension = cbpaidUserExtension::getInstance($user->id);
                     $subscriptions = $paidUserExtension->getUserSubscriptions(null, false);
                     foreach ($subscriptions as $s) {
                         if ($s->parent_plan == $plan->get('parent') && $s->checkIfValid()) {
                             $sPlan = $s->getPlan();
                             if ($sPlan->get('exclusive') && $sPlan->get('item_type') == 'usersubscription') {
                                 // check if any other exclusive subscription with same parent plan is active:
                                 $incompatible = true;
                                 break;
                             }
                         }
                     }
                 }
             }
             if (!$incompatible) {
                 if ($plan->get('parent')) {
                     $plansMgr = cbpaidPlansMgr::getInstance();
                     $parentPlan = $plansMgr->loadPlan($plan->get('parent'));
                     $parentSub = $parentPlan->loadLatestSomethingOfUser($user->id, null);
                     if (!$parentSub) {
                         $incompatible = true;
                     }
                 }
             }
             if ($incompatible) {
                 if (!in_array($user->id, $incompatibleUsersSubs)) {
                     $incompatibleUsersSubs[] = $user->id;
                 }
                 continue;
             }
             if (!$this->dryrun) {
                 $userFull = CBuser::getUserDataInstance($user->id);
                 $this->createSomething($plan, $userFull, $this->state, $subscriptionTime);
                 CBuser::unsetUsersNotNeeded(array((int) $user->id));
             }
         }
     } else {
         $cbpaidTimes = cbpaidTimes::getInstance();
         $systemTimeZone = new DateTimeZone($cbpaidTimes->systemTimeZone());
         foreach ($users as $user) {
             @set_time_limit(60);
             foreach ($planStateDate[(int) $user->id] as $psd) {
                 $plan = $plansMgr->loadPlan((int) $psd['plan']);
                 $status = $psd['status'];
                 if ($psd['date']) {
                     $date = DateTime::createFromFormat('Y-m-d H:i:s', $psd['date'], $systemTimeZone);
                     $subscriptionTime = $date->getTimestamp();
                 } else {
                     $subscriptionTime = $cbpaidTimes->startTime();
                 }
                 $incompatible = false;
                 if (in_array($user->id, $usersSubscribed)) {
                     if ($plan->get('exclusive') && $plan->get('item_type') == 'usersubscription') {
                         $paidUserExtension = cbpaidUserExtension::getInstance($user->id);
                         $subscriptions = $paidUserExtension->getUserSubscriptions(null, false);
                         foreach ($subscriptions as $s) {
                             if ($s->parent_plan == $plan->get('parent') && $s->checkIfValid()) {
                                 $sPlan = $s->getPlan();
                                 if ($sPlan->get('exclusive') && $sPlan->get('item_type') == 'usersubscription') {
                                     // check if any other exclusive subscription with same parent plan is active:
                                     $incompatible = true;
                                     break;
                                 }
                             }
                         }
                     }
                 }
                 if (!$incompatible) {
                     if ($plan->get('parent')) {
                         $plansMgr = cbpaidPlansMgr::getInstance();
                         $parentPlan = $plansMgr->loadPlan($plan->get('parent'));
                         $parentSub = $parentPlan->loadLatestSomethingOfUser($user->id, null);
                         if (!$parentSub) {
                             $incompatible = true;
                         }
                     }
                 }
                 if ($incompatible) {
                     if (!in_array($user->id, $incompatibleUsersSubs)) {
                         $incompatibleUsersSubs[] = $user->id;
                     }
                     continue;
                 }
                 if (!$this->dryrun) {
                     $userFull = CBuser::getUserDataInstance($user->id);
                     $this->createSomething($plan, $userFull, $status, $subscriptionTime);
                     CBuser::unsetUsersNotNeeded(array((int) $user->id));
                 }
             }
         }
     }
     if (count($userIdList) > 0 && count($incompatibleUsersSubs) == 0) {
         $resultText = CBPTXT::T("Success");
     } elseif (count($userIdList) > count($incompatibleUsersSubs)) {
         $resultText = CBPTXT::T("Partial Success");
     } elseif (count($userIdList) == count($incompatibleUsersSubs)) {
         $resultText = CBPTXT::T("Import failed");
     } else {
         $resultText = CBPTXT::T("Unknown Result");
     }
     $return .= '<h1>' . $resultText . ($this->dryrun ? ' [' . CBPTXT::T("DRY-RUN - NO REAL SUBSCRIPTION") . ']' : '') . ':</h1>';
     if (count($incompatibleUsersSubs) > 0) {
         $idList = implode(', ', $incompatibleUsersSubs);
         $return .= '<p>' . CBPTXT::T("Some users have already subscriptions: user ids: ") . $idList . '</p>';
         // $this->_error		=	CBPTXT::T("Importer") . ' - ' . CBPTXT::T("error:") . ' ' . CBPTXT::T("Some users have already subscriptions: user ids: ") . $idList;
         // return false;
     }
     if ($this->import_type != 'file_uid_plan_exp') {
         $return .= '<p>' . sprintf(CBPTXT::T("%d users subscribed to plan: %s , with state: %s"), count($userIdList) - count($incompatibleUsersSubs), $plan->get('name'), CBPTXT::T($this->_states[$this->state])) . '</p>';
         if (count($userIdList) - count($incompatibleUsersSubs) > 0) {
             $return .= '<p>' . CBPTXT::T("Users subscribed (usernames):") . '</p>';
             $return .= '<p>';
             foreach ($users as $user) {
                 if (!in_array($user->id, $incompatibleUsersSubs)) {
                     $return .= $user->username . ' ';
                 }
             }
             $return .= '</p>';
         }
     } else {
         $return .= '<p>' . sprintf(CBPTXT::T("%d users subscribed"), count($userIdList) - count($incompatibleUsersSubs)) . '</p>';
         if (count($userIdList) - count($incompatibleUsersSubs) > 0) {
             $return .= '<p>' . CBPTXT::T("Users subscribed (usernames):") . '</p>';
             foreach ($users as $user) {
                 if (!in_array($user->id, $incompatibleUsersSubs)) {
                     $return .= '<p>' . $user->username . ' ' . CBPTXT::T("to") . ' ';
                     foreach ($planStateDate[(int) $user->id] as $psd) {
                         $plan = $plansMgr->loadPlan((int) $psd['plan']);
                         $status = $psd['status'];
                         $return .= sprintf(CBPTXT::T("plan: %s , with state: %s") . ' ', $plan->get('name'), CBPTXT::T($this->_states[$status]));
                     }
                 }
             }
             $return .= '</p>';
         }
     }
     if (count($incompatibleUsersSubs) > 0) {
         $return .= '<p>' . CBPTXT::T("Following Users could not be subscribed (usernames) because either: (A) an exclusive active subscription exists that would conflict with the imported user subscription, or: (B) it is a children plan but the parent plan subscription does not exist:") . '</p>';
         $return .= '<p>';
         foreach ($incompatibleUsersSubs as $uid) {
             if (isset($users[$uid])) {
                 $return .= $users[$uid]->username . ' ';
             }
         }
         $return .= '</p>';
     }
     $this->_resultOfStore = $return;
     return true;
 }
	/**
	 * Blocks or unblocks a given user's login and sends appropriate email
	 *
	 * @param  UserTable        $user
	 * @param  string           $cause                 'PaidSubscription' (first activation only), 'SubscriptionActivated' (renewals, cancellation reversals), 'SubscriptionDeactivated', 'Denied' 		//TBD: FIX PLUGINS OLD WAS: (one of: 'UserRegistration', 'UserConfirmation', 'UserApproval', 'NewUser', 'UpdateUser')
	 * @param  int              $replacedPlanId        [optional] id of old cancelled plan (for upgrade or blocking user)
	 * @param  cbpaidSomething  $replacedSubscription  [optional] replaced subscription which is getting deactivated
	 * @param  string           $reason                [optional] 'N' new subscription, 'R' renewal, 'U'=update )
	 * @param  int              $autorenewed          0: not auto-renewing (manually renewed), 1: automatically renewed (if $reason == 'R')
	 */
	protected function setBlockPaidUser( &$user, $cause = null, $replacedPlanId = null, $replacedSubscription = null, $reason = null, $autorenewed = 0 ) {
		$deactivate					=	( $this->status != 'A' );
		if  ( $deactivate ) {
			$deactivatedSub			=&	$this;
		} elseif ( $replacedSubscription !== null ) {
			$deactivatedSub			=	$replacedSubscription;
		} else {
			$deactivatedSub			=	null;
		}

		// First trigger integrations for this new/expired subscription:
//		$_PLUGINS->loadPluginGroup( 'user', 'cbsubs.' );
//		$_PLUGINS->loadPluginGroup('user/plug_cbpaidsubscriptions/plugin');
//		$_PLUGINS->trigger( 'onCPayUserStateChange', array( &$user, (int) $deactivate, (int) ! $deactivate, $cause, $this->plan_id, $replacedPlanId, $reason, &$this ) );
		$this->triggerIntegrations( $user, $cause, $replacedPlanId, $replacedSubscription ? $replacedSubscription->id : null, $reason, $autorenewed );

		// Then check all user's subscriptions for consistency:
		$paidUserExtension			=&	cbpaidUserExtension::getInstance( $user->id );
		$paidUserExtension->checkUserSubscriptions( ! $deactivate, $deactivatedSub, $reason );

		$this->sendNewStatusEmail( $user, $cause, $reason, $autorenewed );
	}
 /**
  * Intercepts CB User Manager list Viewer to add filters
  *
  * @param  int        $listId
  * @param  UserTable  $rows
  * @param  cbPageNav  $pageNav
  * @param  string     $search
  * @param  string[]   $lists
  * @param  string     $option
  * @param  string     $select_tag_attribs
  * @return array
  */
 public function onAfterBackendUsersList($listId, &$rows, &$pageNav, &$search, &$lists, $option, $select_tag_attribs)
 {
     if (!cbpaidApp::authoriseAction('cbsubs.usersubscriptionview')) {
         return array();
     }
     $this->outputRegTemplate();
     // 1. Filters:
     // 1.a. prepare dropdown selector filter with the list of published plans:
     $plansMgr = cbpaidPlansMgr::getInstance();
     $plans = $plansMgr->loadPublishedPlans(CBuser::getMyUserDataInstance(), true, 'any', null);
     $plansList = array();
     $plansList[] = moscomprofilerHTML::makeOption(0, CBPTXT::T('- Select Subscription Plan - '));
     foreach ($plans as $k => $plan) {
         $plansList[] = moscomprofilerHTML::makeOption($k, $plan->get('alias'));
     }
     if (count($plans) > 0) {
         $plansList[] = moscomprofilerHTML::makeOption(-1, CBPTXT::T('ANY PLAN ACTIVE'));
         $plansList[] = moscomprofilerHTML::makeOption(-2, CBPTXT::T('NO PLAN ACTIVE'));
     }
     $lists['cbpaidplan'] = moscomprofilerHTML::selectList($plansList, 'filter_cbpaidplan', $select_tag_attribs, 'value', 'text', $this->filter_cbpaidplan, 2);
     // 1.b. prepare additional selector filter for status of subscriptions:
     if ($this->filter_cbpaidplan && $this->filter_cbpaidplan != -2) {
         // any plan or specific plan:		// no plan: nothing for now to do
         $statesList = array();
         $statesList[] = moscomprofilerHTML::makeOption('A', CBPTXT::T('Active'));
         $statesList[] = moscomprofilerHTML::makeOption('X', CBPTXT::T('Expired'));
         $statesList[] = moscomprofilerHTML::makeOption('C', CBPTXT::T('Cancelled'));
         $statesList[] = moscomprofilerHTML::makeOption('U', CBPTXT::T('Upgraded'));
         $lists['cbpaidsubstate'] = moscomprofilerHTML::selectList($statesList, 'filter_cbpaidsubstate', $select_tag_attribs, 'value', 'text', $this->filter_cbpaidsubstate, 1);
         $datesList = array();
         $datesList[] = moscomprofilerHTML::makeOption('', CBPTXT::T('- Select expiry date -'));
         if ($this->filter_cbpaidsubstate == 'A') {
             $datesList[] = moscomprofilerHTML::makeOption('1 DAY', sprintf(CBPTXT::T('Expiring within %s hours'), 24));
             foreach (array(2, 3, 4, 5, 6, 7) as $v) {
                 $datesList[] = moscomprofilerHTML::makeOption($v . ' DAY', sprintf(CBPTXT::T('Expiring within %s days'), $v));
             }
             foreach (array(2, 3, 4) as $v) {
                 $datesList[] = moscomprofilerHTML::makeOption($v . ' WEEK', sprintf(CBPTXT::T('Expiring within %s weeks'), $v));
             }
             $datesList[] = moscomprofilerHTML::makeOption('1 MONTH', CBPTXT::T('Expiring within in 1 month'));
             foreach (array(2, 3, 4, 6, 9, 12) as $v) {
                 $datesList[] = moscomprofilerHTML::makeOption($v . ' MONTH', sprintf(CBPTXT::T('Expiring within %s months'), $v));
             }
         } else {
             $datesList[] = moscomprofilerHTML::makeOption('-1 DAY', sprintf(CBPTXT::T('Expired last %s hours'), 24));
             foreach (array(2, 3, 4, 5, 6, 7) as $v) {
                 $datesList[] = moscomprofilerHTML::makeOption('-' . $v . ' DAY', sprintf(CBPTXT::T('Expired last %s days'), $v));
             }
             foreach (array(2, 3, 4) as $v) {
                 $datesList[] = moscomprofilerHTML::makeOption('-' . $v . ' WEEK', sprintf(CBPTXT::T('Expired last %s weeks'), $v));
             }
             $datesList[] = moscomprofilerHTML::makeOption('-1 MONTH', CBPTXT::T('Expired last month'));
             foreach (array(2, 3, 4, 6, 9, 12) as $v) {
                 $datesList[] = moscomprofilerHTML::makeOption('-' . $v . ' MONTH', sprintf(CBPTXT::T('Expired last %s months'), $v));
             }
         }
         $lists['cbpaidsubexpdate'] = moscomprofilerHTML::selectList($datesList, 'filter_cbpaidsubexpdate', $select_tag_attribs, 'value', 'text', $this->filter_cbpaidsubexpdate, 1);
     }
     // 2. add subscriptions colum to backend users-lists:
     $pluginColumns = array();
     foreach ($rows as $row) {
         $paidUserExtension = cbpaidUserExtension::getInstance((int) $row->id);
         $subscriptions = $paidUserExtension->getUserSubscriptions('A', true);
         $displayPlans = array();
         foreach ($subscriptions as $sub) {
             $plan = $sub->getPlan();
             if ($plan) {
                 $cssclass = $plan->get('cssclass');
                 $aliasHtml = htmlspecialchars($plan->get('alias'));
             } else {
                 $cssclass = null;
                 $aliasHtml = CBPTXT::Ph("PLAN OF SUBSCRIPTION ID [SUB_ID] IS DELETED", array('[SUB_ID]' => $sub->id));
             }
             $displayPlans[] = '<span' . ($cssclass ? ' class="' . htmlspecialchars($cssclass) . '"' : '') . '>' . $aliasHtml . '</span>';
         }
         $pluginColumns[$row->id] = implode(', ', $displayPlans);
     }
     return array(CBPTXT::T('Subscriptions') => $pluginColumns);
 }
	/**
	 * Checks all subscriptions of this plan for mass-expiries
	 *
	 * @param  int           $limit   limit of number of users to expire ( 0 = no limit )
	 * @return int                    Count of subscriptions expired for this plan.
	 */
	public function checkAllSubscriptions( $limit ) {
		global $_CB_framework;

		$now						=	$_CB_framework->now();
		$nowGraceTimeAgo			=	$this->substractValidityFromTime( $this->get( 'graceperiod' ), $now );
		$cutOffDate					=	date( 'Y-m-d H:i:s', $nowGraceTimeAgo );

		$fields						=	array(	'user_id'	);
		$conditions					=	array(	'plan_id'		=>	array( '=', (int) $this->get( 'id' ) ),
			'status'		=>	array( '=', 'A' ),
			'expiry_date'	=>	array( '<', $cutOffDate ),
			'expiry_date '	=>	array( '>', '0000-00-00 00:00:00' )
		);
		$ordering					=	array();
		$subscriptionLoader			=	$this->newSubscription();
		$subscriptionLoader->setMatchingQuery( $fields, $conditions, $ordering, 0, $limit );
		$expiredUsers				=	$this->_db->loadResultArray();

		if ( count( $expiredUsers ) > 0 ) {
			$deactivatedSub			=	null;
			foreach ( $expiredUsers as $user_id ) {
				$paidUserExtension	=&	cbpaidUserExtension::getInstance( $user_id );
				$paidUserExtension->checkUserSubscriptions( false, $deactivatedSub, 'X', true );
			}
		}
		return count( $expiredUsers );
	}
	/**
	 * Stores subscription only if needed, according to global setting createAlsoFreeSubscriptions
	 *
	 * @param  boolean  $updateNulls  TRUE: null object variables are also updated, FALSE: not.
	 * @return boolean                TRUE if successful otherwise FALSE
	 */
	public function store( $updateNulls = false ) {
		// Clears the cache of the subscriptions for that user id, so next fetch is updated as well:
		$paidUserExtension			=&	cbpaidUserExtension::getInstance( $this->user_id );
		$paidUserExtension->getUserSubscriptions( 'clearcache' );

		return parent::store( $updateNulls );
	}
 public function getDefaultInvoiceCountryCode($onlyGeoIp = true)
 {
     return cbpaidUserExtension::getInstance($this->user_id)->getDefaultInvoiceCountryCode($onlyGeoIp);
 }
 /**
  * Updates payment status of basket and of corresponding subscriptions if there is a change in status
  *
  * @param  cbpaidPaymentBasket        $paymentBasket         Basket
  * @param  string                     $eventType             type of event (paypal type): 'web_accept', 'subscr_payment', 'subscr_signup', 'subscr_modify', 'subscr_eot', 'subscr_cancel', 'subscr_failed'
  * @param  string                     $paymentStatus         new status (Completed, RegistrationCancelled)
  * @param  cbpaidPaymentNotification  $notification          notification object of the payment
  * @param  int                        $occurrences           renewal occurrences
  * @param  int                        $autorecurring_type    0: not auto-recurring, 1: auto-recurring without payment processor notifications, 2: auto-renewing with processor notifications updating $expiry_date
  * @param  int                        $autorenew_type        0: not auto-renewing (manual renewals), 1: asked for by user, 2: mandatory by configuration
  * @param  boolean|string             $txnIdMultiplePaymentDates  FALSE: unique txn_id for each payment, TRUE: same txn_id can have multiple payment dates, additionally: 'SINGLEPAYMENT' will not look at txn_id at all
  * @param  boolean                    $storePaymentRecord   TRUE: normal case, create payment record if needed. FALSE: offline case where pending payment should not create a payment record.
  * @return void
  */
 public function updatePaymentStatus($paymentBasket, $eventType, $paymentStatus, &$notification, $occurrences, $autorecurring_type, $autorenew_type, $txnIdMultiplePaymentDates, $storePaymentRecord = true)
 {
     global $_CB_framework, $_PLUGINS;
     $pluginsLoaded = false;
     $basketUpdateNulls = false;
     $previousUnifiedStatus = $this->mapPaymentStatus($paymentBasket->payment_status);
     $unifiedStatus = $this->mapPaymentStatus($paymentStatus);
     // get all related subscriptions being paid by this basket:
     $subscriptions = $paymentBasket->getSubscriptions();
     $thisIsReferencePayment = false;
     $user = CBuser::getUserDataInstance((int) $paymentBasket->user_id);
     if ($paymentBasket->payment_status != $paymentStatus || $unifiedStatus == 'Partially-Refunded' || $autorecurring_type) {
         if ($paymentStatus && (in_array($eventType, array('web_accept', 'subscr_payment', 'subscr_signup')) || in_array($unifiedStatus, array('Reversed', 'Refunded', 'Partially-Refunded')))) {
             $paymentBasket->payment_status = $paymentStatus;
         }
         if (in_array($eventType, array('subscr_payment', 'subscr_signup'))) {
             $paymentBasket->recurring = 1;
         }
         if ($autorecurring_type == 0 && in_array($unifiedStatus, array('Completed', 'Processed', 'FreeTrial'))) {
             $paymentBasket->mc_amount1 = null;
             $paymentBasket->mc_amount3 = null;
             $paymentBasket->period1 = null;
             $paymentBasket->period3 = null;
             $basketUpdateNulls = true;
         }
         // if (count($subscriptions) >= 1) {
         $now = $_CB_framework->now();
         $completed = false;
         $thisIsReferencePayment = false;
         $reason = null;
         switch ($unifiedStatus) {
             case 'FreeTrial':
             case 'Completed':
             case 'Processed':
                 // this includes Canceled_Reversal !!! :
                 if ($unifiedStatus == 'FreeTrial') {
                     $paymentBasket->payment_status = 'Completed';
                 }
                 if ($unifiedStatus == 'FreeTrial' || $unifiedStatus == 'Completed') {
                     if ($notification->payment_date) {
                         $time_completed = cbpaidTimes::getInstance()->gmStrToTime($notification->payment_date);
                     } else {
                         $time_completed = $now;
                     }
                     $paymentBasket->time_completed = Application::Database()->getUtcDateTime($time_completed);
                     $completed = true;
                 }
                 if ($paymentStatus == 'Canceled_Reversal') {
                     $paymentBasket->payment_status = 'Completed';
                 }
                 if (is_object($notification) && isset($notification->txn_id)) {
                     // real payment with transaction id: store as reference payment if not already stored:
                     $thisIsReferencePayment = $this->_storePaymentOnce($paymentBasket, $notification, $now, $txnIdMultiplePaymentDates, 'Updating payment record because of new status of payment basket: ' . $unifiedStatus . ($paymentStatus != $unifiedStatus ? ' (new gateway-status: ' . $paymentStatus . ')' : '') . ' because of event received: ' . $eventType . '. Previous status was: ' . $previousUnifiedStatus);
                 } else {
                     // Free trials don't have a notification:
                     $thisIsReferencePayment = true;
                 }
                 if ($thisIsReferencePayment) {
                     // payment not yet processed:
                     $autorenewed = $paymentBasket->recurring == 1 && $unifiedStatus == 'Completed' && $previousUnifiedStatus == 'Completed';
                     for ($i = 0, $n = count($subscriptions); $i < $n; $i++) {
                         $reason = $autorenewed ? 'R' : $subscriptions[$i]->_reason;
                         $subscriptions[$i]->activate($user, $now, $completed, $reason, $occurrences, $autorecurring_type, $autorenew_type, $autorenewed ? 1 : 0);
                     }
                 }
                 break;
             case 'RegistrationCancelled':
             case 'Reversed':
             case 'Refunded':
             case 'Unsubscribed':
                 if ($unifiedStatus == 'RegistrationCancelled') {
                     if (!($previousUnifiedStatus == 'NotInitiated' || $previousUnifiedStatus === 'Pending' && $paymentBasket->payment_method === 'offline')) {
                         return;
                     }
                 }
                 for ($i = 0, $n = count($subscriptions); $i < $n; $i++) {
                     $reason = $subscriptions[$i]->_reason;
                     if ($reason != 'R' || in_array($unifiedStatus, array('Reversed', 'Refunded'))) {
                         // Expired and Cancelled as well as Partially-Refunded are not reverted !		//TBD: really revert on refund everything ? a plan param would be nice here
                         if (!in_array($previousUnifiedStatus, array('Pending', 'In-Progress', 'Denied', 'Reversed', 'Refunded')) && in_array($subscriptions[$i]->status, array('A', 'R', 'I')) && !$subscriptions[$i]->hasPendingPayment($paymentBasket->id)) {
                             // not a cancelled or denied renewal:
                             $subscriptions[$i]->revert($user, $unifiedStatus);
                         }
                     }
                 }
                 if ($unifiedStatus == 'RegistrationCancelled') {
                     $paymentBasket->historySetMessage('Payment basket deleted because the subscriptions and payment got cancelled');
                     $paymentBasket->delete();
                     // deletes also payment_Items
                 }
                 $paidUserExtension = cbpaidUserExtension::getInstance($paymentBasket->user_id);
                 $subscriptionsAnyAtAll = $paidUserExtension->getUserSubscriptions('');
                 $params = cbpaidApp::settingsParams();
                 $createAlsoFreeSubscriptions = $params->get('createAlsoFreeSubscriptions', 0);
                 if (count($subscriptionsAnyAtAll) == 0 && !$createAlsoFreeSubscriptions) {
                     $user = new UserTable();
                     $id = (int) cbGetParam($_GET, 'user');
                     $user->load((int) $id);
                     if ($user->id && $user->block == 1) {
                         $user->delete(null);
                     }
                 }
                 break;
             case 'Denied':
             case 'Pending':
                 if ($unifiedStatus == 'Denied') {
                     // In fact when denied, it's the case as if the user attempted payment but failed it: He should be able to re-try: So just store the payment as denied for the records.
                     if ($eventType == 'subscr_failed' || $eventType == 'subscr_cancel' && $autorecurring_type != 2) {
                         // special case of a failed attempt:
                         // or this is the final failed attempt of a basket with notifications:
                         break;
                     }
                 }
                 if ($previousUnifiedStatus == 'Completed') {
                     return;
                     // do not change a Completed payment as it cannot become Pending again. If we get "Pending" after "Completed", it is a messages chronological order mistake.
                 }
                 break;
             case 'In-Progress':
             case 'Partially-Refunded':
             default:
                 break;
         }
         if ($eventType == 'subscr_cancel') {
             if (!in_array($unifiedStatus, array('Denied', 'Reversed', 'Refunded', 'Unsubscribed'))) {
                 for ($i = 0, $n = count($subscriptions); $i < $n; $i++) {
                     $subscriptions[$i]->autorecurring_cancelled($user, $unifiedStatus, $eventType);
                 }
             }
         }
         for ($i = 0, $n = count($subscriptions); $i < $n; $i++) {
             $subscriptions[$i]->notifyPaymentStatus($unifiedStatus, $previousUnifiedStatus, $paymentBasket, $notification, $now, $user, $eventType, $paymentStatus, $occurrences, $autorecurring_type, $autorenew_type);
         }
         if (in_array($unifiedStatus, array('Denied', 'Reversed', 'Refunded', 'Partially-Refunded', 'Pending', 'In-Progress'))) {
             $thisIsReferencePayment = $this->_storePaymentOnce($paymentBasket, $notification, $now, $txnIdMultiplePaymentDates, 'Updating payment record because of new status of payment basket: ' . $unifiedStatus . ($paymentStatus != $unifiedStatus ? ' (new gateway-status: ' . $paymentStatus . ')' : '') . ' because of event received: ' . $eventType . '. Previous status was: ' . $previousUnifiedStatus);
         }
         // }
         foreach ($paymentBasket->loadPaymentTotalizers() as $totalizer) {
             $totalizer->notifyPaymentStatus($thisIsReferencePayment, $unifiedStatus, $previousUnifiedStatus, $paymentBasket, $notification, $now, $user, $eventType, $paymentStatus, $occurrences, $autorecurring_type, $autorenew_type, $txnIdMultiplePaymentDates);
         }
         if (!in_array($unifiedStatus, array('RegistrationCancelled'))) {
             if ($thisIsReferencePayment && in_array($unifiedStatus, array('Completed', 'Processed'))) {
                 $paymentBasket->setPaidInvoiceNumber($reason);
             }
             $paymentBasket->historySetMessage('Updating payment basket ' . ($paymentStatus !== null ? 'status: ' . $unifiedStatus . ($paymentStatus != $unifiedStatus ? ' (new gateway-status: ' . $paymentStatus . ')' : '') : '') . ' because of event received: ' . $eventType . ($paymentStatus !== null ? '. Previous status was: ' . $previousUnifiedStatus : ''));
             $paymentBasket->store($basketUpdateNulls);
         } else {
             //TDB ? : $paymentBasket->delete(); in case of RegistrationCancelled done above, but should be done in case of FreeTrial ? (could be a param in future)
         }
         if (!in_array($unifiedStatus, array('Completed', 'Processed')) || $thisIsReferencePayment) {
             $_PLUGINS->loadPluginGroup('user', 'cbsubs.');
             $_PLUGINS->loadPluginGroup('user/plug_cbpaidsubscriptions/plugin');
             $pluginsLoaded = true;
             $_PLUGINS->trigger('onCPayAfterPaymentStatusChange', array(&$user, &$paymentBasket, &$subscriptions, $unifiedStatus, $previousUnifiedStatus, $occurrences, $autorecurring_type, $autorenew_type));
         }
     }
     if (!in_array($unifiedStatus, array('Completed', 'Processed')) || $thisIsReferencePayment) {
         if (!$pluginsLoaded) {
             $_PLUGINS->loadPluginGroup('user', 'cbsubs.');
             $_PLUGINS->loadPluginGroup('user/plug_cbpaidsubscriptions/plugin');
         }
         $_PLUGINS->trigger('onCPayAfterPaymentStatusUpdateEvent', array(&$user, &$paymentBasket, &$subscriptions, $unifiedStatus, $previousUnifiedStatus, $eventType, &$notification));
     }
 }
	/**
	* UserBot Called when a user is deleted from backend (unregistration done)
	*
	* @param  UserTable  $user     reflecting the user being deleted
	* @param  boolean    $success  TRUE for successful deleting
	* @return boolean              true if all is ok, or false if ErrorMSG generated
	*/
	public function onAfterDeleteUser( $user, /** @noinspection PhpUnusedParameterInspection */ $success ) {
		global $_CB_database;

		cbpaidErrorHandler::on();

		$return = true;

		$paidUserExtension			=&	cbpaidUserExtension::getInstance( $user->id );
		$subscriptions				=&	$paidUserExtension->getUserSubscriptions();

		foreach ( array_keys( $subscriptions ) as $k ) {
			$subscriptions[$k]->historySetMessage( 'User subscription deleted because user is deleted' );
			if ( ! $subscriptions[$k]->delete() ) {
				$this->_setErrorMSG('SQL error cbpay userdelete error: '.htmlspecialchars($_CB_database->getErrorMsg())."\n");
				$return = false;
			}
		}
		cbpaidErrorHandler::off();
		return $return;
	}
示例#10
0
	/**
	 * Gets/Computes data values
	 *
	 * @param  int                $userId
	 * @param  cbpaidSomething[]  $subscriptions
	 * @param  string             $dateType
	 * @param  int                $cbFieldId
	 * @param  string             $value
	 * @return array
	 */
	private function getDateValues( $userId, $subscriptions, $dateType, $cbFieldId, $value ) {
		switch ( $dateType ) {
			case 'now':
				$values				=	array( date( 'Y-m-d H:i:s' ) );
				break;
			case 'cbfield':
				$values				=	cbpaidUserExtension::getInstance( $userId )->getFieldValue( $cbFieldId, true );
				if ( ! is_array( $values ) ) {
					// Not multi-valued field:
					$values			=	array( $values );
				}
				break;
			case 'value':		// (incl. CB substitutions):
				$cbUser				=	CBuser::getInstance( $userId );
				if ( $cbUser ) {
					$extraStrings	=	null;
					$values			=	array( $cbUser->replaceUserVars( $value, false, true, $extraStrings, false ) );
				} else {
					$values			=	array( '' );
				}
				break;
			case 'subscription_date':
			case 'last_renewed_date':
			case 'expiry_date':
			case 'payment_date':
				$values				=	array();
				foreach ( $subscriptions as $sub ) {
					if ( isset( $sub->$dateType ) ) {
						$values[]	=	$sub->$dateType;
					}
				}
				break;

			default:
				$values				=	array();
			break;
		}
		return $values;
	}
示例#11
0
	/**
	 * Gets value of field $fieldId from $cbUser record
	 *
	 * @param  CBuser  $cbUser
	 * @param  int     $fieldId
	 * @return mixed
	 */
	private static function _getFieldValue( $cbUser, $fieldId ) {
		$user			=	$cbUser->getUserData();
		if ( $user && isset( $user->id ) ) {
			return cbpaidUserExtension::getInstance( $user->id )->getFieldValue( $fieldId, true );
		} else {
			return null;
		}
	}
	/**
	 * Checks access to URL
	 *
	 * @param  int      $userId
	 * @param  array    $getPostArray
	 * @param  array    $getArray
	 * @param  array    $postsMissingInGetToFindPlans  IN+OUT
	 * @param  string   $listName
	 * @param  boolean  $returnControllingPlans
	 * @return array|boolean|null
	 */
	public function checkAccessUrl( $userId, &$getPostArray, $getArray, &$postsMissingInGetToFindPlans, $listName, $returnControllingPlans = false ) {
		$plansMgr							=&	cbpaidPlansMgr::getInstance();
		$forCause							=	'any';
		// take any plans, not only those for this user:
		$plans								=&	$plansMgr->loadPublishedPlans( null, true, $forCause, null );

		$plansControlling					=	array();
		foreach ( $plans as $k => $plan ) {
			$cpaycontent_list				=	trim( $plan->getParam( $listName, null, 'integrations' ) );
			if ( $cpaycontent_list ) {
				$controlledObjects			=	explode( "\r\n", $cpaycontent_list );
				foreach ( $controlledObjects as $ctrlObj ) {
					$ctrlObjParts			=	array();
					self::_my_parse_str( $ctrlObj, $ctrlObjParts );
					if ( $this->_allKeysInArray( $ctrlObjParts, $getPostArray ) ) {
						$plansControlling[]	=	$k;
						// Now check if we needed a ley from the POST which was not in the GET to have this plan controlling it:
						if ( ! $this->_allKeysInArray( $ctrlObjParts, $getArray ) ) {
							$getArrayKeys	=	array_keys( $getArray );
							foreach ( $ctrlObjParts as $kk => $vv ) {
								if ( ! in_array( $kk, $getArrayKeys ) ) {
									// Indeed: list that key so we add it to the accessurl, so that on the redirect the plan can be found (fix for bug #2204):
									$postsMissingInGetToFindPlans[$kk]	=	$getPostArray[$kk];
								}
							}
						}
					}
				}
			}
		}
	
		$allowAccess						=	null;
		if ( count( $plansControlling ) ) {
			$allowAccess					=	false;
			$paidUserExtension				=	cbpaidUserExtension::getInstance( $userId );
			$subscriptions					=	$paidUserExtension->getUserSubscriptions( 'A', true );
			foreach ( $subscriptions as $sub ) {
				if ( in_array( $sub->plan_id, $plansControlling ) ) {
					$allowAccess			=	true;
					break;
				}
			}
		}
		if ( $allowAccess || ! $returnControllingPlans ) {
			return $allowAccess;
		} else {
			// we need to remove from the list of controlling plans the plans that cannot be upgraded to:
			$this->unsetPlansNotAllowedToBeProposed( $plansControlling, $forCause, $userId );
			return $plansControlling;
		}
	}