AntonLV 9 лет назад
Родитель
Сommit
7a2cecdc5a

+ 1 - 0
modules/boonex/market/classes/BxMarketConfig.php

@@ -55,6 +55,7 @@ class BxMarketConfig extends BxBaseModTextConfig
         	'FIELD_WARNING_RECURRING' => 'warning_recurring',
         	'FIELD_PRICE_RECURRING' => 'price_recurring',
         	'FIELD_DURATION_RECURRING' => 'duration_recurring',
+        	'FIELD_TRIAL_RECURRING' => 'trial_recurring',
         	'FIELD_HEADER_END_RECURRING' => 'header_end_recurring',
             'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
 			'FIELD_ALLOW_PURCHASE_TO' => 'allow_purchase_to',

+ 6 - 4
modules/boonex/market/classes/BxMarketDb.php

@@ -366,7 +366,7 @@ class BxMarketDb extends BxBaseModTextDb
     	)) > 0;
     }
 
-	public function registerLicense($iProfileId, $iProductId, $iCount, $sOrder, $sLicense, $sType, $sDuration = '')
+	public function registerLicense($iProfileId, $iProductId, $iCount, $sOrder, $sLicense, $sType, $sDuration = '', $iTrial = 0)
     {
     	$CNF = &$this->_oConfig->CNF;
 
@@ -379,15 +379,17 @@ class BxMarketDb extends BxBaseModTextDb
     		'type' => $sType
     	);
 
-		$sExpireParam = ''; 
-		if(!empty($sDuration) && isset($this->_aRecurringDurations[$sDuration]))
+		$sExpireParam = '';
+		if(!empty($iTrial))
+		    $sExpireParam = ', `expired`=UNIX_TIMESTAMP(DATE_ADD(DATE_ADD(NOW(), INTERVAL ' . (int)$iTrial . ' DAY), INTERVAL ' . (int)$this->getParam($CNF['OPTION_RECURRING_RESERVE']) . ' DAY))';
+		else if(!empty($sDuration) && isset($this->_aRecurringDurations[$sDuration]))
 			$sExpireParam = ', `expired`=UNIX_TIMESTAMP(DATE_ADD(DATE_ADD(NOW(), ' . $this->_aRecurringDurations[$sDuration] . '), INTERVAL ' . (int)$this->getParam($CNF['OPTION_RECURRING_RESERVE']) . ' DAY))';
 
     	$sQuery = $this->prepare("INSERT INTO `" . $CNF['TABLE_LICENSES'] . "` SET " . $this->arrayToSQL($aQueryParams) . ", `added`=UNIX_TIMESTAMP()" . $sExpireParam);
         return (int)$this->query($sQuery) > 0;
     }
 
-    public function prolongLicense($iProfileId, $iProductId, $iCount, $sOrder, $sLicense, $sType, $sDuration = '')
+    public function prolongLicense($iProfileId, $iProductId, $iCount, $sOrder, $sLicense, $sType, $sDuration = '', $iTrial = 0)
     {
     	$CNF = &$this->_oConfig->CNF;
 

+ 7 - 2
modules/boonex/market/classes/BxMarketModule.php

@@ -275,6 +275,7 @@ class BxMarketModule extends BxBaseModTextModule
 			'url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=view-product&id=' . $aItem[$CNF['FIELD_ID']]),
 			'price_single' => $aItem[$CNF['FIELD_PRICE_SINGLE']],
 			'price_recurring' => $aItem[$CNF['FIELD_PRICE_RECURRING']],
+		    'trial_recurring' => $aItem[$CNF['FIELD_TRIAL_RECURRING']]
         );
     }
 
@@ -299,6 +300,7 @@ class BxMarketModule extends BxBaseModTextModule
 				'url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=view-product&id=' . $aItem[$CNF['FIELD_ID']]),
 				'price_single' => $aItem[$CNF['FIELD_PRICE_SINGLE']],
             	'price_recurring' => $aItem[$CNF['FIELD_PRICE_RECURRING']],
+            	'trial_recurring' => $aItem[$CNF['FIELD_TRIAL_RECURRING']]
            );
 
         return $aResult;
@@ -335,15 +337,17 @@ class BxMarketModule extends BxBaseModTextModule
         if(empty($aItem) || !is_array($aItem))
 			return array();
 
+        $iTrial = 0;
 		$sDuration = '';
 		if($sType == BX_MARKET_LICENSE_TYPE_RECURRING) {
 			$aProduct = $this->_oDb->getContentInfoById($iItemId);
 
+			$iTrial = $aProduct[$this->_oConfig->CNF['FIELD_TRIAL_RECURRING']];
 			$sDuration = $aProduct[$this->_oConfig->CNF['FIELD_DURATION_RECURRING']];
 		}
 
     	$sAction = $this->_oDb->hasLicenseByOrder($iClientId, $iItemId, $sOrder) ? 'prolong' : 'register';
-        if(!$this->_oDb->{$sAction . 'License'}($iClientId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType, $sDuration))
+        if(!$this->_oDb->{$sAction . 'License'}($iClientId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType, $sDuration, $iTrial))
             return array();
 
 		bx_alert($this->getName(), 'license_' . $sAction, 0, false, array(
@@ -353,7 +357,8 @@ class BxMarketModule extends BxBaseModTextModule
 			'license' => $sLicense,
 			'type' => $sType,
 			'count' => $iItemCount,
-			'duration' => $sDuration
+			'duration' => $sDuration,
+		    'trial' => $iTrial
 		));
 
         return $aItem;

+ 3 - 0
modules/boonex/market/install/langs/en.xml

@@ -40,6 +40,9 @@
     <string name="_bx_market_form_entry_input_price_recurring_inf"><![CDATA[Select 'None' to make the product free.]]></string>
     <string name="_bx_market_form_entry_input_sys_duration_recurring"><![CDATA[Billing period]]></string>
     <string name="_bx_market_form_entry_input_duration_recurring"><![CDATA[Billing period]]></string>
+    <string name="_bx_market_form_entry_input_sys_trial_recurring"><![CDATA[Recurring trial]]></string>
+    <string name="_bx_market_form_entry_input_trial_recurring"><![CDATA[Trial period]]></string>
+    <string name="_bx_market_form_entry_input_trial_recurring_inf"><![CDATA[The number of days new customers should receive a free trial. Leave empty to disable Trial Period.]]></string>
     <string name="_bx_market_form_entry_input_sys_header_beg_single"><![CDATA[One-time payment: begin]]></string>
     <string name="_bx_market_form_entry_input_header_beg_single"><![CDATA[One-time payment]]></string>
     <string name="_bx_market_form_entry_input_sys_header_beg_recurring"><![CDATA[Recurring payment: begin]]></string>

+ 27 - 21
modules/boonex/market/install/sql/install.sql

@@ -18,6 +18,7 @@ CREATE TABLE IF NOT EXISTS `bx_market_products` (
   `price_single` float NOT NULL default '0',
   `price_recurring` float NOT NULL default '0',
   `duration_recurring` varchar(16) NOT NULL default 'month',
+  `trial_recurring` int(11) NOT NULL default '0',
   `views` int(11) NOT NULL default '0',
   `rate` float NOT NULL default '0',
   `votes` int(11) NOT NULL default '0',
@@ -300,6 +301,7 @@ INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `ch
 ('bx_market', 'bx_market', 'price_single', '', '', 0, 'text', '_bx_market_form_entry_input_sys_price_single', '_bx_market_form_entry_input_price_single', '_bx_market_form_entry_input_price_single_inf', 0, 0, 0, '', '', '', '', '', '', 'Float', '', 1, 0),
 ('bx_market', 'bx_market', 'price_recurring', '', '#!bx_market_prices', 0, 'select', '_bx_market_form_entry_input_sys_price_recurring', '_bx_market_form_entry_input_price_recurring', '_bx_market_form_entry_input_price_recurring_inf', 0, 0, 0, '', '', '', '', '', '', 'Float', '', 1, 0),
 ('bx_market', 'bx_market', 'duration_recurring', 'month', '#!bx_market_durations', 0, 'select', '_bx_market_form_entry_input_sys_duration_recurring', '_bx_market_form_entry_input_duration_recurring', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_market', 'bx_market', 'trial_recurring', '', '', 0, 'text', '_bx_market_form_entry_input_sys_trial_recurring', '_bx_market_form_entry_input_trial_recurring', '_bx_market_form_entry_input_trial_recurring_inf', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
 ('bx_market', 'bx_market', 'added', '', '', 0, 'datetime', '_bx_market_form_entry_input_sys_added', '_bx_market_form_entry_input_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_market', 'bx_market', 'changed', '', '', 0, 'datetime', '_bx_market_form_entry_input_sys_changed', '_bx_market_form_entry_input_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_market', 'bx_market', 'header_beg_single', '', '', 0, 'block_header', '_bx_market_form_entry_input_sys_header_beg_single', '_bx_market_form_entry_input_header_beg_single', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
@@ -328,17 +330,18 @@ INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for
 ('bx_market_entry_add', 'warning_recurring', 2147483647, 1, 13),
 ('bx_market_entry_add', 'duration_recurring', 2147483647, 1, 14),
 ('bx_market_entry_add', 'price_recurring', 2147483647, 1, 15),
-('bx_market_entry_add', 'header_end_recurring', 2147483647, 1, 16),
-('bx_market_entry_add', 'header_beg_privacy', 2147483647, 1, 17),
-('bx_market_entry_add', 'allow_view_to', 2147483647, 1, 18),
-('bx_market_entry_add', 'allow_purchase_to', 2147483647, 1, 19),
-('bx_market_entry_add', 'allow_comment_to', 2147483647, 1, 20),
-('bx_market_entry_add', 'allow_vote_to', 2147483647, 1, 21),
-('bx_market_entry_add', 'header_end_privacy', 2147483647, 1, 22),
-('bx_market_entry_add', 'notes', 2147483647, 1, 23),
-('bx_market_entry_add', 'location', 2147483647, 1, 24),
-('bx_market_entry_add', 'do_submit', 2147483647, 0, 25),
-('bx_market_entry_add', 'do_publish', 2147483647, 1, 26),
+('bx_market_entry_add', 'trial_recurring', 2147483647, 1, 16),
+('bx_market_entry_add', 'header_end_recurring', 2147483647, 1, 17),
+('bx_market_entry_add', 'header_beg_privacy', 2147483647, 1, 18),
+('bx_market_entry_add', 'allow_view_to', 2147483647, 1, 19),
+('bx_market_entry_add', 'allow_purchase_to', 2147483647, 1, 20),
+('bx_market_entry_add', 'allow_comment_to', 2147483647, 1, 21),
+('bx_market_entry_add', 'allow_vote_to', 2147483647, 1, 22),
+('bx_market_entry_add', 'header_end_privacy', 2147483647, 1, 23),
+('bx_market_entry_add', 'notes', 2147483647, 1, 24),
+('bx_market_entry_add', 'location', 2147483647, 1, 25),
+('bx_market_entry_add', 'do_submit', 2147483647, 0, 26),
+('bx_market_entry_add', 'do_publish', 2147483647, 1, 27),
 
 ('bx_market_entry_delete', 'notes', 2147483647, 0, 0),
 ('bx_market_entry_delete', 'location', 2147483647, 0, 0),
@@ -349,6 +352,7 @@ INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for
 ('bx_market_entry_delete', 'header_beg_recurring', 2147483647, 0, 0),
 ('bx_market_entry_delete', 'duration_recurring', 2147483647, 0, 0),
 ('bx_market_entry_delete', 'price_recurring', 2147483647, 0, 0),
+('bx_market_entry_delete', 'trial_recurring', 2147483647, 0, 0),
 ('bx_market_entry_delete', 'header_end_recurring', 2147483647, 0, 0),
 ('bx_market_entry_delete', 'pictures', 2147483647, 0, 0),
 ('bx_market_entry_delete', 'files', 2147483647, 0, 0),
@@ -381,16 +385,17 @@ INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for
 ('bx_market_entry_edit', 'warning_recurring', 2147483647, 1, 14),
 ('bx_market_entry_edit', 'duration_recurring', 2147483647, 1, 15),
 ('bx_market_entry_edit', 'price_recurring', 2147483647, 1, 16),
-('bx_market_entry_edit', 'header_end_recurring', 2147483647, 1, 17),
-('bx_market_entry_edit', 'header_beg_privacy', 2147483647, 1, 18),
-('bx_market_entry_edit', 'allow_view_to', 2147483647, 1, 19),
-('bx_market_entry_edit', 'allow_purchase_to', 2147483647, 1, 20),
-('bx_market_entry_edit', 'allow_comment_to', 2147483647, 1, 21),
-('bx_market_entry_edit', 'allow_vote_to', 2147483647, 1, 22),
-('bx_market_entry_edit', 'header_end_privacy', 2147483647, 1, 23),
-('bx_market_entry_edit', 'notes', 2147483647, 1, 24),
-('bx_market_entry_edit', 'location', 2147483647, 1, 25),
-('bx_market_entry_edit', 'do_submit', 2147483647, 1, 26),
+('bx_market_entry_edit', 'trial_recurring', 2147483647, 1, 17),
+('bx_market_entry_edit', 'header_end_recurring', 2147483647, 1, 18),
+('bx_market_entry_edit', 'header_beg_privacy', 2147483647, 1, 19),
+('bx_market_entry_edit', 'allow_view_to', 2147483647, 1, 20),
+('bx_market_entry_edit', 'allow_purchase_to', 2147483647, 1, 21),
+('bx_market_entry_edit', 'allow_comment_to', 2147483647, 1, 22),
+('bx_market_entry_edit', 'allow_vote_to', 2147483647, 1, 23),
+('bx_market_entry_edit', 'header_end_privacy', 2147483647, 1, 24),
+('bx_market_entry_edit', 'notes', 2147483647, 1, 25),
+('bx_market_entry_edit', 'location', 2147483647, 1, 26),
+('bx_market_entry_edit', 'do_submit', 2147483647, 1, 27),
 
 ('bx_market_entry_view', 'notes', 2147483647, 0, 0),
 ('bx_market_entry_view', 'location', 2147483647, 0, 0),
@@ -401,6 +406,7 @@ INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for
 ('bx_market_entry_view', 'header_beg_recurring', 2147483647, 0, 0),
 ('bx_market_entry_view', 'duration_recurring', 2147483647, 0, 0),
 ('bx_market_entry_view', 'price_recurring', 2147483647, 0, 0),
+('bx_market_entry_view', 'trial_recurring', 2147483647, 0, 0),
 ('bx_market_entry_view', 'header_end_recurring', 2147483647, 0, 0),
 ('bx_market_entry_view', 'pictures', 2147483647, 0, 0),
 ('bx_market_entry_view', 'files', 2147483647, 0, 0),

+ 14 - 0
modules/boonex/payment/classes/BxPaymentConfig.php

@@ -33,6 +33,7 @@ class BxPaymentConfig extends BxBaseModPaymentConfig
 
         	'KEY_ARRAY_PRICE_SINGLE' => 'price_single',
         	'KEY_ARRAY_PRICE_RECURRING' => 'price_recurring',
+        	'KEY_ARRAY_TRIAL_RECURRING' => 'trial_recurring',
         
 	        // some language keys
         	'T' => array(
@@ -146,6 +147,19 @@ class BxPaymentConfig extends BxBaseModPaymentConfig
 		return (float)$fPrice;
     }
 
+    public function getTrial($sType, $aItem)
+    {
+        $iTrial = 0;
+
+		switch($sType) {
+			case BX_PAYMENT_TYPE_RECURRING:
+				$iTrial = $aItem[$this->getKey('KEY_ARRAY_TRIAL_RECURRING')];
+				break;
+		}
+
+		return (int)$iTrial;
+    }
+
     public function getModuleId($mixedId)
     {
     	if(is_numeric($mixedId))

+ 19 - 2
modules/boonex/payment/classes/BxPaymentModule.php

@@ -428,7 +428,8 @@ class BxPaymentModule extends BxBaseModPaymentModule
         	return $this->_oTemplate->displayPageCodeError($aResult['message']);
 
 		$aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$aResult['pending_id']));
-		if($aPending['type'] == BX_PAYMENT_TYPE_RECURRING)
+		$bTypeRecurring = $aPending['type'] == BX_PAYMENT_TYPE_RECURRING;
+		if($bTypeRecurring)
 		    $this->registerSubscription($aPending, array(
 		        'customer_id' => $aResult['customer_id'], 
 		    	'subscription_id' => $aResult['subscription_id']
@@ -441,7 +442,7 @@ class BxPaymentModule extends BxBaseModPaymentModule
 			$this->getObjectJoin()->performJoin((int)$aPending['id'], isset($aResult['client_name']) ? $aResult['client_name'] : '', isset($aResult['client_email']) ? $aResult['client_email'] : '');
 
 		//--- Register payment for purchased items in associated modules 
-		if(!empty($aResult['paid']))
+		if(!empty($aResult['paid']) || ($bTypeRecurring && !empty($aResult['trial'])))
 			$this->registerPayment($aPending);
 
 		if($oProvider->needRedirect()) {
@@ -598,6 +599,15 @@ class BxPaymentModule extends BxBaseModPaymentModule
 	    $this->onSubscriptionCreate($aPending);
 	}
 
+	public function updateSubscription($aPending, $aParams = array())
+	{
+	    $this->_oDb->updateSubscription($aParams, array(
+	        'pending_id' => $aPending['id']
+	    ));
+
+	    $this->onSubscriptionUpdate($aPending);
+	}
+
 	public function cancelSubscription($mixedPending)
 	{
 		$aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
@@ -639,6 +649,13 @@ class BxPaymentModule extends BxBaseModPaymentModule
 		//--- 'System' -> 'Create Subscription' for Alerts Engine ---//
 	}
 
+	public function onSubscriptionUpdate($aPending, $aResult = array())
+	{
+	    //--- 'System' -> 'Update Subscription' for Alerts Engine ---//
+		bx_alert('system', 'update_subscription', 0, $aPending['client_id'], array('pending' => $aPending));
+		//--- 'System' -> 'Update Subscription' for Alerts Engine ---//
+	}
+	
 	public function onSubscriptionCancel($aPending, $aResult = array())
 	{
 		//--- 'System' -> 'Cancel Subscription' for Alerts Engine ---//

+ 11 - 7
modules/boonex/payment/classes/BxPaymentProviderStripe.php

@@ -144,7 +144,8 @@ class BxPaymentProviderStripe extends BxBaseModPaymentProvider implements iBxBas
 		    'subscription_id' => '',
 			'client_name' => '',
 			'client_email' => '',
-			'paid' => false
+			'paid' => false,
+			'trial' => false,
 		);
 
 		switch($aPending['type']) {
@@ -181,7 +182,8 @@ class BxPaymentProviderStripe extends BxBaseModPaymentProvider implements iBxBas
 					'message' => $this->_sLangsPrefix . 'strp_msg_subscribed',
                     'customer_id' => $sCustomerId,
 				    'subscription_id' => $sOrderId,
-					'client_email' => $aCustomer['email']
+					'client_email' => $aCustomer['email'],
+				    'trial' => $aSubscription['status'] == 'trialing'
 				));
 				break;
 		}
@@ -478,8 +480,6 @@ class BxPaymentProviderStripe extends BxBaseModPaymentProvider implements iBxBas
 
 	protected function _createSubscription($sToken, $iPendingId, &$aClient, &$aCartInfo)
 	{
-		$bTrial = false;
-
 		if(empty($this->_oCustomer))
 			$this->_createCustomer($sToken, $aClient);
 
@@ -491,9 +491,8 @@ class BxPaymentProviderStripe extends BxBaseModPaymentProvider implements iBxBas
 			if(empty($aItem) || !is_array($aItem))
 				return false;
 
-			//TODO: "Trial" wasn't finaly relized. It's just a draft.
-			if(isset($aItem['trial']) && $aItem['trial'] === true)
-				$bTrial = true;
+			$iTrial = $this->_oModule->_oConfig->getTrial(BX_PAYMENT_TYPE_RECURRING, $aItem);
+			$bTrial = !empty($iTrial);
 
 			$oSubscription = $this->_oCustomer->subscriptions->create(array(
 				'plan' => $aItem['name'],
@@ -635,6 +634,11 @@ class BxPaymentProviderStripe extends BxBaseModPaymentProvider implements iBxBas
 		if($this->_bCheckAmount && ((float)$aPending['amount'] != $fChargeAmount || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $sChargeCurrency) !== 0))
 			return false;
 
+        if($aPending['type'] == BX_PAYMENT_TYPE_RECURRING)
+            $this->_oModule->updateSubscription($aPending, array(
+                'paid' => 1
+            ));
+
 		return $this->_oModule->registerPayment($aPending);
 	}
 

+ 2 - 1
modules/boonex/payment/install/sql/install.sql

@@ -66,7 +66,8 @@ CREATE TABLE IF NOT EXISTS `bx_payment_subscriptions` (
   `subscription_id` varchar(32) NOT NULL default '',
   `paid` tinyint(4) NOT NULL default '0',
   `date` int(11) NOT NULL default '0',
-  PRIMARY KEY(`id`)
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `pending_id` (`pending_id`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
 CREATE TABLE IF NOT EXISTS `bx_payment_transactions_pending` (

+ 5 - 2
modules/boonex/russian/data/langs/bx_market/ru.xml

@@ -35,11 +35,14 @@
 	<string name="_bx_market_form_entry_input_sys_price_single"><![CDATA[Цена]]></string>
 	<string name="_bx_market_form_entry_input_price_single"><![CDATA[Цена]]></string>
     <string name="_bx_market_form_entry_input_price_single_inf"><![CDATA[Оставьте пустым, чтобы сделать продукт бесплатным.]]></string>
-	<string name="_bx_market_form_entry_input_sys_price_recurring"><![CDATA[Оплата за месяц]]></string>
-	<string name="_bx_market_form_entry_input_price_recurring"><![CDATA[Оплата за месяц]]></string>
+	<string name="_bx_market_form_entry_input_sys_price_recurring"><![CDATA[Периодические выплаты]]></string>
+	<string name="_bx_market_form_entry_input_price_recurring"><![CDATA[Оплата за период]]></string>
     <string name="_bx_market_form_entry_input_price_recurring_inf"><![CDATA[Выберите 'Нет', чтобы сделать продукт бесплатным.]]></string>
 	<string name="_bx_market_form_entry_input_sys_duration_recurring"><![CDATA[Период оплаты]]></string>
     <string name="_bx_market_form_entry_input_duration_recurring"><![CDATA[Период оплаты]]></string>
+    <string name="_bx_market_form_entry_input_sys_trial_recurring"><![CDATA[Пробный период]]></string>
+    <string name="_bx_market_form_entry_input_trial_recurring"><![CDATA[Пробный период]]></string>
+    <string name="_bx_market_form_entry_input_trial_recurring_inf"><![CDATA[Количество пробных дней, которое новые пользователи получат бесплатно. Оставьте пустым для отключения Пробного Периода.]]></string>
     <string name="_bx_market_form_entry_input_sys_header_beg_single"><![CDATA[Разовая оплата: начало]]></string>
     <string name="_bx_market_form_entry_input_header_beg_single"><![CDATA[Разовая оплата]]></string>
     <string name="_bx_market_form_entry_input_sys_header_beg_recurring"><![CDATA[Подписка: начало]]></string>