/** * 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.'; }