/**
  * Creates a something of a plan
  *
  * @param  cbpaidProduct  $plan
  * @param  UserTable      $user
  * @param  string         $state
  * @param  int            $subscriptionTime
  */
 protected function createSomething($plan, $user, $state, $subscriptionTime)
 {
     global $_CB_database;
     $replacesSubId = null;
     $reason = 'N';
     if ($state == 'X' && $plan->get('item_type') != 'usersubscription') {
         // safeguard for donations and merchandises: they do not expire!, so set them as cencelled if import is as expired:
         $state = 'C';
     }
     /*
     		if ( $plan->get( 'exclusive' ) && ( $plan->get( 'item_type' ) == 'usersubscription' ) && ( $state == 'A' ) ) {
     			$incompatible				=	false;
     			$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' ) ) {
      						// This other exclusive user subscription with same parent plan is active: then it is an upgrade from that subscription
      						$replacesSubId	=	array( $s->plan_id, $s->id );
      						$reason			=	'U';
      						break;
      					}
      				}
      			}
      			if ( $incompatible ) {
     				continue;
      			}
     		}
     */
     $parentSubId = null;
     if ($plan->get('parent')) {
         $plansMgr = cbpaidPlansMgr::getInstance();
         $parentPlan = $plansMgr->loadPlan($plan->get('parent'));
         $parentSub = $parentPlan->loadLatestSomethingOfUser($user->id, null);
         if ($parentSub) {
             $parentSubId = array($parentSub->plan_id, $parentSub->id);
         }
     }
     $postdata = array();
     $price = null;
     $recurringPrice = null;
     $subscription = $plan->createProductThing($user, $postdata, $reason, $state == 'A' ? 'I' : $state, $replacesSubId, null, $subscriptionTime, $price, $recurringPrice, $parentSubId);
     if ($state == 'A') {
         $subscription->activate($user, $subscriptionTime);
     } elseif ($state == 'X') {
         /** @var cbpaidUsersubscriptionRecord $subscription */
         if (is_callable(array($subscription, 'computeExpiryTimeIfActivatedNow'))) {
             // Sets expiry_date for expired user subscriptions:
             $expiry = $subscription->computeExpiryTimeIfActivatedNow($subscriptionTime);
             $subscription->expiry_date = $expiry === null ? $_CB_database->getNullDate() : $_CB_database->getUtcDateTime($expiry);
             if (!$subscription->store()) {
                 trigger_error('subscription store error:' . htmlspecialchars($_CB_database->getErrorMsg()), E_USER_ERROR);
             }
         }
     }
 }
 /**
  * Checks for the user's subscriptions,
  * and if no subscription found (and free memberships not allowed):
  * redirects or returns FALSE depending on $redirect
  * Otherwise returns TRUE
  *
  * @param  string   $functionName  Name of calling function (CB API functions: getDisplayTab, getEditTab, onDuringLogin, getTabComponent, module: mod_subscriptions )
  * @param  int      $userId        Check a specific user
  * @param  boolean  $redirect      If should redirect in case of expiration
  * @return boolean                 if $redirect == false: TRUE: membership valid, FALSE: membership not valid, otherwise: TRUE or REDIRECT !
  */
 public function checkExpireMe($functionName, $userId = null, $redirect = true)
 {
     global $_CB_framework;
     static $notCalled = true;
     static $notMassExpired = true;
     if ($notCalled && $_CB_framework->GetUi() == 1) {
         if ($userId == null) {
             $params = cbpaidApp::settingsParams();
             if ($notMassExpired && $params->get('massexpirymethod', 0) == 1) {
                 // mass-expire 10 subscriptions at a time on the way if not exipring a particular user:
                 $plansMgr = cbpaidPlansMgr::getInstance();
                 $plansMgr->checkAllSubscriptions(10);
                 $notMassExpired = false;
             }
             $userId = $_CB_framework->myId();
         }
         if ($userId) {
             // make sure to not check more than once:
             $notCalled = false;
             $null = null;
             $paidUserExtension = cbpaidUserExtension::getInstance($userId);
             $subscriptionOk = $paidUserExtension->checkUserSubscriptions(false, $null, 'X', true);
             if (!$subscriptionOk) {
                 if ($redirect) {
                     $this->_redirectExpiredMembership($userId);
                     return false;
                     // if we are already displaying the correct screen...
                 } else {
                     return false;
                 }
             }
         }
     }
     return true;
 }
	/**
	* gets the chosen plans from the form, and checks if they are allowed for that user
	* also gets the options of the plans
	* In detail:
	* gets an array of array of int as an array of int (removing first level), verifying that if index is not 0 the parent exists
	* In each plan object there is a ->_options variable with a Registry object with the option values of the plan
	*
	* @param  UserTable        $user            Reflecting the user being registered or saved
	* @param  string           $name            name of parameter in REQUEST URL
	* @param  cbpaidProduct[]  $allowedPlans    array of cbpaidProduct  which are allowed
	* @param  boolean          $isRegistration  TRUE: Registration process (guest), or FALSE: upgrade-process (logged-in user)
	* @param  string           $reason          Subscription reason: 'N'=new subscription (default), 'R'=renewal, 'U'=update
	* @param  boolean          $returnPlans     TRUE: returns plan objects or FALSE: returns plan ids only.
	* @param  string           $postfix         postfix for identifying multiple plans spaces (optional)
	* @return int[]|cbpaidProduct[]|string     ARRAY of int|of cbpaidProducts : Plans which are selected within hierarchy (according to the post, to be rechecked !) or STRING: error message.
	*/
	protected function & _planGetAndCheckReqParamArray( &$user, $name, &$allowedPlans, $isRegistration, $reason, $returnPlans = false, $postfix = '' ) {
		global $_CB_framework, $_POST;

		$params							=&	cbpaidApp::settingsParams();
		$enableFreeRegisteredUser		=	$params->get( 'enableFreeRegisteredUser', 1 );
		$createAlsoFreeSubscriptions	=	$params->get( 'createAlsoFreeSubscriptions', 0 );

		$ui								=	$_CB_framework->getUi();
		if ( ! $isRegistration ) {
			if ( $ui == 1 ) {
				$userId					=	(int) cbGetParam( $_POST, 'user', 0 );
			} else {
				$userId					=	(int) cbGetParam( $_POST, 'id', 0 );
			}
		} else {
			$userId						=	null;
		}

		$selectedPlanIds							=	$this->_plangetReqParamArray( $name, $postfix );
		/// $validSub									=	array();
		// 1. checks that selected plans hierarchy is respected:
		$ok											=	true;
		$plansMgr									=	null;
		foreach ( $selectedPlanIds as $id ) {
			if ( $id != 0 ) {						// ignore "None" plan in backend edit profile
				$ok									=	false;
	
				// foreach ( $allowedPlans as $planid => $p ) {
				if ( isset( $allowedPlans[(int) $id] ) ) {
					$p								=	$allowedPlans[(int) $id];
	
					if ( $id == $p->id ) {
						$parentOk					=	true;
						$parentId					=	$p->get( 'parent' );
						if ( $parentId != 0 ) {
							// the selected plan has a parent plan: check if parent plan is also chosen or already subscribed and active:
							$parentOk				=	false;
							foreach ($selectedPlanIds as $selPlanId ) {
								if ( $parentId == $selPlanId ) {
									$parentOk		=	true;
									break;
								}
							}
							if ( ( ! $isRegistration ) && ( ! $parentOk ) ) {
								// try to see if user is subscribed already to the parent plan:
								if ( $userId ) {
									if ( $plansMgr === null ) {
										$plansMgr	=&	cbpaidPlansMgr::getInstance();
									}
									$plan			=	$plansMgr->loadPlan( $parentId );
									/** @var $plan cbpaidProduct */
									if ( $plan ) {
										// Check if allow free lifetime users without need to create such subscriptions:
										if ( $enableFreeRegisteredUser && ( ! $createAlsoFreeSubscriptions ) && $plan->isLifetimeValidity() && $plan->isFree() ) {
											$parentOk		=	true;
										} else {
											$sub			=	$plan->newSubscription();
											/** @var $sub cbpaidSomething */
											if ( $sub->loadValidUserSubscription( $userId ) ) {
												$parentOk	=	true;
												/// $validSub[$parentId]		=	$sub->id;
											}
										}
									}
								}
							}
						}
						if ( $parentOk ) {
							$ok						=	true;
						}
						break;
					}
				}
				if ( ! $ok ) {
					break;
				}
			}
		}

		if ( ! $ok ) {
			$selectedPlanIds								=	CBPTXT::T("Chosen plans combination is not allowed (you must choose coherent plans selection, e.g. parent subscriptions to a plan must be active).");
		} else {
			// 2. Check that all exclusivities are respected:
			$plansMgr										=&	cbpaidPlansMgr::getInstance();
			// 2.a. build array of exclusive [parent][plan]:
			$exclusiveChildren								=	array();
			// 2.a.1. add the plans just selected now:
			foreach ($allowedPlans as $id => $p ) {
				if ( $p->get( 'exclusive' ) ) {
					$exclusiveChildren[$p->get( 'parent' )][$p->get( 'id' )]	=	( in_array( $id, $selectedPlanIds ) ? 1 : 0 );
				}
			}
			// 2.a.2. add the plans already subscribed with active subscription (if we are not just upgrading that level):
			$ValidUserPlans									=	array();
			$validSubExists									=	array();
			if ( ( ! $isRegistration ) && $userId ) {
				foreach ( $exclusiveChildren as $parentId => $exclPlansArray ) {
					if ( $parentId != 0 ) {
						$plan								=	$plansMgr->loadPlan( $parentId );
						if ( $plan ) {
							$sub							=	$plan->newSubscription();
							$ValidUserPlans[$parentId]		=	( $sub->loadValidUserSubscription( $userId ) );
						} else {
							$selectedPlanIds				=	CBPTXT::T("Chosen plan has a parent plan configured that doesn't exist anymore.");
						}
					}
					$numberOfSelected						=	array_sum( $exclPlansArray );
					if ( $numberOfSelected == 0 ) {
						$firstFreeLifeTime					=	array();
						// foreach ( $exclPlansArray as $childId => $selected )
						foreach ( array_keys( $exclPlansArray ) as $childId ) {
							$plan							=	$plansMgr->loadPlan( $childId );
							if ( ( ! isset( $firstFreeLifeTime[$parentId] ) ) && ( $enableFreeRegisteredUser && ( ! $createAlsoFreeSubscriptions ) && $plan->isLifetimeValidity() && $plan->isFree() ) ) {
								$firstFreeLifeTime[$parentId]	=	$plan->get( 'id' );
							}
							if ( ! isset( $ValidUserPlans[$childId] ) ) {
								$sub						=	$plan->newSubscription();
								$ValidUserPlans[$childId]	=	( $sub->loadValidUserSubscription( $userId ) );
							}
							if ( $ValidUserPlans[$childId] ) {
								$exclusiveChildren[$parentId][$childId]		=	1;
								$validSubExists[$parentId]						=	1;
							}
						}
					}
				}
			}
			// 2.b. check that exactly 1 exclusive plan is selected at each level (including still valid subscribed plans) which matters:
			if ( ! ( ( $ui == 2 ) && ( $selectedPlanIds == array( '0' ) ) ) ) {		// ignore "None" plan in backend edit profile
				foreach ( $exclusiveChildren as $parentId => $exclPlansArray ) {
					$numberOfSelected						=	array_sum( $exclPlansArray );
					if ( $numberOfSelected > 1 ) {
						$selectedPlanIds					=	CBPTXT::T("Chosen plans combination is not allowed (you can't choose more than one mandatory plan).") . $numberOfSelected;
						break;
					}
					elseif ( ( $numberOfSelected == 0 ) && ( ! isset( $validSubExists[$parentId] ) ) && ( ! isset( $firstFreeLifeTime[$parentId] ) ) ) {
						if ( ( $parentId == 0 ) || in_array( $parentId, $selectedPlanIds ) || ( isset( $ValidUserPlans[$parentId] ) && ( $ValidUserPlans[$parentId] == true ) ) )
						{
							$selectedPlanIds				=	CBPTXT::T("Chosen plans combination is not allowed (you must choose coherent plans selection, e.g. mandatory subscription(s) must be active or mandatory plan(s) must be chosen).");
							$names							=	array();
							foreach ( array_keys( $exclPlansArray ) as $childId ) {
								$exclPlan					=&	$plansMgr->loadPlan( $childId );
								/** @var $exclPlan cbpaidProduct */
								$names[]					=	$exclPlan->get( 'name' );
							}
							if ( $parentId ) {
								$parentPlan					=&	$plansMgr->loadPlan( $parentId );
								/** @var $parentPlan cbpaidProduct */
								$parentName					=	$parentPlan->get( 'name' );
								$selectedPlanIds			.=	' ' . CBPTXT::T( sprintf( "'%s' has mandatory options '%s' and none is selected." , $parentName, implode( "', '", $names ) ) );
							}
							break;
						}
					}
				}
			}
			// 3. Checks that all selected plans' conditions are met:
			if ( is_array( $selectedPlanIds ) ) {
				foreach ( $selectedPlanIds as $id ) {
					if ( $id ) {
						$plan								=&	$plansMgr->loadPlan( $id );
						if ( $plan ) {
							if ( ! $plan->checkActivateConditions( $user, $reason, $selectedPlanIds ) ) {
								// Error text will be in selectedPlanIds in case of error returning false:
								break;
							}
						}
					}
				}
			}
			// 4. Checks done:
			if ( $returnPlans && is_array( $selectedPlanIds ) && ( count( $selectedPlanIds ) > 0 ) ) {
				// if returning selected plans, sort them in same order and with same keys as corresponding allowed plans:
				global $_PLUGINS;
				$_PLUGINS->loadPluginGroup( 'user', 'cbsubs.' );
				$_PLUGINS->loadPluginGroup('user/plug_cbpaidsubscriptions/plugin');

				$selectedPlans								=	array();
				foreach ($allowedPlans as $id => $p ) {
					if ( in_array( $id, $selectedPlanIds ) ) {
						/** @var cbpaidProduct[] $selectedPlans */
						$selectedPlans[(int) $id]			=	$allowedPlans[$id];
						$selectionId						=	'plan' . $id;
						$selectionName						=	'plan' . ( $selectedPlans[$id]->get( 'exclusive' ) ? 'E' : 'N' ) . '[' . (int) $selectedPlans[$id]->parent . ']';
						$selectionValue						=	$id;
						$view								=	$selectedPlans[$id]->getViewer();

						$paramsOrString						=	$view->getOptions( $selectionId, $selectionName, $selectionValue, $reason );
						if ( is_string( $paramsOrString ) ) {
							$selectedPlans					=	$paramsOrString;		// error message
							break;
						}
						$selectedPlans[(int) $id]->_options		=	$paramsOrString;
						$selectedPlans[(int) $id]->_integrations	=	new Registry( '' );
						$_PLUGINS->trigger( 'onCPayAfterPlanSelected', array( &$selectedPlans[(int) $id], &$selectedPlans[(int) $id]->_integrations , $reason ) );
						if ( $_PLUGINS->is_errors() ) {
							$selectedPlans							=	$_PLUGINS->getErrorMSG();
							break;
						}
					}
				}
				return $selectedPlans;
			}
		}
		return $selectedPlanIds;
	}
 /**
  * View for <param  type="private" class="cbpaidParamsExt" method="checkAllSubscriptions">...
  *
  * @param  string              $value                  Stored Data of Model Value associated with the element
  * @param  ParamsInterface     $pluginParams           Main settigns parameters of the plugin
  * @param  string              $name                   Name attribute
  * @param  CBSimpleXMLElement  $param                  This XML node
  * @param  string              $control_name           Name of the control
  * @param  string              $control_name_name      css id-encode of the names of the controls surrounding this node
  * @param  boolean             $view                   TRUE: view, FALSE: edit
  * @param  cbpaidTable         $modelOfData            Data of the Model corresponding to this View
  * @param  cbpaidTable[]       $modelOfDataRows        Displayed Rows if it is a table
  * @param  int                 $modelOfDataRowsNumber  Total Number of rows
  * @return null|string
  */
 public function checkAllSubscriptions($value, &$pluginParams, $name, &$param, $control_name, $control_name_name, $view, &$modelOfData, &$modelOfDataRows, &$modelOfDataRowsNumber)
 {
     $size = $param->attributes('size');
     if ($size == '') {
         $size = 100;
     }
     $cbsubsParams = cbpaidApp::settingsParams();
     if ($cbsubsParams->get('massexpirymethod') < 3) {
         $plansMgr = cbpaidPlansMgr::getInstance();
         $total = $plansMgr->checkAllSubscriptions((int) $size);
         if ($total == $size) {
             $total .= ' (' . CBPTXT::T("reload page for more mass expiries") . ')';
         }
     } else {
         $total = '0 (' . CBPTXT::T("no mass expiry from admin area, Settings-Global-Massexpiry is only by cron tasks") . ')';
     }
     $basketsMgr = cbpaidOrdersMgr::getInstance();
     $expBaskets = $basketsMgr->timeoutUnusedBaskets(null, (int) $size);
     return $total . ' / ' . $expBaskets;
 }
 /**
  * Called just before emailing each user from CB Users management backend
  *
  * @param  UserTable  $user
  * @param  string     $emailSubject
  * @param  string     $emailBody
  * @param  int        $mode
  * @param  array      $extraStrings    Entries can be filled in this function and will be used to email
  * @param  boolean    $simulationMode
  */
 public function onBeforeBackendUserEmail(&$user, &$emailSubject, &$emailBody, $mode, &$extraStrings, $simulationMode)
 {
     if (cbpaidApp::authoriseAction('cbsubs.usersubscriptionview')) {
         if ($this->filter_cbpaidplan > 0) {
             $params = cbpaidApp::settingsParams();
             $showtime = $params->get('showtime', '1') == '1';
             $plansMgr = cbpaidPlansMgr::getInstance();
             $plan = $plansMgr->loadPlan((int) $this->filter_cbpaidplan);
             $sub = $plan->loadLatestSomethingOfUser($user->id, $this->filter_cbpaidsubstate);
             $extraStrings['subscription_start_date'] = $sub ? cbFormatDate($sub->getSubscriptionDate(), 1, $showtime) : CBPTXT::T('No subscription');
             if ($plan->isProductWithExpiration()) {
                 if ($sub) {
                     $extraStrings['subscription_end_date'] = $sub->getFormattedExpirationDateText();
                 } else {
                     $extraStrings['subscription_end_date'] = CBPTXT::T('No subscription');
                 }
             }
             $extraStrings['subscription_lastrenew_date'] = $sub ? cbFormatDate($sub->getLastRenewDate(), 1, $showtime) : CBPTXT::T('No subscription');
         }
     }
 }
 /**
  * Used by XML for Backend:
  *
  * Maps array of arrays to an array of new objects of the corresponding class for each row
  *
  * @param  array|int  $resultsArray   array of a row of database to convert | int id of row to load
  * @return cbpaidProduct
  */
 public static function productObjects($resultsArray)
 {
     $plansMgr = cbpaidPlansMgr::getInstance();
     $objectsArray = $plansMgr->getObjects($resultsArray);
     return $objectsArray;
 }
Esempio n. 7
0
	/**
	 * loads the plan corresponding to this subscription into internal variable
	 *
	 * @return void
	 */
	protected function loadPlan( ) {
		$plansMgr		=&	cbpaidPlansMgr::getInstance();
		$this->_plan	=&	$plansMgr->loadPlan( $this->plan_id );
	}
	/**
	 * WARNING: UNCHECKED ACCESS! On purpose unchecked access for M2M operations
	 * Generates the HTML to display for a specific component-like page for the tab. WARNING: unchecked access !
	 * @param  TabTable|null  $tab       the tab database entry
	 * @param  UserTable      $user      the user being displayed
	 * @param  int            $ui        1 for front-end, 2 for back-end
	 * @param  array          $postdata  _POST data for saving edited tab content as generated with getEditTab
	 * @return mixed                     either string HTML for tab content, or false if ErrorMSG generated
	 */
	public function getTabComponent( /** @noinspection PhpUnusedParameterInspection */ $tab, $user, $ui, $postdata ) {
		global $_CB_database, $_CB_framework, $_POST;

		$return								=	'';
		$paid								=	false;

		$oldignoreuserabort = ignore_user_abort(true);

		$allowHumanHtmlOutput				=	true;			// this will be reverted in case of M2M server-to-server notifications

		$act								=	$this->base->_getReqParam( 'act' );
		$actPosted							=	isset($_POST[$this->base->_getPagingParamName('act')]);

		if ( $act === null ) {
			$act							=	$this->base->input( 'act', null, GetterInterface::COMMAND );
			$actPosted						=	$this->base->input( 'post/act', null, GetterInterface::COMMAND ) !== null;
		}

		$post_user_id						=	(int) cbGetParam( $_GET, 'user', 0 );

		if ( $actPosted && ( $post_user_id > 0 ) ) {
			$access							=	false;
			$myId							=	$_CB_framework->myId();
			if ( is_object( $user ) ) {
				if ( $myId == 0 ) {
					if ( in_array( $act, array( 'saveeditinvoiceaddress', 'saveeditbasketintegration', 'showbskt' ) ) ) {
						$access				=	true;
					} else {
						$paidsubsManager	=&	cbpaidSubscriptionsMgr::getInstance();
						if ( ! $paidsubsManager->checkExpireMe( __FUNCTION__, $user->id, false ) ) {
							// expired subscriptions: we will allow limited access to:
							if ( in_array( $act, array( 'upgrade', 'pay', 'reactivate', 'resubscribe', 'display_subscriptions' ) ) ) {
								$access		=	true;
							}
						}
					}
				} else {
					if ( ( $ui == 1 && ( $user->id == $myId ) )
						||	 ( cbpaidApp::authoriseAction( 'cbsubs.usersubscriptionmanage' ) ) ) {
						$access				=	true;
					}
				}
			} else {
				$return						=	CBPTXT::T("User does not exist") . '.';
			}
			if ( ! $access ) {
				$return						.=	'<br />' . CBPTXT::T("Not authorized action") . '.';
				return $return;
			}

			cbSpoofCheck( 'plugin' );		// anti-spoofing check


			// renew or upgrade subscription payment form:
			$params							=	$this->params;
			$now							=	$_CB_framework->now();
			$subscriptionsGUI				=	new cbpaidControllerUI();
			$subscriptionIds				=	$subscriptionsGUI->getEditPostedBoxes( 'id' );

			if ( $subscriptionIds == array( 0 ) ) {
				$subscriptionIds			=	array();
			}
			if ( $post_user_id && ( $user->id == $post_user_id ) ) {
				outputCbTemplate();
				$this->base->outputRegTemplate();
				outputCbJs();
				switch ( $act ) {
					case 'upgrade':		// upgrade an existing subscription
						// display basket and payment buttons or redirect for payment depending if multiple payment choices or intro text present:
						$chosenPlans		=	$subscriptionsGUI->getAndCheckChosenUpgradePlans( $postdata, $user, $now );
						if ( ( ! is_array( $chosenPlans ) ) || ( count( $chosenPlans ) == 0 ) ) {
							$subTxt			=	CBPTXT::T( $params->get( 'subscription_name', 'subscription' ) );
							$return			.=	( is_string( $chosenPlans ) ? $chosenPlans . '<br />' : '' )
								.	sprintf( CBPTXT::Th("Please press back button and select the %s plan to which you would like to upgrade."), $subTxt );
							break;
						}
						$introText			=	CBPTXT::Th( $params->get( 'intro_text_upgrade', null ) );
						//TBD: check if already exists (reload protection):
						$paymentBasket		=	cbpaidControllerOrder::createSubscriptionsAndPayment( $user, $chosenPlans, $postdata, $subscriptionIds, null, 'R', CBPTXT::T("Upgrade"), 'U' );
						if ( is_object( $paymentBasket ) ) {
							$return			=	cbpaidControllerOrder::showBasketForPayment( $user, $paymentBasket, $introText );
						} else {
							$return			=	$paymentBasket;		// show messages as nothing to pay.
						}
						break;
					case 'pay':			// pay for an unpaid subscription
						// display basket and payment buttons or redirect for payment depending if multiple payment choices or intro text present:
						$plan				=	$this->base->_getReqParam( 'plan' );
						if ( ( ! $plan ) || ( ! isset( $subscriptionIds[$plan] ) ) || ( ! $subscriptionIds[$plan] ) ) {
							$subTxt			=	CBPTXT::T( $params->get( 'subscription_name', 'subscription' ) );
							$return			.=	sprintf( CBPTXT::Th("Please press back button and select a %s plan."), $subTxt );
							break;
						}
						$plansMgr			=&	cbpaidPlansMgr::getInstance();
						$chosenPlans		=	array();
						$chosenPlans[(int) $plan]		=	$plansMgr->loadPlan( (int) $plan );
						$introText			=	CBPTXT::Th( $params->get( 'intro_text', null ) );
						$paymentStatus		=	null;
						$return				=	cbpaidControllerOrder::showPaymentForm( $user, $chosenPlans, $introText, $subscriptionIds, $paymentStatus );
						break;
					case 'renew':		// renew a still valid subscription
					case 'reactivate':	// reactivate an expired subscription
					case 'resubscribe':	// resubscribe a cancelled subscription
						// display basket and payment buttons or redirect for payment depending if multiple payment choices or intro text present:
						$plan				=	$this->base->_getReqParam( 'plan' );
						if ( ( ! $plan ) || ( ! isset( $subscriptionIds[$plan] ) ) || ( ! $subscriptionIds[$plan] ) ) {
							$subTxt			=	CBPTXT::T( $params->get( 'subscription_name', 'subscription' ) );
							$return			.=	sprintf( CBPTXT::Th("Please press back button and select a %s plan."), $subTxt );
							break;
						}
						$plansMgr			=&	cbpaidPlansMgr::getInstance();
						$chosenPlans		=	array();
						$chosenPlans[(int) $plan]		=	$plansMgr->loadPlan( (int) $plan );

						$paidSomethingMgr	=&	cbpaidSomethingMgr::getInstance();
						$subscription		=	$paidSomethingMgr->loadSomething( $subscriptionIds[$plan][0], $subscriptionIds[$plan][1] );
						global $_PLUGINS;
						$_PLUGINS->loadPluginGroup( 'user', 'cbsubs.' );
						$_PLUGINS->loadPluginGroup('user/plug_cbpaidsubscriptions/plugin');
						$_PLUGINS->trigger( 'onCPayAfterPlanRenewalSelected', array( &$chosenPlans[(int) $plan], &$subscription, $act ) );
						if ( $_PLUGINS->is_errors() ) {
							$return			.=	$_PLUGINS->getErrorMSG();
							break;
						}

						$introText			=	CBPTXT::Th( $params->get( 'intro_text_renew', null ) );
						//TBD: check if already exists (reload protection):
						$paymentBasket		=	cbpaidControllerOrder::createSubscriptionsAndPayment( $user, $chosenPlans, $postdata, $subscriptionIds, null, null, CBPTXT::T("Renew"), 'R' );
						if ( is_object( $paymentBasket ) ) {
							$return			=	cbpaidControllerOrder::showBasketForPayment( $user, $paymentBasket, $introText );
						} else {
							$return			=	$paymentBasket;		// show messages as nothing to pay.
						}
						break;
					case 'unsubscribe':	// request to unsubscribe an active subscription
						// display unsubscribe confirmation form:
						$plan				=	$this->base->_getReqParam( 'plan' );
						if ( ( ! $plan ) || ( ! isset( $subscriptionIds[$plan] ) ) || ( ! $subscriptionIds[$plan] ) ) {
							$subTxt			=	CBPTXT::T( $params->get( 'subscription_name', 'subscription' ) );
							$return			.=	sprintf( CBPTXT::Th("Please press back button and select a %s plan."), $subTxt );
							break;
						}
						$introText			=	CBPTXT::Th( $params->get( 'unsubscribe_intro_text' , null ) );
						$return				=	$subscriptionsGUI->showUnsubscribeForm( $user, $introText, (int) $plan, (int) $subscriptionIds[$plan][1] );

						break;
					case 'confirm_unsubscribe':	// confirm previous request to unsubscribe an active subscription
						// unsubscribe confirmed:
						$plan				=	$this->base->_getReqParam( 'plan' );
						if ( ( ! $plan ) || ( ! isset( $subscriptionIds[$plan] ) ) || ( ! $subscriptionIds[$plan] ) ) {
							$subTxt			=	CBPTXT::T( $params->get( 'subscription_name', 'subscription' ) );
							$return			.=	sprintf( CBPTXT::Th("Please press back button and select a %s plan."), $subTxt );
							break;
						}
						if ( ( $plan ) && ( count( $subscriptionIds ) == 1 ) ) {
							$unsubscribeConfText =	CBPTXT::Th( $params->get( 'unsubscribe_confirmation_text', null ) );
							$return			=	cbpaidControllerOrder::doUnsubscribeConfirm( $user, $unsubscribeConfText, (int) $plan, (int) $subscriptionIds[$plan][1] );
						}
						break;
					case 'display_subscriptions':
						// unsubscribe cancelled: display subscriptions:
						$return				=	$this->base->displayUserTab( $user );
						break;
					case 'showinvoice':
						// shows a particular user invoice:
						if ( $params->get( 'show_invoices', 1 ) ) {
							$invoiceNo		=	$this->base->_getReqParam( 'invoice' );
							$return			=	$this->showInvoice( $invoiceNo, $user );
						}
						break;
					case 'saveeditinvoiceaddress':
					case 'editinvoiceaddress':		// this is the case of reload of invoicing address
						$invoicingAddressQuery		=	$params->get( 'invoicing_address_query' );
						if ( $invoicingAddressQuery > 0 ) {
							$basketId				=	$this->base->_getReqParam( 'basket', 0 );
							$hashToCheck			=	$this->base->_getReqParam( 'bck' );
							$paymentBasket			=	new cbpaidPaymentBasket( $_CB_database );
							if ( $basketId && $paymentBasket->load( (int) $basketId ) && ( $paymentBasket->payment_status == 'NotInitiated' ) && ( $hashToCheck == $paymentBasket->checkHashUser( $hashToCheck ) ) ) {
								if ( ( $act == 'saveeditinvoiceaddress' ) && $this->base->input( 'actbutton', null, GetterInterface::COMMAND ) ) {				// IE7-8 will return text instead of value and IE6 will return button all the time http://www.dev-archive.net/articles/forms/multiple-submit-buttons.html
									$return			=	$paymentBasket->saveInvoicingAddressForm( $user );
									if ( $return === null ) {
										$paymentBasket->storeInvoicingDefaultAddress();
										$introText	=	CBPTXT::Th( $params->get( 'intro_text', null ) );
										$return		.=	cbpaidControllerOrder::showBasketForPayment( $user, $paymentBasket, $introText );
									}
								} else {
									// invoice has reloaded itself (e.g. for country change):
									$return			=	$paymentBasket->renderInvoicingAddressForm( $user );
								}
							} else {
								$this->base->_setErrorMSG( CBPTXT::T("No unpaid payment basket found.") );
							}
						} else {
							$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
						}

						break;
					case 'saverecordpayment':
					case 'editrecordpayment':		// this is the case of reload of the form
						$basketId				=	$this->base->_getReqParam( 'basket', 0 );
						$hashToCheck			=	$this->base->_getReqParam( 'bck' );
						$paymentBasket			=	new cbpaidPaymentBasket( $_CB_database );
						if ( $basketId && $paymentBasket->load( (int) $basketId ) && ( $paymentBasket->payment_status != 'Completed' ) && ( $hashToCheck == $paymentBasket->checkHashUser( $hashToCheck ) ) ) {
							if ( $paymentBasket->authoriseAction( 'cbsubs.recordpayments' ) ) {
								if ( ( $act == 'saverecordpayment' ) && $this->base->input( 'actbutton', null, GetterInterface::COMMAND ) ) {				// IE7-8 will return text instead of value and IE6 will return button all the time http://www.dev-archive.net/articles/forms/multiple-submit-buttons.html
									$return			=	cbpaidRecordBasketPayment::saveRecordPayment( $paymentBasket->id );
									if ( $return === null ) {
										$return		.=	CBPTXT::T("Payment recorded.")
											.	' <a href="' . $_CB_framework->userProfileUrl( $paymentBasket->user_id, true ) . '">'
											.	CBPTXT::Th("View user profile")
											.	'</a>';
									}
								} else {
									// invoice has reloaded itself (e.g. for country change):
									$return			=	cbpaidRecordBasketPayment::displayRecordPaymentForm( $paymentBasket->id );
								}
							} else {
								$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
							}
						} else {
							$this->base->_setErrorMSG( CBPTXT::T("No unpaid payment basket found.") );
						}

						break;

					default:
						cbNotAuth();
						return '';
						break;
				}
			}

		} elseif ( $this->base->_getReqParam( 'account' ) && ( ( (int) cbGetParam( $_GET, 'user', 0 ) ) > 0 ) ) {

			$account					=	$this->base->_getReqParam( 'account' );
			$post_user_id				=	(int) cbGetParam( $_GET, 'user', 0 );
			$user						=	CBuser::getUserDataInstance( (int) $post_user_id );
			if ( $user->id ) {
				if ( isset( $_SESSION['cbsubs']['expireduser'] ) && ( $_SESSION['cbsubs']['expireduser'] == $user->id ) ) {
					// expired subscriptions of membership: show possibilities:
					$subscriptionsGUI		=	new cbpaidControllerUI();

					outputCbTemplate();
					$this->base->outputRegTemplate();
					outputCbJs();

					switch ( $account ) {
						case 'expired':
							$paidsubsManager		=&	cbpaidSubscriptionsMgr::getInstance();
							if ( ! $paidsubsManager->checkExpireMe( __FUNCTION__, $user->id, false ) ) {
								// no valid membership:
								$return				=	$subscriptionsGUI->getShowSubscriptionUpgrades( $user, true );
							}

							break;
						default:
							break;
					}
				} else {
					$return					=	CBPTXT::Th("Browser cookies must be enabled.");
				}
			}

		} elseif ( in_array( $act, array( 'setbsktpmtmeth', 'setbsktcurrency' ) ) ) {

			cbSpoofCheck( 'plugin' );		// anti-spoofing check
			$params							=	$this->params;
			outputCbTemplate();
			$this->base->outputRegTemplate();
			outputCbJs();

			$basketId				=	$this->base->_getReqParam( 'bskt', 0 );
			$hashToCheck			=	$this->base->_getReqParam( 'bck' );

			$paymentBasket			=	new cbpaidPaymentBasket( $_CB_database );
			if ( $basketId && $paymentBasket->load( (int) $basketId ) && ( $paymentBasket->payment_status == 'NotInitiated' ) && ( $hashToCheck == $paymentBasket->checkHashUser( $hashToCheck ) ) ) {

				switch ( $act ) {
					case 'setbsktpmtmeth':
						if ( $params->get( 'payment_method_selection_type' ) == 'radios' ) {
							$chosenPaymentMethod	=	cbGetParam( $_POST, 'payment_method' );
							$introText				=	CBPTXT::Th( $params->get( 'intro_text', null ) );
							$return					=	$paymentBasket->saveBasketPaymentMethodForm( $user, $introText, $chosenPaymentMethod );
							if ( $return === null ) {
								$return				.=	cbpaidControllerOrder::showBasketForPayment( $user, $paymentBasket, $introText );
							}
						} else {
							$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
						}
						break;

					case 'setbsktcurrency':
						if ( $params->get( 'allow_select_currency', '0' ) ) {
							$newCurrency			=	cbGetParam( $_POST, 'currency' );
							if ( $newCurrency ) {
								if ( in_array( $newCurrency, cbpaidControllerPaychoices::getInstance()->getAllCurrencies() ) ) {
									$paymentBasket->changeCurrency( $newCurrency );
								} else {
									$this->base->_setErrorMSG( CBPTXT::T("This currency is not allowed") );
								}
								$introText			=	CBPTXT::Th( $params->get( 'intro_text', null ) );
								$return				.=	cbpaidControllerOrder::showBasketForPayment( $user, $paymentBasket, $introText );
							} else {
								$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
							}
						} else {
							$this->base->_setErrorMSG( CBPTXT::T("Changes of currency of orders are not authorized") );
						}
						break;

					default:
						cbNotAuth();
						return '';
						break;
				}

			} else {
				$this->base->_setErrorMSG( CBPTXT::T("No unpaid payment basket found.") );
			}

		} elseif ( $act == 'cbsubsclass' ) {

			$pluginName						=	$this->base->_getReqParam( 'class' );
			if ( preg_match( '/^[a-z]+$/', $pluginName ) ) {
				$element					=	'cbsubs.' . $pluginName;
				global $_PLUGINS;
				$_PLUGINS->loadPluginGroup('user/plug_cbpaidsubscriptions/plugin', $element );
				$loadedPlugins				=&	$_PLUGINS->getLoadedPluginGroup( 'user/plug_cbpaidsubscriptions/plugin' );
				$params						=	$this->params;
				foreach ($loadedPlugins as $p ) {
					if ( $p->element == $element ) {
						$pluginId			=	$p->id;
						$args				=	array( &$user, &$params, &$postdata );
						/** @noinspection PhpUndefinedCallbackInspection */
						$return				=	$_PLUGINS->call( $pluginId, 'executeTask', 'getcbsubs' . $pluginName . 'Tab', $args, null );
						break;
					}
				}
			}

		} elseif ( $act && ( ! in_array( $act, array( 'showbskt', 'setbsktpmtmeth' ) ) ) && ( ( (int) cbGetParam( $_GET, 'user', 0 ) ) > 0 ) ) {

			if ( ! is_object( $user ) ) {
				return CBPTXT::T("User does not exist.");
			}

			$params								=	$this->params;

			$post_user_id						=	(int) cbGetParam( $_GET, 'user', 0 );
			if ( $post_user_id && ( ( $user->id == $post_user_id ) || ( cbpaidApp::authoriseAction( 'cbsubs.usersubscriptionmanage' ) ) ) ) {

				outputCbTemplate();
				$this->base->outputRegTemplate();
				outputCbJs();

				switch ( $act ) {
					case 'showinvoice':
						if ( $params->get( 'show_invoices', 1 ) ) {
							$invoiceNo			=	$this->base->_getReqParam( 'invoice', 0 );
							// This also checks for cbpaidApp::authoriseAction on cbsubs.sales or cbsubs.financial access permissions:
							$return				=	$this->showInvoice( $invoiceNo, $user );
						} else {
							$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
						}
						break;
					case 'showinvoiceslist':
						$showInvoices			=	$params->get( 'show_invoices', 1 );
						$invoicesShowPeriod		=	$params->get( 'invoices_show_period', '0000-06-00 00:00:00' );
						$itsmyself				=	( $_CB_framework->myId() == $user->id );
						if ( $showInvoices && ( $itsmyself || ( cbpaidApp::authoriseAction( 'cbsubs.sales' ) || cbpaidApp::authoriseAction( 'cbsubs.financial' ) ) ) ) {
							$subscriptionsGUI	=	new cbpaidControllerUI();
							$invoices			=	$this->_getInvoices( $user, $invoicesShowPeriod, false );

							if ( $invoicesShowPeriod && ( $invoicesShowPeriod != '0000-00-00 00:00:00' ) ) {
								$cbpaidTimes	=&	cbpaidTimes::getInstance();
								$periodText		=	$cbpaidTimes->renderPeriod( $invoicesShowPeriod, 1, false );
							} else {
								$periodText		=	'';
							}
							$return				.=	$subscriptionsGUI->showInvoicesList( $invoices, $user, $itsmyself, $periodText );
						} else {
							$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
						}
						break;
					case 'editinvoiceaddress':			// this is the case of the initial edit address link
						if ( $params->get( 'invoicing_address_query' ) > 0 ) {
							$basketId			=	$this->base->_getReqParam( 'basket', 0 );
							$hashToCheck		=	$this->base->_getReqParam( 'bck' );
							$paymentBasket		=	new cbpaidPaymentBasket( $_CB_database );
							if ( $basketId && $paymentBasket->load( (int) $basketId ) && ( $paymentBasket->payment_status == 'NotInitiated' ) && ( $hashToCheck == $paymentBasket->checkHashUser( $hashToCheck ) ) ) {
								$return			=	$paymentBasket->renderInvoicingAddressForm( $user );
							} else {
								$this->base->_setErrorMSG( CBPTXT::T("No unpaid payment basket found.") );
							}
						} else {
							$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
						}
						break;
					case 'showrecordpayment':
						$paymentBasketId		=	$this->base->_getReqParam( 'recordpayment', 0 );
						if ( $paymentBasketId ) {
							$paymentBasket		=	new cbpaidPaymentBasket();
							if ( $paymentBasket->load( (int) $paymentBasketId ) && $paymentBasket->authoriseAction( 'cbsubs.recordpayments' ) ) {
								// Auto-loads class: and authorization is checked inside:
								$return				=	cbpaidRecordBasketPayment::displayRecordPaymentForm( $paymentBasketId );
							} else {
								$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
							}
						} else {
							$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
						}
						break;
					default:
						$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
						break;
				}
			}

		} elseif ( $act == 'showbskt' && ( ( ( (int) cbGetParam( $_GET, 'user', 0 ) ) > 0 ) ) || ( $this->base->_getReqParam( 'bskt', 0 ) && $this->base->_getReqParam( 'bck' ) ) ) {

			$basketId			=	$this->base->_getReqParam( 'bskt', 0 );
			$hashToCheck		=	$this->base->_getReqParam( 'bck' );

			// Basket integrations saving/editing url:
			if ( in_array($act, array( 'saveeditbasketintegration', 'editbasketintegration' ) ) ) {		// edit is the case of edit or reload of integration form
				$integration			=	$this->base->_getReqParam( 'integration' );
				$paymentBasket			=	new cbpaidPaymentBasket( $_CB_database );
				if ( preg_match( '/^[a-z]+$/', $integration ) && $basketId && $paymentBasket->load( (int) $basketId ) && ( $paymentBasket->payment_status == 'NotInitiated' ) && ( $hashToCheck == $paymentBasket->checkHashUser( $hashToCheck ) ) ) {
					global $_PLUGINS;
					$element			=	'cbsubs.' . $integration;
					$_PLUGINS->loadPluginGroup('user/plug_cbpaidsubscriptions/plugin', $element );
					$results		=	$_PLUGINS->trigger( 'onCPayEditBasketIntegration', array( $integration, $act, &$paymentBasket ) );
					$return			=	null;
					foreach ( $results as $r ) {
						if ( $r ) {
							$return	.=	$r;
						}
					}
					if ( $act == 'editbasketintegration' ) {
						if ( $return !== null ) {
							return $return;
						}
					}
				} else {
					$this->base->_setErrorMSG( CBPTXT::T("No unpaid payment basket found.") );
				}
			}


			$post_user_id							=	(int) cbGetParam( $_GET, 'user', 0 );
			if ( $post_user_id && ! ( ( is_object( $user ) && ( $user->id == $post_user_id ) ) ) ) {
				return CBPTXT::T("User does not exist.");
			}

			outputCbTemplate();
			$this->base->outputRegTemplate();
			outputCbJs();
			$params				=	$this->params;

			$paymentBasket		=	new cbpaidPaymentBasket( $_CB_database );
			if ( $basketId && $paymentBasket->load( (int) $basketId ) && ( $paymentBasket->payment_status == 'NotInitiated' ) ) {
				if ( ! $post_user_id ) {
					$cbUser		=&	CBuser::getInstance( (int) $paymentBasket->user_id );
					$user		=&	$cbUser->getUserData();
					if ( ( ! is_object( $user ) ) || ! $user->id ) {
						return CBPTXT::T("User does not exist.");
					}
				}
				if ( ( $hashToCheck && $hashToCheck == $paymentBasket->checkHashUser( $hashToCheck ) )
					|| ( ( ! $hashToCheck ) && $paymentBasket->user_id && ( $paymentBasket->user_id == $_CB_framework->myId() ) ) )
				{
					$introText	=	CBPTXT::Th( $params->get( 'intro_text', null ) );
					$return		.=	cbpaidControllerOrder::showBasketForPayment( $user, $paymentBasket, $introText );
				} else {
					$this->base->_setErrorMSG( CBPTXT::T("Not authorized action") );
				}
			} else {
				$this->base->_setErrorMSG( CBPTXT::T("No unpaid payment basket found.") );
			}

			//	} elseif ( isset($_REQUEST['result']) && isset( $_REQUEST['user'] ) && ( $_REQUEST['user'] > 0 ) ) {
		} elseif ( isset($_REQUEST['result']) && ( $this->base->_getReqParam('method') || $this->base->_getReqParam('gacctno') ) ) {

			// don't check license here so initiated payments can complete !

			$params				=	$this->params;

			$method				=	$this->base->_getReqParam('method');

			if ( ( $method == 'freetrial' ) || ( $method == 'cancelpay' ) ) {
				cbpaidApp::import( 'processors.freetrial.freetrial' );
				cbpaidApp::import( 'processors.cancelpay.cancelpay' );
				$className		=	'cbpaidGatewayAccount' . $method;
				$payAccount		=	new $className( $_CB_database );
			} else {
				$gateAccount	=	$this->base->_getReqParam('gacctno');

				$payAccount		=	cbpaidControllerPaychoices::getInstance()->getPayAccount( $gateAccount );
				if ( ! $payAccount ) {
					return '';
				}
			}
			$payClass			=	$payAccount->getPayMean();
			$paymentBasket		=	new cbpaidPaymentBasket($_CB_database);

			if ( $payClass && ( ( $this->base->_getReqParam('method') == $payClass->getPayName() ) || ( $this->base->_getReqParam('method') == null ) ) && $payClass->hashPdtBackCheck( $this->base->_getReqParam('pdtback') ) ) {
				// output for resultNotification: $return and $allowHumanHtmlOutput
				$return			=	$payClass->resultNotification( $paymentBasket, $postdata, $allowHumanHtmlOutput );
			}

			if ( ! $paymentBasket->id ) {
				$this->base->_setErrorMSG(CBPTXT::T("No suitable basket found."));
			} else {
				$user			=&	CBuser::getUserDataInstance( (int) $paymentBasket->user_id );

				if ( $paymentBasket->payment_status == 'RegistrationCancelled' ) {
					// registration cancelled: delete payment basket and delete user after checking that he is not yet active:
					if ( $paymentBasket->load( (int) $paymentBasket->id ) ) {
						if ( $payClass->hashPdtBackCheck( $this->base->_getReqParam('pdtback') ) && ( ( $paymentBasket->payment_status == 'NotInitiated' ) || ( ( $paymentBasket->payment_status === 'Pending' ) && ( $paymentBasket->payment_method === 'offline' ) ) ) ) {

							$notification						=	new cbpaidPaymentNotification();
							$notification->initNotification( $payClass, 0, 'P', $paymentBasket->payment_status, $paymentBasket->payment_type, null, $_CB_framework->now(), $paymentBasket->charset );

							$payClass->updatePaymentStatus( $paymentBasket, 'web_accept', 'RegistrationCancelled', $notification, 0, 0, 0, true );

							// This is a notification or a return to site after payment, we want to log any error happening in third-party stuff in case:
							cbpaidErrorHandler::keepTurnedOn();
						}
					}
				}
				if ( $allowHumanHtmlOutput ) {
					// If frontend, we display result, otherwise, If Server-to-server notification: do not display any additional text here !
					switch ( $paymentBasket->payment_status ) {
						case 'Completed':
							// PayPal recommends including the following information with the confirmation:
							// - Item name
							// - Amount paid
							// - Payer email
							// - Shipping address
							$newMsg = sprintf( CBPTXT::Th("Thank you for your payment of %s for the %s %s."), $paymentBasket->renderPrice(),
								$paymentBasket->item_name,
								htmlspecialchars( $payClass->getTxtUsingAccount( $paymentBasket ) ) )		// ' using your paypal account ' . $paymentBasket->payer_email
								. ' ' . $payClass->getTxtNextStep( $paymentBasket );
							// . "Your transaction has been completed, and a receipt for your purchase has been emailed to you by PayPal. "
							// . "You may log into your account at www.paypal.com to view details of this transaction.</p>\n";
							if ( $params->get( 'show_invoices' ) ) {
								$itsmyself			=	( $_CB_framework->myId() == $user->id );
								$subscriptionsGUI	=	new cbpaidControllerUI();
								$newMsg				.=	'<p id="cbregviewinvoicelink">'
									.	$subscriptionsGUI->getInvoiceShowAhtml( $paymentBasket, $user, $itsmyself, CBPTXT::Th("View printable invoice") )
									.	'</p>'
								;
							}
							$paid = true;
							break;
						case 'Pending':
							$newMsg = sprintf( CBPTXT::Th("Thank you for initiating the payment of %s for the %s %s."), $paymentBasket->renderPrice(),
								$paymentBasket->item_name,
								htmlspecialchars( $payClass->getTxtUsingAccount( $paymentBasket ) ) )		// ' using your paypal account ' . $paymentBasket->payer_email
								. ' ' . $payClass->getTxtNextStep( $paymentBasket );
							// . "Your payment is currently being processed. "
							// . "A receipt for your purchase will be emailed to you by PayPal once processing is complete. "
							// . "You may log into your account at www.paypal.com to view status details of this transaction.</p>\n";
							break;
						case 'RegistrationCancelled':
							$newMsg		=	$payClass->getTxtNextStep( $paymentBasket );
							break;
						case 'FreeTrial':
							$newMsg = CBPTXT::Th("Thank you for subscribing to") . ' ' . $paymentBasket->item_name . '.'
								. ' ' . $payClass->getTxtNextStep( $paymentBasket );
							break;
						case null:
							$newMsg	= CBPTXT::T("Payment basket does not exist.");
							break;
						case 'NotInitiated':
							$newMsg	=	'';
							break;
						case 'RedisplayOriginalBasket':
							if ( $paymentBasket->load( (int) $paymentBasket->id ) && ( $paymentBasket->payment_status == 'NotInitiated' ) ) {
								$introText		=	CBPTXT::Th( $params->get( 'intro_text', null ) );
								$return			.=	cbpaidControllerOrder::showBasketForPayment( $user, $paymentBasket, $introText );
							}
							$newMsg				=	'';
							break;
						case 'Processed':
						case 'Denied':
						case 'Reversed':
						case 'Refunded':
						case 'Partially-Refunded':
						default:
							$newMsg = $payClass->getTxtNextStep( $paymentBasket );
							// "<p>Your transaction is not cleared and has currently following status: <strong>" . $paymentBasket->payment_status . ".</strong></p>"
							// . "<p>You may log into your account at www.paypal.com to view status details of this transaction.</p>";
							break;
					}

					if ( in_array( $paymentBasket->payment_status, array( 'Completed', 'Pending' ) ) ) {
						$subscriptions = $paymentBasket->getSubscriptions();
						$texts		=	array();			// avoid repeating several times identical texts:
						if ( is_array( $subscriptions ) ) {
							foreach ( $subscriptions as $sub ) {
								/** @var $sub cbpaidSomething */
								$thankYouParam		=	( $paymentBasket->payment_status == 'Completed') ? 'thankyoutextcompleted' : 'thankyoutextpending';
								$thankYouText		=	$sub->getPersonalized( $thankYouParam, true );
								if ( $thankYouText && ! in_array( $thankYouText, $texts ) ) {
									$texts[]		=	$thankYouText;
									if ( strpos( $thankYouText, '<' ) === false ) {
										$msgTag		=	'p';
									} else {
										$msgTag		=	'div';
									}
									$newMsg			.=	'<' . $msgTag . ' class="cbregThanks" id="cbregThanks' . $sub->plan_id . '">' . $thankYouText . '</' . $msgTag . ">\n";
								}
							}
						}
					}
					if ( $newMsg ) {
						$return .= '<div>' . $newMsg . '</div>';
					}

					if ( $paid && ( $_CB_framework->myId() < 1 ) && ( cbGetParam( $_REQUEST, 'user', 0 ) == $paymentBasket->user_id ) ) {
						$_CB_database->setQuery( "SELECT * FROM #__comprofiler c, #__users u WHERE c.id=u.id AND c.id=".(int) $paymentBasket->user_id );
						if ( $_CB_database->loadObject( $user ) && ( $user->lastvisitDate == '0000-00-00 00:00:00' ) ) {
							$return = '<p>' . implode( '', getActivationMessage( $user, 'UserRegistration' ) ) . '</p>' . $return;
						}
					}
				}
			}

		} else {
			cbNotAuth();
			return ' ' . CBPTXT::T("No result.");
		}

		if ( $allowHumanHtmlOutput ) {
			$allErrorMsgs	=	$this->base->getErrorMSG( '</div><div class="error">' );
			if ( $allErrorMsgs ) {
				$errorMsg	=	'<div class="error">' . $allErrorMsgs . '</div>';
			} else {
				$errorMsg	=	null;
			}

			/** @var string $return */
			if ( ( $return == '' ) && ( $errorMsg ) ) {
				$this->base->outputRegTemplate();
				$return		=	$errorMsg . '<br /><br />' . $return;
				$return		.=	cbpaidControllerOrder::showBasketForPayment( $user, $paymentBasket, '' );
			} else {
				$return		=	$errorMsg . $return;
			}
		}

		if ( ! is_null( $oldignoreuserabort ) ) {
			ignore_user_abort($oldignoreuserabort);
		}

		return $return;
	}
 /**
  * WARNING: UNCHECKED ACCESS! On purpose unchecked access for M2M operations
  * Generates the HTML to display for a specific component-like page for the tab. WARNING: unchecked access !
  * @param  null       $tab
  * @param  UserTable  $user      the user being displayed
  * @param  int        $ui        1 for front-end, 2 for back-end
  * @param  array      $postdata  _POST data for saving edited tab content as generated with getEditTab
  * @return mixed                 either string HTML for tab content, or false if ErrorMSG generated
  */
 public function getCBpluginComponent($tab, &$user, $ui, &$postdata)
 {
     global $_CB_framework, $ueConfig, $_GET;
     cbpaidErrorHandler::on();
     $result = null;
     $do = cbGetParam($_GET, 'do');
     switch ($do) {
         case null:
             $return = $this->getTabComponent($tab, $user, $ui, $postdata);
             cbpaidErrorHandler::keepTurnedOn();
             break;
         case 'display_subscriptions':
             if ($user && $user->id && $_CB_framework->myId()) {
                 $regTitle = strip_tags(CBPTXT::T($this->params->get('regTitle', "Subscriptions")));
                 outputCbTemplate();
                 $_CB_framework->setPageTitle($regTitle);
                 $_CB_framework->appendPathWay($regTitle);
                 $pre = '<div class="cbPageOuter"><div class="cbPageInner">';
                 $post = '</div></div><div class="cbClr"> </div>';
                 $return = $pre . $this->displayUserTab($user) . $post;
             } else {
                 if ($_CB_framework->getCfg('allowUserRegistration') == '0' && (!isset($ueConfig['reg_admin_allowcbregistration']) || $ueConfig['reg_admin_allowcbregistration'] != '1')) {
                     $return = _UE_NOT_AUTHORIZED . '<br />' . _UE_DO_LOGIN;
                 } else {
                     /*
                     $registrationUrl	=	cbSef( 'index.php?option=com_comprofiler&task=registers' );
                     $registrationLink	=	'<a href="' . $registrationUrl . '">' . _UE_REGISTER . '</a>';
                     $loginRegisterText	=	sprintf( CBPTXT::Th("Please login or %s"), $registrationLink );
                     $return				=	_UE_NOT_AUTHORIZED . '<br /><br />' . $loginRegisterText;
                     */
                     $accessPlans = null;
                     $return = cbpaidControllerOffer::displaySpecificPlans($accessPlans, null, $user, '');
                 }
             }
             break;
         case 'accessdenied':
             $params = cbpaidApp::settingsParams();
             $accessRedirectLink = $params->get('subscriptionNeededRedirectLink');
             if ($accessRedirectLink) {
                 $textMessage = $params->get('subscriptionNeededText', "A membership is needed for access.");
                 $return = null;
                 cbRedirect(cbSef($accessRedirectLink, false), CBPTXT::T($textMessage), 'warning');
             } else {
                 /** @noinspection PhpIncludeInspection */
                 include_once cbpaidApp::getAbsoluteFilePath('plugin/cbsubscontent/cbsubs.content_deniedview.php');
                 $accessDeniedView = new cbpaidContentAccessDeniedView();
                 $return = $accessDeniedView->display($user, $this);
             }
             break;
         case 'displayplans':
             $plansParam = cbGetParam($_GET, 'plans');
             $plans = null;
             $preselect = null;
             if ($plansParam) {
                 $plansParam = explode('-', $plansParam);
                 foreach ($plansParam as $p) {
                     $pN = (int) $p;
                     if ($pN) {
                         $plans[] = $pN;
                         if (substr($p, -1) == 's') {
                             $preselect[] = $pN;
                         }
                     }
                 }
             }
             if ($user === null || $user->id == $_CB_framework->myId()) {
                 $introText = CBPTXT::Th($this->params->get('plansDisplayIntroText', "We suggest subscribing to following subscriptions:"));
                 $return = cbpaidControllerOffer::displaySpecificPlans($plans, $preselect, $user, $introText);
             } else {
                 $return = _UE_NOT_AUTHORIZED;
             }
             break;
         case 'massexpire':
             // cron
             $params = cbpaidApp::settingsParams();
             $key = cbGetParam($_GET, 'key');
             if ($key && $key == md5($params->get('license_number')) && $params->get('massexpirymethod', 0) >= 2) {
                 $limit = $params->get('massexpirynumber', 100);
                 // mass-expire 100 subscriptions at a time on the way if not exipring a particular user:
                 $plansMgr = cbpaidPlansMgr::getInstance();
                 $plansMgr->checkAllSubscriptions((int) $limit);
                 $return = null;
             } else {
                 $return = CBPTXT::Th("Invalid mass-expiry link: link is in global CBSubs settings.");
             }
             break;
         case 'autopayments':
             // cron
             $params = cbpaidApp::settingsParams();
             $key = cbGetParam($_GET, 'key');
             if ($key && $key == md5($params->get('license_number'))) {
                 $limit = $params->get('massautorenewalsnumber', 100);
                 // mass-autorenew 100 subscriptions at a time:
                 $results = cbpaidOrdersMgr::getInstance()->triggerScheduledAutoRecurringPayments((int) $limit);
                 $return = implode("\r\n\r\n", $results);
                 $massrenewalemail = trim($params->get('massrenewalemail', ''));
                 if ($massrenewalemail) {
                     cbimport('cb.notification');
                     $recipients = explode(',', $massrenewalemail);
                     if ($return) {
                         $body = CBPTXT::T("CBSubs has just processed auto-recurring payments as follows:") . "\r\n\r\n" . $return . "\r\n\r\n" . CBPTXT::T("This is an automated email, do not reply.") . "\r\n\r\n";
                         comprofilerMail('', '', $recipients, CBPTXT::T("CBSubs has processed auto-recurring payments"), $body);
                     }
                 }
                 if ($params->get('massrenewaloutputincron', 1) != 1) {
                     // silence output to Cron:
                     $return = null;
                 }
             } else {
                 $return = CBPTXT::Th("Invalid auto-renewals link: link is in global CBSubs settings.");
             }
             break;
         default:
             $return = sprintf(CBPTXT::Th("No valid %s action chosen"), '"do"') . '.';
             break;
     }
     cbpaidErrorHandler::off();
     return $return;
 }
 /**
  * Gets all plans GIDs
  *
  * @param  UserTable  $user           User to check for
  * @return array                      ( $block, $gid )
  */
 protected function _allPlansGid($user)
 {
     global $_CB_framework;
     // Determine highest new $gid (0 means nothing left):
     $registeredGid = (int) $_CB_framework->acl->mapGroupNamesToValues('Registered');
     $allGids = array($registeredGid => $registeredGid);
     $plansMgr = cbpaidPlansMgr::getInstance();
     $plans = $plansMgr->loadPublishedPlans($user, true, 'any', null);
     foreach ($plans as $p) {
         $planGid = (int) $p->get('usergroup');
         if ($planGid) {
             $allGids[$planGid] = $planGid;
         }
     }
     return $allGids;
 }
 /**
  * Loads all of Something of user $user.
  *
  * @param  UserTable          $user      The user
  * @param  string             $status    Optionally the status of the something ('A'=active, 'X'=expired, and so on)
  * @return cbpaidSomething[][]
  */
 public static function getAllSomethingOfUser($user, $status = 'A')
 {
     static $somethings = array();
     $statusIndex = $status ? $status : 'ZZ';
     if (!isset($somethings[$user->id][$statusIndex])) {
         $somethings[$user->id][$statusIndex] = array();
         $plansMgr = cbpaidPlansMgr::getInstance();
         $plans = $plansMgr->loadPublishedPlans($user, true, 'any', null);
         foreach ($plans as $plan) {
             // $plan = NEW cbpaidProduct();
             if (!isset($somethings[$user->id][$statusIndex][$plan->item_type])) {
                 $somethings[$user->id][$statusIndex][$plan->item_type] = $plan->newSubscription()->loadTheseSomethingsOfUser($user->id, $status);
             }
         }
     }
     return $somethings[$user->id][$statusIndex];
 }
Esempio n. 12
0
	/**
	 * @return array
	 */
	public function plans()
	{
		$plansList					=	array();

		if ( $this->installed() ) {
			$plansMgr				=	cbpaidPlansMgr::getInstance();
			$plans					=	$plansMgr->loadPublishedPlans( null, true, 'any', null );

			if ( $plans ) {
				$plansList			=	array();

				foreach ( $plans as $k => $plan ) {
					$plansList[]	=	moscomprofilerHTML::makeOption( (string) $k, $plan->get( 'alias' ) );
				}
			}
		}

		return $plansList;
	}
	/**
	 * Creates a new (or loads an existing) subscription, and if it's non-free:
	 * Creates a payment basket if there is not already one
	 * ---- and then displays payment processing mask, button, or redirects
	 * If it's free: activates account and does not return anything.
	 *
	 * @param  UserTable           $user
	 * @param  cbpaidProduct[]     $chosenPlans              array of cbpaidProduct : Chosen plans to pay
	 * @param  array               $postdata                 $_POST array for the parameters of the subscription plans
	 * @param  array|null          $replacesSubscriptionIds  In fact: the existing one in all cases, except if new to be created.
	 * @param  array|null          $existingSubscriptionIds  In fact: the new one in case of upgrade !
	 * @param  string              $status 					 subscription status: 'R'=registered (default) , 'I'=illegal, 'A'=active, etc.
	 * @param  string              $prefixText 				 text to prefix the payment items (default: null)
	 * @param  string              $reason 					 payment reason: 'N'=new subscription (default), 'R'=renewal, 'U'=update
	 * @param  string              $payment                  'now' (default), 'free'
	 * @return cbpaidPaymentBasket|string                    object if something to pay, otherwise HTML text for message.
	 */
	public static function createSubscriptionsAndPayment( &$user, $chosenPlans, $postdata, $replacesSubscriptionIds = null, $existingSubscriptionIds = null, $status = 'R', $prefixText = null, $reason='N', $payment = 'now' ) {
		global $_CB_framework, $_CB_database;

		$subscriptionTime				=	$_CB_framework->now();

		/** @var cbpaidSomething[] $subscriptions */
		$subscriptions					=	array();
		$needToPay						=	false;

		//TBD LATER: Handle fully payment baskets as baskets, adding/replacing the content with the new items:
		$paymentBasket					=&	cbpaidPaymentBasket::getInstanceBasketOfUser( $user->id, false );			//TBD could be true to avoid old baskets ?
		if ( $paymentBasket->id ) {
			// otherwise show existing basket:
			return $paymentBasket;
		}

		if ( ! ( $chosenPlans && ( count( $chosenPlans ) > 0 ) ) ) {
			trigger_error( 'createSubscriptionsAndPayment:: called without plans chosen !', E_USER_ERROR );
		}
		// 1. add subscription records if not existing: pass 1: parents, pass 2: children:
		$pass							=	0;
		while ( ++$pass <= 2 ) {
			foreach ( $chosenPlans as $plan ) {
				$parentPlan							=	$plan->get( 'parent' );
				if ( ( ( $pass == 1 ) && ( $parentPlan == 0 ) ) || ( ( $pass == 2 ) && ( $parentPlan != 0 ) ) ) {
					$planId							=	$plan->get( 'id' );

					/* $reasonInCaseExpired			=	$reason; */
					// find replaced subscription id:
					$replacesSubId					=	null;
					if ( $replacesSubscriptionIds && isset( $replacesSubscriptionIds[$planId] ) ) {
						$replacesSubId				=	$replacesSubscriptionIds[$planId];
						/*		//TBD later: need to check if we really want to renew an existing subscription when there is an interruption.
						if ( $reason == 'R' ) {
							$paidSomethinMgr		=&	cbpaidSomethingMgr::getInstance();
							$replacesSub			=&	$paidSomethinMgr->loadSomething( $replacesSubId[0], $replacesSubId[1] );
							if ( $replacesSub ) {
								if ( ! $replacesSub->checkIfValid( $subscriptionTime ) ) {

								}
							}
						}
						*/
					} else {
						if ( $reason == 'R' ) {
							trigger_error( 'createSubscriptionsAndPayment::no existing subscription for renewal !', E_USER_ERROR );
							exit;
						}
					}

					// find existing plan+subscription id:
					$existingSubId					=	null;
					if ( $reason != 'R' ) {
						// new or upgrade: create or load $subscription:
						if ( $existingSubscriptionIds && isset( $existingSubscriptionIds[$planId] ) ) {
							$existingSubId			=	$existingSubscriptionIds[$planId];
						}
					}

					// check that subscription is renewable if getting renewed:
					if ( ( $reason == 'R' ) && $replacesSubId ) {
						$paidSomethingMgr						=&	cbpaidSomethingMgr::getInstance();
						$subscription							=	$paidSomethingMgr->loadSomething( $replacesSubId[0], $replacesSubId[1] );
						if ( ! $subscription->checkIfRenewable() ) {
							trigger_error( sprintf( 'createSubscriptionsAndPayment::Renewal not allowed !' ), E_USER_WARNING );
							return 'Unexpected condition: Renewal not allowed !';
						}
					}
					// find parent subscription id if exists:
					$parentSubId									=	null;
					if ( $parentPlan ) {
						switch ( $reason ) {
							case 'R':
								// renew: don't change anything in the existing subscription (no update on NULL):
								// $parentSubId						=	null;
								break;
							case 'U':
								// upgrade: check if parent subscription is upgraded same time:
								if ( isset( $subscriptions[$parentPlan] ) ) {
									$parentSubId					=	array( (int) $subscriptions[$parentPlan]->plan_id, (int) $subscriptions[$parentPlan]->id );
								} else {
									// if not: try to find the existing subscription in database:
									if ( $existingSubId ) {
										$paidSomethinMgr			=&	cbpaidSomethingMgr::getInstance();
										$thisSub					=	$paidSomethinMgr->loadSomething( $existingSubId[0], $existingSubId[1] );
										if ( $thisSub ) {
											// then try to find parent subscription of the existing subscription:
											if ( $thisSub->parent_plan && $thisSub->parent_subscription ) {
												$thisSubParent		=	$paidSomethinMgr->loadSomething( $thisSub->parent_plan, $thisSub->parent_subscription );
												if ( $thisSubParent ) {
													$parentSubId	=	array( $thisSubParent->parent_plan, $thisSubParent->parent_subscription );
												}
											}
										} else {
											trigger_error( sprintf( 'createSubscriptionsAndPayment::no existing subscription id %d found in database for upgraded plan id %d !', $existingSubId[1], $existingSubId[0] ), E_USER_WARNING );
										}
									} else {
										// try finding subscription of parent plan by this user:
										$plansMgr					=&	cbpaidPlansMgr::getInstance();
										$parPlan					=	$plansMgr->loadPlan( $parentPlan );
										if ( $parPlan ) {
											$something				=	$parPlan->newSubscription();
											$foundParent			=	$something->loadLatestSomethingOfUser( $user->id );
											if ( $foundParent ) {
												$parentSubId		=	array( $something->plan_id, $something->id );
											}
										}
									}
								}
								break;

							case 'N':
							default:
								// new: find parent subscription:
								if ( isset( $subscriptions[$parentPlan] ) ) {
									$parentSubId		=	array( (int) $subscriptions[$parentPlan]->plan_id, (int) $subscriptions[$parentPlan]->id );
								} else {
									trigger_error( sprintf( 'createSubscriptionsAndPayment::no existing subscription for parent plan id %d of plan %d in new subscription !', $parentPlan, $planId ), E_USER_WARNING );
								}
								break;
						}
					}

					// creates the subscription of the correct type:
					$price						=	false;		// returned values from next line:
					$recurringPrice				=	false;		// returned values from next line:
					$subscriptions[$planId]		=	$plan->createProductThing( $user, $postdata, $reason, $status, $replacesSubId, $existingSubId, $subscriptionTime, $price, $recurringPrice, $parentSubId );
					if ( ( $price === false ) && ( $recurringPrice === false ) ) {
						unset( $subscriptions[$planId] );		// can't be subscribed/purchased
						unset( $chosenPlans[$planId] );
					} elseif ( ( $price > 0 ) || ( $recurringPrice > 0 ) ) {
						// $lastSubscriptionId	=	$subscriptions[$planId]->id;
						// $lastPlanId			=	$planId;
						$needToPay				=	true;
					}
				}
			}
		}

		// Sort subscriptions, so they are presented in basket in same order as on the plans selection:
		$sortedSubscriptions					=	array();
		foreach ( array_keys( $chosenPlans ) as $id ) {
			$sortedSubscriptions[$id]			=	$subscriptions[$id];
		}

		if ( ( $payment == 'free' ) || ( ! $needToPay ) ) {						//TBD: Should we activate already what can be activated (check for hierarchy) !???
			// Free plan: no payment ! : activate $subscription now:
			$thankYouText						=	array();
			$cbUser								=	CBuser::getInstance( $user->id );
			foreach ( array_keys( $subscriptions ) as $k ) {
				if ( ( $reason != 'R' ) || $subscriptions[$k]->checkIfRenewable() ) {
					$occurrences				=	1;
					$autorecurring_type			=	0;
					$autorenew_type				=	0;
					// bug #1184 fix: this was certainly wrong in backend at least, but in frontend too most likely too, as it would block from renewing imho:
					// $autorecurring_type			=	( ( $chosenPlans[$k]->autorecurring > 0 ) ? 2 : 0 );
					// $autorenew_type				=	( ( $chosenPlans[$k]->autorecurring > 0 ) ? 2 : 0 );
					$subscriptions[$k]->activate( $user, $subscriptionTime, true, $reason, $occurrences, $autorecurring_type, $autorenew_type );
					$extraStrings				=	$subscriptions[$k]->substitutionStrings( true );
					$thankYouText[]				=	trim( $cbUser->replaceUserVars( CBPTXT::Th( $subscriptions[$k]->getText( 'thankyoutextcompleted' ) ), true, true, $extraStrings, false ) );
				}
			}
			if ( count( $thankYouText ) > 0 ) {
				return implode( '<br />', $thankYouText );
			} else {
				return CBPTXT::Th("Chosen plan(s) can not be subscribed") . '.';
			}
		} else {
			// non-free plan:
			// 2. add payment_item and payment_basket records:

			// get the most recent payment basket for $subscription
			$paymentBasket						=	new cbpaidPaymentBasket( $_CB_database );
			/*
						$basketLoaded						=	$paymentBasket->loadLatestBasketOfUserPlanSubscription( $user->id );
						if ( $basketLoaded ) {
							$paymentBasket->delete();
							$paymentBasket					=	new cbpaidPaymentBasket( $_CB_database );
							//TBD LATER: Handle fully payment baskets as baskets, adding/replacing the content with the new items.
						}
			*/
			$hasAmountToPay						=	$paymentBasket->createAndFillCreteSubscriptionsItems( $user, $sortedSubscriptions, $prefixText, $reason, $subscriptionTime );
			if ( ! $hasAmountToPay ) {
				$thankYouText					=	array();
				$cbUser							=	CBuser::getInstance( $user->id );
				foreach ( array_keys( $subscriptions ) as $k ) {
					$subscriptions[$k]->activate( $user, $subscriptionTime, true, $reason );
					$extraStrings				=	$subscriptions[$k]->substitutionStrings( true );
					$thankYouText[]				=	trim( $cbUser->replaceUserVars( CBPTXT::Th( $subscriptions[$k]->getText( 'thankyoutextcompleted' ) ), true, true, $extraStrings, false ) );
				}
				return implode( '<br />', $thankYouText );
			}

			if ( ( $paymentBasket->payment_status === null ) || ( $paymentBasket->payment_status == 'NotInitiated' ) ) {
				return $paymentBasket;
			}
		}
		trigger_error( '_createSubscriptionsAndPayment: Unexpected condition: no payment and no free plan', E_USER_NOTICE );
		return 'Unexpected condition.';
	}
Esempio n. 14
0
	/**
	 * Gives upgrade possibilities for plans and discount in case of renewal.
	 * Only exclusive plans can be upgraded to other exclusive plans with the same father.
	 *
	 * @param  int             $ui              1: frontend user, 2: backend admin
	 * @param  UserTable       $user            user being displayed
	 * @param  cbpaidSomething $subscription    subscriptions being proposed for upgrade
	 * @param  float           $remainingValue  remaining value of the subscription (for prorate upgrades) in currency of this plan
	 * @param  float           $quantity        Quantity purchased
	 * @param  int             $now             unix time
	 * @return array
	 */
	public function upgradePlansPossibilities( /** @noinspection PhpUnusedParameterInspection */ $ui, UserTable $user, &$subscription, $remainingValue, $quantity, $now ) {
		$result			=	array();
		if ( $this->get( 'exclusive' ) == 1 ) {
			$plansMgr						=&	cbpaidPlansMgr::getInstance();
			$plans							=&	$plansMgr->loadPublishedPlans( $user, true, 'upgrade', null );		//TBD LATER: implement restriction on owner
			$remainingValueCurrencies		=	array( $this->currency()	=>	$remainingValue );
			foreach ( $plans as $p ) {
				if ( ( $p->get( 'exclusive' ) == 1 ) && ( $p->id != $this->id ) && ( $p->parent == $this->parent ) ) {
					if ( $remainingValue == 0 ) {
						$pCurRemVal			=	0;
					} else {
						if ( ! isset( $remainingValueCurrencies[$p->currency()] ) ) {
							$remainingValueCurrencies[$p->currency()]	=	$this->_priceConvert( $p->currency(), $remainingValue );
						}
						$pCurRemVal			=	$remainingValueCurrencies[$p->currency()];
					}

					$discountedPrice		=	$p->getPrice( null, $subscription, 'U', 0, $now, $pCurRemVal, $quantity );
					if ( ( $discountedPrice == false ) && ( $p->get( 'auto_compute_upgrade' ) == 0 ) ) {
						$discountedPrice	=	0;
					}
					if ( $discountedPrice !== false ) {
						$result[$p->id]		=	$discountedPrice;
					}
				}
			}
		}
		return $result;
	}
	/**
	 * parses regex match callback plan substitutions
	 *
	 * @param  array   $matches
	 * @return string
	 */
	public function replacePlanSubstitutions( $matches ) {
		$planId					=	( isset( $matches[1] ) ? (int) $matches[1] : null );
		$text					=	( isset( $matches[2] ) ? $matches[2] : null );

		if ( $planId && $text ) {
			$user				=	cbUser::getMyUserDataInstance();
			$plansMgr			=	cbpaidPlansMgr::getInstance();
			$plan				=	$plansMgr->getPublishedPlan( $planId, $user );

			if ( $plan ) {
				// Output CSS for displaying the plan properly:
				cbpaidTemplateHandler::getViewer( '', null )->outputTemplateCss( 'cbpaidsubscriptions' );
				$plan->getTemplateOutoutCss();

				// Get substitutions:
				return $plan->getPersonalized( $text, $user->id, true, true, null, false );
			}
		}

		return null;
	}