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