/**
  * Gives translated offset-adjusted gmdate()
  * Right now only supports formats 'F' and 'j F'
  *
  * @param  string  $format     Format like PHP's date()
  * @param  int     $timestamp  Unix Timestamp
  * @return string
  */
 public static function Tdate($format, $timestamp)
 {
     $monthNumber = cbpaidTimes::getInstance()->localDate('n', $timestamp);
     $monthName = self::T('UE_MONTHS_' . $monthNumber);
     if ($format == 'F') {
         return $monthName;
     }
     if ($format == 'j F') {
         $day = cbpaidTimes::getInstance()->localDate('j', $timestamp);
         return self::P("[DAY] [MONTHNAME]", array('[DAY]' => $day, '[MONTHNAME]' => $monthName));
     }
     return 'UNHANDLED FORMAT IN CBPTxt::Tdate: ' . $format;
 }
	/**
	 * Get the most recent unpaid payment basket for that user
	 *
	 * @param  int      $userId
	 * @return cbpaidPaymentBasket|boolean  Basket or false = db_error
	 */
	public function loadCurrentUnpaidBasket( $userId ) {
		global $_CB_framework;

		$cbpaidTimes			=&	cbpaidTimes::getInstance();
		$basket					=	$this->_tryLoadCurrentUnpaidBasket( $userId );
		if ( $basket ) {
			$timeInitiated		=	$cbpaidTimes->strToTime( $basket->time_initiated );
			$maxInitiatedTime	=	$_CB_framework->now() -10800;	// NOW - 3 hours

			if ( $timeInitiated < $maxInitiatedTime ) {
				$this->timeoutUnusedBaskets( $userId );
				$basket			=	null;
			}

		}
		return $basket;
	}
	/**
	 * 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;
	}
 /**
  * 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));
     }
 }
 /**
  * If table key (id) is NULL : inserts a new row
  * otherwise updates existing row in the database table
  *
  * Can be overridden or overloaded by the child class
  *
  * @param  boolean  $updateNulls  TRUE: null object variables are also updated, FALSE: not.
  * @return boolean                TRUE if successful otherwise FALSE
  */
 public function store($updateNulls = false)
 {
     if ($this->time_paid && $this->time_paid != $this->_db->getNullDate()) {
         $time_paid = cbpaidTimes::getInstance()->strToTime($this->time_paid);
         // we do NOT use PHP strtotime, which is broken
         $dateDayHour = explode(' ', cbpaidTimes::getInstance()->localDate('Y-m-d w H o W', $time_paid));
         $dateDayHour[1] += 1;
         // --> 1 = Sunday...7 = Saturday, ISO-8601 numeric representation of the day of the week, like MySQL
         $this->time_paid_date = $dateDayHour[0];
         $this->time_paid_day_of_week = $dateDayHour[1];
         $this->time_paid_yearweek = $dateDayHour[3] . '-W' . $dateDayHour[4];
         $this->time_paid_yearmonth = substr($dateDayHour[0], 0, 7);
         $this->time_paid_hour = $dateDayHour[2];
     }
     return parent::store($updateNulls);
 }
 /**
  * Updates the payment item corresponding to this Something
  *
  * @param  cbpaidPaymentItem    $item
  * @param  cbpaidPaymentBasket  $paymentBasket
  * @param  int                  $quantity          Quantity
  * @param  string               $currency_code     The currency of the payment basket (so the payment item must be converted into that currency
  * @return void
  */
 public function updatePaymentItem(&$item, $paymentBasket, $quantity = null, $currency_code = null)
 {
     $item->callIntegrations('beforeUpdatePaymentItem', $this, $paymentBasket);
     if ($quantity === null) {
         $quantity = $item->quantity;
     }
     if ($currency_code === null) {
         $currency_code = $item->currency;
     }
     $reason = $item->reason;
     $tryAutorecurring = $item->autorecurring;
     $start_time = cbpaidTimes::getInstance()->strToTime($item->start_date);
     list($first_rate, , $rate, , $prorate_discount, , ) = $this->computeItemRatesAndValidity($quantity, $currency_code, $reason, $start_time, $tryAutorecurring);
     if ($first_rate !== false) {
         $item->quantity = $quantity;
         $item->currency = $currency_code;
         $item->first_rate = $first_rate;
         $item->rate = $rate;
         $item->prorate_discount = $prorate_discount;
     }
     $item->callIntegrations('afterUpdatePaymentItem', $this, $paymentBasket);
 }
 /**
  * This is the frontend or backend method used directly
  * @see cbpaidPaymentBasket::store()
  *
  * If table key (id) is NULL : inserts a new row
  * otherwise updates existing row in the database table
  *
  * Can be overridden or overloaded by the child class
  *
  * @param  boolean  $updateNulls  TRUE: null object variables are also updated, FALSE: not.
  * @return boolean                TRUE if successful otherwise FALSE
  */
 public function store($updateNulls = false)
 {
     global $_CB_framework, $_CB_database;
     // 1) check:
     if (!in_array($this->payment_status, array('Pending', 'Refunded', 'NotInitiated'))) {
         $this->setError(CBPTXT::T("This payment basket is not pending."));
         return false;
     }
     if ($this->txn_id == '') {
         $this->txn_id = 'None';
         // needed for updatePayment to generate payment record.
     }
     $paymentBasket = new cbpaidPaymentBasket($_CB_database);
     $paymentBasket->load($this->id);
     if (!$paymentBasket->gateway_account) {
         $this->setError(CBPTXT::T("This payment basket has no gateway associated so can not be paid manually."));
         return false;
     }
     $ipn = new cbpaidPaymentNotification($_CB_database);
     $ipn->bindObjectToThisObject($paymentBasket, 'id');
     $ipn->mc_currency = $this->mc_currency;
     $ipn->mc_gross = $this->mc_gross;
     if (!preg_match('/^[1-9][0-9]{3}-[01][0-9]-[0-3][0-9]/', $this->time_completed)) {
         $this->time_completed = Application::Database()->getUtcDateTime();
     }
     $paymentBasket->time_completed = $this->time_completed;
     $ipn->payment_type = $this->payment_type;
     $paymentBasket->payment_type = $this->payment_type;
     $ipn->txn_id = $this->txn_id;
     $paymentBasket->txn_id = $this->txn_id;
     $ipn->payment_status = 'Completed';
     $ipn->txn_type = 'web_accept';
     $ipn->payment_method = $this->payment_method;
     $ipn->gateway_account = $this->gateway_account;
     $ipn->log_type = 'P';
     $ipn->time_received = $_CB_database->getUtcDateTime();
     $ipn->payment_date = gmdate('H:i:s M d, Y T', $this->time_completed ? cbpaidTimes::getInstance()->strToTime($this->time_completed) : cbpaidTimes::getInstance()->startTime());
     // paypal-style				//TBD FIXME: WE SHOULD CHANGE THIS OLD DATE STYLE ONCE WITH UTC timezone inputed
     $ipn->payment_basket_id = $this->id;
     $ipn->raw_result = 'manual';
     $ipn->raw_data = '';
     $ipn->ip_addresses = cbpaidRequest::getIPlist();
     $ipn->user_id = Application::MyUser()->getUserId();
     $ipn->txn_id = $this->txn_id;
     $ipn->payment_type = $this->payment_type;
     $ipn->charset = $_CB_framework->outputCharset();
     //TBD
     /*
     		$paymentBasket->first_name	= $ipn->first_name	= cbGetParam( $_POST, 'txtBTitle' );
     		$paymentBasket->first_name		= $ipn->first_name		= cbGetParam( $_POST, 'txtBFirstName' );
     		$paymentBasket->last_name		= $ipn->last_name		= cbGetParam( $_POST, 'txtBLastName' );
     		$paymentBasket->address_street	= $ipn->address_street	= cbGetParam( $_POST, 'txtBAddr1' );
     		$paymentBasket->address_zip		= $ipn->address_zip		= cbGetParam( $_POST, 'txtBZipCode' );
     		$paymentBasket->address_city	= $ipn->address_city	= cbGetParam( $_POST, 'txtBCity' );
     		$paymentBasket->address_country	= $ipn->address_country	= cbGetParam( $_POST, 'txtBCountry' );
     		//TBD? $paymentBasket->phone	= $ipn->phone			= cbGetParam( $_POST, 'txtBTel' );
     		//TBD? $paymentBasket->fax		= $ipn->fax				= cbGetParam( $_POST, 'txtBFax' );
     		$paymentBasket->payer_email		= $ipn->payer_email		= cbGetParam( $_POST, 'txtBEmail' );
     */
     if (!$_CB_database->insertObject($ipn->getTableName(), $ipn, $ipn->getKeyName())) {
         trigger_error('store error:' . htmlspecialchars($_CB_database->getErrorMsg()), E_USER_ERROR);
         //TBD also in paypal: error code 500 !!!
     }
     $payAccount = cbpaidControllerPaychoices::getInstance()->getPayAccount($paymentBasket->gateway_account);
     if (!$payAccount) {
         $this->setError(CBPTXT::T("This payment basket's associated gateway account is not active, so can not be paid manually."));
         return false;
     }
     $payClass = $payAccount->getPayMean();
     $payClass->updatePaymentStatus($paymentBasket, 'web_accept', 'Completed', $ipn, 1, 0, 0, 'singlepayment');
     return true;
 }
 /**
  * View for <param  type="private" class="cbpaidParamsExt" method="checkcertificate">...
  *
  * @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 checkcertificate($value, &$pluginParams, $name, &$param, $control_name, $control_name_name, $view, &$modelOfData, &$modelOfDataRows, &$modelOfDataRowsNumber)
 {
     $return = '';
     $default = $param->attributes('default');
     $filePath = isset($modelOfData->{$default}) ? $modelOfData->{$default} : null;
     //->get( 'default' );
     $ok = false;
     if ($filePath) {
         $readable = @file_exists($filePath) && @is_readable($filePath);
         if ($readable) {
             $certificate = @openssl_x509_read(file_get_contents($filePath));
             if ($certificate !== false) {
                 $details = @openssl_x509_parse($certificate, false);
                 if ($details !== false) {
                     /*
                     foreach ( $details as $k => $v ) {
                     	$return	.=	$k . ': ' . $v . '<br />';
                     }
                     $return		.=	var_export( $details, true ) . '<br />';
                     */
                     $return .= isset($details['name']) ? "Name: " . $details['name'] . '<br />' : '';
                     $return .= isset($details['validFrom_time_t']) ? "Valid from: " . cbpaidTimes::getInstance()->getUtcDateOfTime($details['validFrom_time_t']) . '<br />' : '';
                     $return .= isset($details['validTo_time_t']) ? "Valid until: " . cbpaidTimes::getInstance()->getUtcDateOfTime($details['validTo_time_t']) . '<br />' : '';
                     $ok = true;
                     if (isset($details['validTo_time_t']) && $details['validTo_time_t'] < time()) {
                         $return .= '<br /><span class="cbSmallWarning">' . "Certificate has expired !" . '</span>';
                         $ok = false;
                     } elseif (isset($details['validFrom_time_t']) && $details['validFrom_time_t'] > time()) {
                         $return .= '<br /><span class="cbSmallWarning">' . "Certificate is not yet valid !" . '</span>';
                         $ok = false;
                     } else {
                         $return .= "Certificate appears valid";
                     }
                 } else {
                     $return = "File is not a X509 certificate (public key)";
                 }
             } else {
                 $return = sprintf("File %s is readable but can not be opened as a X509 certificate (openssl_x509_read failed on public key cert)", $filePath);
             }
         } else {
             $return = sprintf("File %s does not exist or is not readable", $filePath);
         }
     } else {
         $return = "Filename not set";
     }
     return $this->_outputGreenRed('', $ok, $return, $return);
 }
 /**
  * Renders a calendar or time-period validity period, e.g. Year 2007, March - May 2007, December 2006 - January 2007, etc.
  *
  * @param  int|null  $expiryTime   Unix-time
  * @param  int|null  $startTime    Unix-time
  * @param  string    $varName      variable name ( 'validity' (default) or 'first_validity' )
  * @param  string    $reason       payment reason: 'N'=new subscription (default), 'R'=renewal, 'U'=update (needed only if $expiryTime is NULL)
  * @param  int       $occurrences  number of occurrences (needed only if $expiryTime is NULL)
  * @param  boolean   $displayOne   Display significant 1s also if it's 1: e.g. TRUE: 1 year, FALSE: year
  * @param  boolean   $html         true: Display for html with non-breaking spaces
  * @param  string    $status       status of subscription
  * @return string
  */
 public function getFormattedValidity($expiryTime, $startTime, $varName, $reason = null, $occurrences = 1, $displayOne = true, $html = false, $status = 'I')
 {
     $this->fixVarName($varName);
     $text = '';
     if ($this->isCalendarValidity($varName)) {
         $now = cbpaidTimes::getInstance()->startTime();
         if ($startTime === null) {
             $startTime = $now;
         }
         if ($expiryTime === null) {
             $expiryTime = $this->getExpiryTime($startTime, $varName, $occurrences, $reason, $status);
             // WARNING: adjusts $startTime to the real Start-time, which is wanted here
         }
         $isValid = $now < $expiryTime;
         list($y, $c, $d, , , ) = $this->getValidity($varName);
         // = sscanf( substr( $this->get( $varName ), 2 ), '%d-%d-%d %d:%d:%d' );
         list($yn, $cn, $dn) = sscanf(cbpaidTimes::getInstance()->localDate('Y-m-d', $now), '%d-%d-%d');
         list($ys, $cs, $ds) = sscanf(cbpaidTimes::getInstance()->localDate('Y-m-d', $startTime), '%d-%d-%d');
         list($ye, $ce, $de) = sscanf(cbpaidTimes::getInstance()->localDate('Y-m-d', $expiryTime), '%d-%d-%d');
         $calStart = $this->calendarYearStart($varName);
         if ($y && $calStart == '01-01') {
             if ($y == 1 && $ye <= $ys + 1) {
                 $text .= sprintf($this->_htmlNbsp(CBPTXT::T("Year %s"), $html), $ye);
                 // 'Year 2007'
                 if ($ye != $yn && $isValid) {
                     $text .= ' (' . CBPTXT::T("valid from now on") . ')';
                 }
             } else {
                 $years = $ye - $ys + 1;
                 if (!$isValid || $y == $years && $ys == $yn) {
                     $text .= sprintf($this->_htmlNbsp(CBPTXT::T("Years %s - %s"), $html), $ys, $ye);
                     // 'Years 2006 - 2007'
                 } else {
                     if ($y == $years) {
                         $text .= sprintf($this->_htmlNbsp(CBPTXT::T("Years %s - %s"), $html), $ys, $ye);
                         // 'Years 2007 - 2008'
                     } else {
                         $text .= sprintf($this->_htmlNbsp(CBPTXT::T("Years %s - %s"), $html), $ys + 1, $ye);
                         // 'Years 2007 - 2008'
                     }
                     $text .= ' (' . CBPTXT::T("valid from now on") . ')';
                 }
             }
         } elseif ($c || $y) {
             if ($calStart != '01-01' && !preg_match('/$..-01/', $calStart)) {
                 // $text .= $calStart . date( 'Y-m-d H:i:s', $startTime ) .( $c + ( $y * 12 ) ) . '_' . ($ce - $cs + 1 + ( ( $ye - $ys ) * 12 )) . '_';
                 $text .= CBPTXT::Tdate('j F', $startTime) . ($ys != $ye ? $this->_htmlNbsp(' ', $html) . $ys : '');
                 // 'January' or 'December 2006'
                 $text .= $this->_htmlNbsp(' - ', $html);
                 // ' - '
                 $text .= CBPTXT::Tdate('j F', $expiryTime) . $this->_htmlNbsp(' ', $html) . $ye;
                 // 'February 2007'
                 if (($ys > $yn || $cs > $cn && $ys == $yn) && $isValid) {
                     $text .= ' (' . CBPTXT::T("valid from now on") . ')';
                 }
             } else {
                 $months = $ce - $cs + 1 + ($ye - $ys) * 12;
                 if ($c == 1 && $y == 0 || $months == 1) {
                     $text .= CBPTXT::Tdate('F', $expiryTime) . $this->_htmlNbsp(' ', $html) . $ye;
                     // 'January 2007'
                     if ($ce != $cn && $isValid) {
                         $text .= ' (' . CBPTXT::T("valid from now on") . ')';
                     }
                 } else {
                     // if ( ( $c + ( $y * 12 ) ) == $months ) {
                     $text .= CBPTXT::Tdate('F', $startTime) . ($ys != $ye ? $this->_htmlNbsp(' ', $html) . $ys : '');
                     // 'January' or 'December 2006'
                     $text .= $this->_htmlNbsp(' - ', $html);
                     // ' - '
                     $text .= CBPTXT::Tdate('F', $expiryTime) . $this->_htmlNbsp(' ', $html) . $ye;
                     // 'February 2007'
                     if (!($cs == $cn && $ys == $yn) && $isValid) {
                         $text .= ' (' . CBPTXT::T("valid from now on") . ')';
                     }
                     // } else {		//TBD: check if this else is still needed
                     /*	list($ynn, $cnn, $dnn, $hnn, $mnn, $snn) = sscanf( gmdate( 'Y-m-d H:i:s', $startTime ), '%d-%d-%d %d:%d:%d' );
                     				$cnn += 2;
                     				$dnn = 0;
                     				$nextMonthTime = mktime($hnn, $mnn, $snn, $cnn, $dnn, $ynn);
                     				$text .= gmdate( 'F', $nextMonthTime) . ( ( $ynn != $ye ) ? $this->_htmlNbsp( ' ', $html ) . $ynn : '' );	// 'January' or 'December 2006'
                     				$text .= $this->_htmlNbsp( ' - ', $html );														// ' - '
                     				$text .= gmdate( 'F', $expiryTime) . $this->_htmlNbsp( ' ', $html ) . $ye;						// 'February 2007'
                     				if ( $isValid ) {
                     					$text .= ' (' . CBPTXT::T("valid from now on") . ')';
                     				}
                     			*/
                     // }
                 }
             }
         } elseif ($d) {
             if ($de == $dn) {
                 $text .= CBPTXT::T("Today");
             } elseif ($de == $dn + 1 || $de == 1 && $expiryTime - $now < 48 * 3600) {
                 if ($d == 1) {
                     $text .= CBPTXT::T("Tomorrow");
                     if ($isValid) {
                         $text .= ' (' . CBPTXT::T("valid from now on") . ')';
                     }
                 } else {
                     $text .= CBPTXT::T("Today and tomorrow");
                 }
             } else {
                 if ($isValid) {
                     $days = (int) floor(($expiryTime - $now) / (24 * 3600));
                     if ($days < $d && $ds == $dn) {
                         $t = CBPTXT::T("Today and next %d days");
                         if ($html) {
                             $t = str_replace(' %d ', '&nbsp;%d&nbsp;', $t);
                         }
                         $text .= sprintf($t, $days);
                     } else {
                         $text .= sprintf($this->_htmlNbsp(CBPTXT::T("Next %d days"), $html), $days) . ' (' . CBPTXT::T("in addition of today, valid from now on") . ')';
                     }
                 } else {
                     $showtime = false;
                     cbimport('cb.tabs');
                     // cbFormatDate is in comprofiler.class.php
                     $expText = cbFormatDate($expiryTime, 0, $showtime);
                     $startText = cbFormatDate($startTime, 0, $showtime);
                     $text .= $startText;
                     if ($startText != $expText) {
                         $text .= $this->_htmlNbsp(' - ', $html) . $expText;
                     }
                 }
             }
         }
     } else {
         $text = $this->_htmlNbsp($this->renderPeriod($this->getValidity($varName), 1, $displayOne), $html);
     }
     return trim($text);
 }
示例#10
0
	/**
	 * Compares $v1 to $v2 using $diffOperator and of $diffOperator is a duration-date (e.g. '-0000-00-01 00:00:00'), $diffLarger will give the underlying operator
	 * @param  string  $v1            Value 1
	 * @param  string  $v2            Value 2
	 * @param  string  $diffOperator  =,<,>,!=,E,!E,regexp,!regexp,birthday,+0000-00-01 00:00:00
	 * @param  string  $diffLarger
	 * @return boolean
	 */
	private function _compareValuesWithOperator( $v1, $v2, $diffOperator, $diffLarger ) {
		global $_CB_database;

		switch ( $diffOperator ) {
			case '=':
				return ( $v1 == $v2 );
				break;
			case '<':
				return ( $v1 < $v2 );
				break;
			case '>':
				return ( $v1 > $v2 );
				break;
			case '!=':
				return ( $v1 != $v2 );
				break;
			case 'E':
				return ( stripos( $v1, $v2 ) !== false );
				break;
			case '!E':
				return ( stripos( $v1, $v2 ) === false );
				break;
			case 'regexp':
				return preg_match( $v1, $v2 );
				break;
			case '!regexp':
				return ! preg_match( $v1, $v2 );
				break;
			case 'birthday':
				return ( ( strlen( $v1 ) >= 10 ) && ( strlen( $v2 ) >= 10 ) )
						&& ( substr( $v1, 5, 5 ) == substr( $v2, 5, 5 ) )		// same month and day
						&& ( substr( $v1, 0, 4 ) != substr( $v2, 0, 4 ) );		// but not same year
				break;
			default:
				if ( strlen($diffOperator ) == 20 ) {
					//TODO make it work for dates < 1970 !!!! AND for DATE without TIME
					if ( ( strlen( $v1 ) == 19 ) && ( $v1 != $_CB_database->getNullDate() ) ) {
						$t1		=	cbpaidTimes::getInstance()->strToTime( $v1 );
					} else {
						$t1		=	0;
					}
					if ( ( strlen( $v2 ) == 19 ) && ( $v2 != $_CB_database->getNullDate() ) ) {
						$t2		=	$this->_timeAddSubDurationToDate( $diffOperator, $v2 );
					} else {
						$t2		=	0;
					}
					return ( $diffLarger ? ( $t1 >= $t2 ) : ( $t1 <= $t2 ) );
				} else {
					// no condition means this condition is OK:
					return true;
				}
				break;
		}
	}
示例#11
0
	/**
	 * Returns formatted time period ( xxx weeks , or xxx years xxx months xxx days xxx hours xxx minutes xxx seconds
	 *
	 * @param  int[]    $ycdhmsArray  = list( $years, $months, $days, $hours, $minutes, $seconds )
	 * @param  int      $occurrences  [default: 1] multiply period by the occurrences before displaying
	 * @param  boolean  $displayOne   [default: true] displays also if only 1 unit of something
	 * @param  string   $prefix       text between number and period, e.g. 3 calendar months
	 * @return string
	 */
	public function renderPeriod( $ycdhmsArray, $occurrences = 1, $displayOne = true, $prefix = '' ) {
		$cbpaidTimes	=&	cbpaidTimes::getInstance();
		return $cbpaidTimes->renderPeriod( $ycdhmsArray, $occurrences, $displayOne, $prefix );
	}
 /**
  * Computes SQL DATETIME of next schedule based on $baseObject
  *
  * @param  exampleScheduledClass  $baseObject
  * @param  boolean                $justFailed
  * @return string
  */
 public function computeMaturity($baseObject, $justFailed = false)
 {
     static $timeWords = array('S' => 'second', 'I' => 'minute', 'H' => 'hours', 'D' => 'day', 'W' => 'week', 'M' => 'month', 'Y' => 'year');
     $nextMaturityTime = cbpaidTimes::getInstance()->gmStrToTime($baseObject->subscr_date);
     $recurrings = $baseObject->recur_times_used;
     // first period:
     if ($baseObject->period1) {
         $parray = explode(' ', $baseObject->period1);
         // e.g. '12 M' => array( '12', 'M' )
         if (count($parray) == 2 && isset($timeWords[$parray[1]])) {
             // check format
             $nextMaturityTime = cbpaidTimes::getInstance()->gmStrToTime('+' . $parray[0] . ' ' . $timeWords[$parray[1]], $nextMaturityTime);
             // e.g. '+ 12 months'
         }
     } else {
         ++$recurrings;
     }
     // reoccuring period:
     if ($recurrings) {
         $parray = explode(' ', $baseObject->period3);
         // e.g. '12 M' => array( '12', 'M' )
         if (count($parray) == 2 && isset($timeWords[$parray[1]])) {
             // Format is valid ?
             // Format is valid:
             $number = intval($parray[0]) * $recurrings;
             $nextMaturityTime = cbpaidTimes::getInstance()->gmStrToTime('+' . $number . ' ' . $timeWords[$parray[1]], $nextMaturityTime);
             // e.g. '+ 12 months'
         }
     }
     $nextMaturityTime += $baseObject->reattempts_tried * $this->retryInterval;
     if ($justFailed) {
         $tomorrow = cbpaidTimes::getInstance()->startTime() + $this->retryInterval;
         if ($tomorrow > $nextMaturityTime) {
             $nextMaturityTime = $tomorrow;
         }
     }
     return Application::Database()->getUtcDateTime($nextMaturityTime);
 }
 /**
  * Checks if currency conversion of $this is up to date
  *
  * @param  int     $extraHoursOfValidity  number of hours of extra-validity
  * @param  string  $renewalInterval       strtotime relative time of validity (default: '+12 hours')
  * @return boolean                        TRUE: entry is up-to-date, FALSE: not up-to-date
  */
 public function isUpToDate($extraHoursOfValidity = 0, $renewalInterval = '+12 hours')
 {
     global $_CB_framework;
     if ($this->last_renewed_date && $this->last_renewed_date != '0000-00-00 00:00:00') {
         $now = $_CB_framework->now();
         $lastRenewedTime = cbpaidTimes::getInstance()->strToTime($this->last_renewed_date);
         $nextRenewalDue = cbpaidTimes::getInstance()->gmStrToTime($renewalInterval, $lastRenewedTime);
         $result = $now < $nextRenewalDue + $extraHoursOfValidity * 3600;
     } else {
         $result = false;
     }
     return $result;
 }
 /**
  * Computes start time from $endTime for $showPeriod date
  * @param  string  $showPeriod  SQL DATETIME formatted period of time
  * @param  int     $endTime     End time
  * @return int|null             Start-time or null for not computable
  */
 private function _periodOfValidity($showPeriod, $endTime)
 {
     if (!$showPeriod || $showPeriod == '0000-00-00 00:00:00') {
         return null;
     }
     $duration = cbpaidTimes::getInstance()->dateInterval($showPeriod);
     $systemTimeZone = new DateTimeZone(cbpaidTimes::getInstance()->systemTimeZone());
     $endDate = new DateTime('@' . $endTime, $systemTimeZone);
     $endDate->setTimezone($systemTimeZone);
     $startDate = $endDate->sub($duration);
     return $startDate->getTimestamp();
 }
 /**
  * Returns today's date in an array
  *
  * @return array  array( year, month, day )
  */
 protected static function _getYearMonthDay()
 {
     return explode('-', cbpaidTimes::getInstance()->localDate('Y-m-d'));
 }
示例#16
0
	/**
	 * Adds rate periods start and stop periods
	 *
	 * @param  array                        $ratePeriods
	 * @param  cbpaidPaymentBasket          $paymentBasket
	 * @param  int                          $paymentItemIndex
	 * @param  cbpaidsalestaxTotalizertype  $taxRate
	 * @param  string                       $taxRate_stop_date
	 * @param  boolean                      $hasSecondPeriod
	 * @param  string                       $itemSecondStart
	 */
	private static function addRatePeriodJustStartDates( &$ratePeriods, $paymentBasket, $paymentItemIndex, $taxRate, $taxRate_stop_date, $hasSecondPeriod, $itemSecondStart ) {
		global $_CB_framework;
		$offset						=	(int) $_CB_framework->getCfg( 'offset' ) * 3600;
		$paymentBasketDay			=	date( 'Y-m-d', cbpaidTimes::getInstance()->strToTime( $paymentBasket->time_initiated ) + $offset );

		$taxApplicableToFirstPeriod		=	( $taxRate->start_date <= $paymentBasketDay ) && ( $taxRate_stop_date >= $paymentBasketDay );
		$taxApplicableToSecondPeriod	=	$hasSecondPeriod  && ( $taxRate->start_date <= $itemSecondStart ) && ( $taxRate_stop_date >= $itemSecondStart );

		if ( $taxApplicableToFirstPeriod && $taxApplicableToSecondPeriod ) {
			$ratePeriods[0][0]		=	'0000-00-00';
			$ratePeriods[0][1]		=	'0000-00-00';
			$ratePeriods[0][2]		=	'all';
			$ratePeriods[0][3]		=	0;
			$ratePeriods[0][4]		=	0;
			$ratePeriods[0][5]		=	0;
			$ratePeriods[0][6]		=	0;
			$ratePeriods[0][7][]	=	$paymentItemIndex;
		} elseif ( $taxApplicableToFirstPeriod ) {
			$ratePeriods[]			=	array( $paymentBasketDay, $paymentBasketDay, 'first', 0, 0, 0, 0, array( $paymentItemIndex ) );
		} elseif ( $taxApplicableToSecondPeriod ) {
			$ratePeriods[]			=	array( $itemSecondStart, $itemSecondStart, 'second', 0, 0, 0, 0, array( $paymentItemIndex ) );
		}
	}
	/**
	 * Renders payments cycles with rate and validity for $this basket
	 *
	 * @param  boolean       $html
	 * @param  boolean       $roundings  TRUE: use settings roundings, FALSE: round to cents
	 * @return string                 HTML text
	 */
	public function renderRatesValidtiy( $html, $roundings = true ) {
		if ( $this->period1 ) {
			if ( $this->recur_times ) {
				$tmpltext	=	CBPTXT::T("%s for the first %s, then %s for each %s, in %s installments");
			} else {
				$tmpltext	=	CBPTXT::T("%s for the first %s, then %s each %s");		//TBD: alternate text: "&s, then, after %s, %s each %s"
			}
		} else {
			if ( $this->recur_times ) {
				$tmpltext	=	CBPTXT::T("%3\$s for each %4\$s, in %5\$s installments");
			} else {
				$tmpltext	=	CBPTXT::T("%3\$s for each %4\$s");
			}
		}
		$cbpaidMoney			=&	cbpaidMoney::getInstance();
		$cbpaidTimes			=&	cbpaidTimes::getInstance();

		if ( $this->period1 ) {
			$validity			 =	$this->ymwdPeriodToTimePeriod( $this->period1 );
			$first_validity_text =	$cbpaidTimes->renderPeriod( $validity, 1 , false );
			$first_rate_text	 =	$cbpaidMoney->renderPrice( $this->mc_amount1, $this->mc_currency, $html, $roundings );
		} else {
			$first_validity_text =	null;
			$first_rate_text	 =	null;
		}

		$validity				=	$this->ymwdPeriodToTimePeriod( $this->period3 );
		$validity_text			=	$cbpaidTimes->renderPeriod( $validity, 1 , false );
		$rate_text				=	$cbpaidMoney->renderPrice( $this->mc_amount3, $this->mc_currency, $html, $roundings );

		$text					=	sprintf( $tmpltext, $first_rate_text, $first_validity_text, $rate_text, $validity_text, $this->recur_times );
		return $text;
	}
 /**
  * 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)
 {
     $now = cbpaidTimes::getInstance()->startTime();
     $nowGraceTimeAgo = $this->substractValidityFromTime($this->get('graceperiod'), $now);
     $cutOffDate = $this->_db->getUtcDateTime($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);
 }
 /**
  * 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;
 }
 /**
  * Updates the payment item corresponding to this Something
  *
  * @param  cbpaidPaymentItem    $item
  * @param  cbpaidPaymentBasket  $paymentBasket
  * @param  int                  $quantity          Quantity
  * @param  string               $currency_code     The currency of the payment basket (so the payment item must be converted into that currency
  * @return void
  */
 public function updatePaymentItem(&$item, $paymentBasket, $quantity = null, $currency_code = null)
 {
     $item->callIntegrations('beforeUpdatePaymentItem', $this, $paymentBasket);
     if ($quantity === null) {
         $quantity = $item->quantity;
     }
     if ($currency_code === null) {
         $currency_code = $item->currency;
     }
     $start_time = cbpaidTimes::getInstance()->strToTime($item->start_date);
     $rate = $this->getPriceOfNextPayment($currency_code, $start_time, $quantity, $item->reason);
     if ($rate === false) {
         $rate = 0;
     }
     $item->currency = $currency_code;
     $item->rate = $rate;
     $item->quantity = $quantity;
     $item->callIntegrations('afterUpdatePaymentItem', $this, $paymentBasket);
 }
 /**
  * Renders a $variable for an $output
  *
  * @param  string   $variable
  * @param  string   $output
  * @param  boolean  $rounded
  * @return string|null
  */
 public function renderColumn($variable, $output = 'html', $rounded = false)
 {
     $html = $output == 'html';
     switch ($variable) {
         case 'rate':
             $ret = $this->renderItemRate($html);
             break;
         case 'discount_amount':
         case 'tax_amount':
             $ret = $this->renderJustItemRates($variable, $html, $rounded);
             break;
         case 'first_rate':
         case 'first_discount_amount':
         case 'first_tax_amount':
             $ret = cbpaidMoney::getInstance()->renderPrice($this->{$variable}, $this->currency, $html, $rounded);
             break;
         case 'quantity':
             // removes insignifiant zeros after ., as well as the . itself if no decimals:
             $matches = null;
             $matched = preg_match("/^(.+?)[.]?[0]*\$/", $this->get($variable), $matches);
             $ret = $matched ? $matches[1] : null;
             break;
         case 'validity_period':
             if ($this->start_date && $this->stop_date && $this->start_date != '0000-00-00 00:00:00' && $this->stop_date != '0000-00-00 00:00:00') {
                 $showTime = false;
                 $startDate = cbFormatDate($this->start_date, 1, $showTime);
                 $stopDate = cbFormatDate($this->stop_date, 1, $showTime);
                 $ret = htmlspecialchars($startDate);
                 if ($stopDate && $startDate != $stopDate) {
                     $ret .= ($html ? '&nbsp;-&nbsp;' : ' - ') . htmlspecialchars($stopDate);
                 }
                 if ($this->second_stop_date && $this->second_stop_date != '0000-00-00 00:00:00') {
                     $secondStartDate = cbFormatDate($this->_db->getUtcDateTime(cbpaidTimes::getInstance()->strToTime($this->stop_date) + 1), 1, $showTime);
                     $secondStopDate = cbFormatDate($this->second_stop_date, 1, $showTime);
                     $retsecond = htmlspecialchars($secondStartDate) . ($html ? '&nbsp;-&nbsp;' : ' - ') . htmlspecialchars($secondStopDate);
                     $ret = sprintf($html ? CBPTXT::Th("%s, then %s") : CBPTXT::T("%s, then %s"), $ret, $retsecond);
                 }
             } else {
                 $ret = null;
             }
             break;
         case 'tax_rule_id':
             if ($this->tax_rule_id && is_callable(array('cbpaidTaxRule', 'getInstance'))) {
                 $ret = cbpaidTaxRule::getInstance((int) $this->tax_rule_id)->getShortCode();
             } else {
                 $ret = null;
             }
             break;
         case 'original_rate':
         case 'first_original_rate':
             $ret = null;
             break;
         case 'ordering':
         case 'artnum':
         case 'description':
         case 'discount_text':
         default:
             $value = $this->get($variable);
             if ($value !== null) {
                 $ret = htmlspecialchars($this->get($variable));
             } else {
                 $ret = null;
             }
             break;
     }
     return $ret;
 }
 /**
  * Returns formatted time period ( xxx weeks , or xxx years xxx months xxx days xxx hours xxx minutes xxx seconds
  *
  * @param  string        $varName                    'validity' or 'fist_validity'
  * @param  int           $occurrences                [default: 1] multiply period by the occurrences before displaying
  * @param  boolean       $displayOne                 [default: true] displays also if only 1 unit of something
  * @param  boolean       $displayCalendarYearStart   [default: true] displays start of calendar year if not January 1st
  * @return string
  */
 private function _renderPeriodOfValiditiy($varName, $occurrences = 1, $displayOne = true, $displayCalendarYearStart = true)
 {
     $ycdhmsArray = $this->getValidity($varName);
     $prefix = $this->isCalendarValidity($varName) ? CBPTXT::T("calendar ") : '';
     $text = $this->renderPeriod($ycdhmsArray, $occurrences, $displayOne, $prefix);
     $calStart = $this->calendarYearStart($varName);
     if ($prefix && $calStart != '01-01' && $displayCalendarYearStart) {
         list($m, $d) = explode('-', $calStart);
         $text .= ' ' . CBPTXT::T("starting") . ' ' . CBPTXT::Tdate('F j', cbpaidTimes::getInstance()->localStrToTime((int) $m . '/' . (int) $d));
     }
     return $text;
 }