Ver Fonte

Ticket #5153 - Contexts: Improve paid join.

AntonLV há 1 ano atrás
pai
commit
85a671655f

+ 1 - 0
modules/base/general/classes/BxBaseModGeneralMenuViewActions.php

@@ -591,6 +591,7 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
                 return '';
 
             $this->_oMenuActions->setContentId($this->_iContentId);
+            $this->_oMenuActions->addMarkers($this->getMarkers());
 
             $this->addMarkers($this->_oMenuActions->getMarkers());
         }

+ 38 - 3
modules/base/groups/classes/BxBaseModGroupsConfig.php

@@ -55,9 +55,13 @@ class BxBaseModGroupsConfig extends BxBaseModProfileConfig
         return isset($this->_aHtmlIds[$sKey]) ? $this->_aHtmlIds[$sKey] : '';
     }
 
-    public function getCurrency()
+    public function getCurrency($iAuthorId = 0)
     {
-    	return $this->_aCurrency;
+        if(!$iAuthorId)
+            return $this->_aCurrency;
+
+        $aCurrency = BxDolPayments::getInstance()->getCurrencyInfo($iAuthorId);
+        return !empty($aCurrency) && is_array($aCurrency) ? $aCurrency : $this->_aCurrency;
     }
 
     public function isFans()
@@ -85,11 +89,42 @@ class BxBaseModGroupsConfig extends BxBaseModProfileConfig
         return $this->_bUseCoverAsThumb;
     }
 
+    public function getRolesPurchasable()
+    {
+        $aRoles = parent::getRoles();
+
+        $aResult = [];
+        foreach($aRoles as $iValue => $sTitle)
+            if(!in_array($iValue, [BX_BASE_MOD_GROUPS_ROLE_ADMINISTRATOR, BX_BASE_MOD_GROUPS_ROLE_MODERATOR]))
+                $aResult[$iValue] = $sTitle;
+
+        return $aResult;
+    }
+
     public function getPriceName($sName)
     {
         return uriGenerate($sName, $this->CNF['TABLE_PRICES'], $this->CNF['FIELD_PRICE_NAME'], ['lowercase' => false]);
     }
-    
+
+    public function getPriceTitle($iAuthorId, $aPrice)
+    {
+        $aCurrency = $this->getCurrency($iAuthorId);
+
+        $sPrice = _t_format_currency_ext($aPrice['price'], ['sign' => $aCurrency['sign']]);
+
+        $sResult = '';
+        if(!empty($aPrice['period']) && !empty($aPrice['period_unit'])) {
+            $bPeriods = (int)$aPrice['period'] > 1;
+            $sDuration = ($bPeriods ? $aPrice['period'] . ' ' : '') . _t('_duration_' . $aPrice['period_unit'] . ($bPeriods ? '_pl' : ''));
+
+            $sResult = _t('_price_recurring', $sPrice, $sDuration);
+        }
+        else
+            $sResult = _t('_price_single', $sPrice);
+
+        return $sResult;
+    }
+
     protected function _initUseCoverAsThumb()
     {
         if(($sKey = 'PARAM_USE_COVER_AS_THUMB') && !empty($this->CNF[$sKey]))

+ 12 - 1
modules/base/groups/classes/BxBaseModGroupsDb.php

@@ -333,7 +333,7 @@ class BxBaseModGroupsDb extends BxBaseModProfileDb
         $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
 
         if(!isset($aParams['order']) || empty($aParams['order']))
-            $sOrderClause = "ORDER BY `tp`.`Order` ASC";
+            $sOrderClause = "ORDER BY `tp`.`order` ASC";
 
         switch($aParams['type']) {
             case 'by_id':
@@ -360,6 +360,12 @@ class BxBaseModGroupsDb extends BxBaseModProfileDb
                 );
 
                 $sWhereClause .= "AND `tp`.`profile_id`=:profile_id";
+
+                if(!empty($aParams['default'])) {
+                    $aMethod['name'] = 'getRow';
+
+                    $sWhereClause .= " AND `tp`.`default`='1'";
+                }
                 break;
 
             case 'by_prpp':
@@ -388,6 +394,11 @@ class BxBaseModGroupsDb extends BxBaseModProfileDb
         ));
     }
 
+    public function updatePrices($aSet, $aWhere)
+    {
+        return (int)$this->query("UPDATE `" . $this->_oConfig->CNF['TABLE_PRICES'] . "` SET " . $this->arrayToSQL($aSet) . "  WHERE " . $this->arrayToSQL($aWhere, " AND ")) > 0;
+    }
+    
     public function deletePrices($aWhere)
     {
         return (int)$this->query("DELETE FROM `" . $this->_oConfig->CNF['TABLE_PRICES'] . "` WHERE " . $this->arrayToSQL($aWhere, " AND ")) > 0;

+ 17 - 2
modules/base/groups/classes/BxBaseModGroupsFormPrice.php

@@ -22,6 +22,17 @@ class BxBaseModGroupsFormPrice extends BxTemplFormView
 
         $CNF = &$this->_oModule->_oConfig->CNF;
 
+        if(isset($this->aInputs[$CNF['FIELD_PRICE_ROLE_ID']])) {
+            $aRoles = $this->_oModule->_oConfig->getRolesPurchasable();
+
+            $this->aInputs[$CNF['FIELD_PRICE_ROLE_ID']]['values'][] = ['key' => '', 'value' => _t('_sys_please_select')];
+            foreach($aRoles as $iId => $sTitle)
+                $this->aInputs[$CNF['FIELD_PRICE_ROLE_ID']]['values'][] = [
+                    'key' => 'r' . $iId, 
+                    'value' => _t($sTitle)
+                ];
+        }
+
         if(isset($this->aInputs[$CNF['FIELD_PRICE_NAME']])) {
             $sJsObject = $this->_oModule->_oConfig->getJsObject('prices');
 
@@ -39,16 +50,20 @@ class BxBaseModGroupsFormPrice extends BxTemplFormView
 
     public function setRoleId($iRoleId)
     {
+        if($iRoleId === false)
+            return;
+
         $CNF = &$this->_oModule->_oConfig->CNF;
 
-        $this->aInputs[$CNF['FIELD_PRICE_ROLE_ID']]['value'] = (int)$iRoleId;
+        $this->aInputs[$CNF['FIELD_PRICE_ROLE_ID']]['value'] = $this->_oModule->_oConfig->roleIdI2S($iRoleId);
+
         if(empty($this->aInputs[$CNF['FIELD_PRICE_NAME']]['value'])) {
             $aRoles = $this->_oModule->_oConfig->getRoles();
             $this->aInputs[$CNF['FIELD_PRICE_NAME']]['value'] = $this->_oModule->_oConfig->getPriceName(_t($aRoles[$iRoleId]));
         }
     }
 
-    public function insert ($aValsToAdd = array(), $isIgnore = false)
+    public function insert ($aValsToAdd = [], $isIgnore = false)
     {
         $CNF = &$this->_oModule->_oConfig->CNF;
 

+ 15 - 3
modules/base/groups/classes/BxBaseModGroupsGridPrices.php

@@ -32,7 +32,7 @@ class BxBaseModGroupsGridPrices extends BxTemplGrid
 
         $CNF = $this->_oModule->_oConfig->CNF;
 
-        $this->_aRoles = BxDolFormQuery::getDataItems($CNF['OBJECT_PRE_LIST_ROLES']);
+        $this->_aRoles = $this->_oModule->_oConfig->getRolesPurchasable();
         $this->_aPeriodUnits = BxDolForm::getDataItems($CNF['OBJECT_PRE_LIST_PERIOD_UNITS']);
 
         $this->_iGroupProfileId = 0;
@@ -68,10 +68,12 @@ class BxBaseModGroupsGridPrices extends BxTemplGrid
 
     protected function _getCellPrice($mixedValue, $sKey, $aField, $aRow)
     {
+        $CNF = $this->_oModule->_oConfig->CNF;
+
         if((float)$mixedValue != 0) {
-            $aCurrency = $this->_oModule->_oConfig->getCurrency();
+            $aCurrency = $this->_oModule->_oConfig->getCurrency($this->_aGroupContentInfo[$CNF['FIELD_AUTHOR']]);
 
-        $mixedValue = html_entity_decode($aCurrency['sign']) . $mixedValue;
+            $mixedValue = html_entity_decode($aCurrency['sign']) . $mixedValue;
         }
         else 
             $mixedValue = _t('_free');
@@ -79,6 +81,16 @@ class BxBaseModGroupsGridPrices extends BxTemplGrid
         return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
     }
 
+    protected function _roleIdI2S($iValue)
+    {
+        return $this->_oModule->_oConfig->roleIdI2S($iValue);
+    }
+
+    protected function _roleIdS2I($sValue)
+    {
+        return $this->_oModule->_oConfig->roleIdS2I($sValue);
+    }
+
     protected function _getIds()
     {
         $aIds = bx_get('ids');

+ 61 - 33
modules/base/groups/classes/BxBaseModGroupsGridPricesManage.php

@@ -19,10 +19,8 @@ class BxBaseModGroupsGridPricesManage extends BxBaseModGroupsGridPrices
     {
         parent::__construct ($aOptions, $oTemplate);
 
-        $CNF = &$this->_oModule->_oConfig->CNF;
-
-        $this->_iRoleId = 0;
-        if(($iRoleId = (int)bx_get('role_id')) !== false)
+        $this->_iRoleId = false;
+        if(($iRoleId = bx_get('role_id')) !== false)
             $this->setRoleId($iRoleId);
     }
 
@@ -50,9 +48,17 @@ class BxBaseModGroupsGridPricesManage extends BxBaseModGroupsGridPrices
          return '/api.php?r=system/perfom_action_api/TemplServiceGrid/&params[]=&o=' . $this->_sObject . '&a=' . $sAction . '&profile_id=' . $this->_iGroupProfileId . '&role_id=' . $this->_iRoleId . '&id=' . $iId;
     }
 
-    public function setRoleId($iRoleId)
+    public function setRoleId($mixedRoleId)
     {
-        $this->_iRoleId = (int)$iRoleId;
+        if(is_string($mixedRoleId)) {
+            if($mixedRoleId === '')
+                return;
+
+            if(!is_numeric($mixedRoleId))
+                $mixedRoleId = $this->_roleIdS2I($mixedRoleId);
+        }
+
+        $this->_iRoleId = (int)$mixedRoleId;
         $this->_aQueryAppend['role_id'] = $this->_iRoleId;
     }
 
@@ -88,21 +94,27 @@ class BxBaseModGroupsGridPricesManage extends BxBaseModGroupsGridPrices
             return $this->_bIsApi ? [bx_api_get_msg($mixedResult)] : echoJson(['msg' => $mixedResult]);
 
         $sFilter = bx_get('filter');
-        if(strpos($sFilter, $this->_sParamsDivider) !== false)
-            list($this->_iRoleId, $sFilter) = explode($this->_sParamsDivider, $sFilter);
+        if(strpos($sFilter, $this->_sParamsDivider) !== false) {
+            list($sRoleId, $sFilter) = explode($this->_sParamsDivider, $sFilter);
+            if($sRoleId)
+                $this->setRoleId($sRoleId);
+        }
 
-        if(!is_numeric($this->_iRoleId) && ($iRoleId = bx_get('role_id')) !== false)
-            $this->_iRoleId = (int)$iRoleId;
+        if($this->_iRoleId === false && ($sRoleId = bx_get('role_id')) !== false)
+            $this->setRoleId($sRoleId);
 
         $sForm = $CNF['OBJECT_FORM_PRICE_DISPLAY_ADD'];
         $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_PRICE'], $CNF['OBJECT_FORM_PRICE_DISPLAY_ADD']);
         $oForm->setId($sForm);
         $oForm->setName($sForm);
-        $oForm->setAction(BX_DOL_URL_ROOT . bx_append_url_params('grid.php', array('o' => $this->_sObject, 'a' => $sAction, 'profile_id' => $this->_iGroupProfileId, 'role_id' => $this->_iRoleId)));
+        $oForm->setAction(BX_DOL_URL_ROOT . bx_append_url_params('grid.php', ['o' => $this->_sObject, 'a' => $sAction, 'profile_id' => $this->_iGroupProfileId]));
         $oForm->setRoleId($this->_iRoleId);
 
         $oForm->initChecker();
         if($oForm->isSubmittedAndValid()) {
+            $sRoleId = $oForm->getCleanValue('role_id');
+            BxDolForm::setSubmittedValue('role_id', $this->_roleIdS2I($sRoleId), $oForm->aFormAttrs['method']);
+
             $iPeriod = $oForm->getCleanValue('period');
             $sPeriodUnit = $oForm->getCleanValue('period_unit');
 
@@ -113,6 +125,9 @@ class BxBaseModGroupsGridPricesManage extends BxBaseModGroupsGridPrices
             if(!empty($aPrice) && is_array($aPrice))
                 return ($sMsg = _t($CNF['T']['err_price_duplicate'])) && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : echoJson(['msg' => $sMsg]);
 
+            if($oForm->getCleanValue('default') != 0)
+                $this->_oModule->_oDb->updatePrices(['default' => 0], ['profile_id' => $this->_iGroupProfileId]);
+
             $iId = (int)$oForm->insert(['profile_id' => $this->_iGroupProfileId, 'added' => time(), 'order' => $this->_oModule->_oDb->getPriceOrderMax($this->_iRoleId) + 1]);
             if($iId != 0)
                 $aRes = ['grid' => $this->getCode(false), 'blink' => $iId];
@@ -153,14 +168,19 @@ class BxBaseModGroupsGridPricesManage extends BxBaseModGroupsGridPrices
         if(!is_array($aItem) || empty($aItem))
             return $this->_bIsApi ? [] : echoJson([]);
 
+        $aItem['role_id'] = $this->_roleIdI2S($aItem['role_id']);
+
         $sForm = $CNF['OBJECT_FORM_PRICE_DISPLAY_EDIT'];
         $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_PRICE'], $CNF['OBJECT_FORM_PRICE_DISPLAY_EDIT']);
         $oForm->setId($sForm);
         $oForm->setName($sForm);
-        $oForm->setAction(BX_DOL_URL_ROOT . bx_append_url_params('grid.php', ['o' => $this->_sObject, 'a' => $sAction, 'profile_id' => $this->_iGroupProfileId, 'role_id' => $this->_iRoleId]));
+        $oForm->setAction(BX_DOL_URL_ROOT . bx_append_url_params('grid.php', ['o' => $this->_sObject, 'a' => $sAction, 'profile_id' => $this->_iGroupProfileId]));
 
         $oForm->initChecker($aItem);
         if($oForm->isSubmittedAndValid()) {
+            if($oForm->getCleanValue('default') != 0)
+                $this->_oModule->_oDb->updatePrices(['default' => 0], ['profile_id' => $this->_iGroupProfileId]);
+
             if($oForm->update($aItem['id']) !== false)
                 $aRes = ['grid' => $this->getCode(false), 'blink' => $aItem['id']];
             else
@@ -189,17 +209,17 @@ class BxBaseModGroupsGridPricesManage extends BxBaseModGroupsGridPrices
 
     	$aIds = bx_get('ids');
         if(!$aIds || !is_array($aIds))
-            return echoJson(array());
+            return echoJson([]);
 
         $iAffected = 0;
-        $aIdsAffected = array();
+        $aIdsAffected = [];
         foreach($aIds as $iId)
-            if($this->_oModule->_oDb->deletePrices(array('id' => $iId))) {
+            if($this->_oModule->_oDb->deletePrices(['id' => $iId])) {
                 $aIdsAffected[] = $iId;
                 $iAffected++;
             }
 
-        return echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected) : array('msg' => _t($CNF['T']['err_cannot_perform'])));
+        return echoJson($iAffected ? ['grid' => $this->getCode(false), 'blink' => $aIdsAffected] : ['msg' => _t($CNF['T']['err_cannot_perform'])]);
     }
 
     protected function _addJsCss()
@@ -217,32 +237,39 @@ class BxBaseModGroupsGridPricesManage extends BxBaseModGroupsGridPrices
         ]);
     }
 
+    protected function _getCellDefaultPrice($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault((int)$mixedValue != 0 ? _t('_Yes') : '', $sKey, $aField, $aRow);
+    }
+
     protected function _getFilterControls()
     {
         parent::_getFilterControls();
 
         $sContent = '';
-        $oForm = new BxTemplFormView(array());
+        $oForm = new BxTemplFormView([]);
 
-        $aInputRoles = array(
+        $aInputRoles = [
             'type' => 'select',
             'name' => 'role',
-            'attrs' => array(
+            'attrs' => [
                 'id' => 'bx-grid-level-' . $this->_sObject,
                 'onChange' => 'javascript:' . $this->_oModule->_oConfig->getJsObject('prices') . '.onChangeRole()'
-            ),
+            ],
             'value' => $this->_iRoleId,
-            'values' => $this->_aRoles
-        );
+            'values' => ['' => _t('_Select_all')]
+        ];
+        foreach($this->_aRoles as $iId => $sTitle)
+            $aInputRoles['values'][$this->_roleIdI2S($iId)] = $sTitle;
         $sContent .=  $oForm->genRow($aInputRoles);
 
-        $aInputSearch = array(
+        $aInputSearch = [
             'type' => 'text',
             'name' => 'keyword',
-            'attrs' => array(
+            'attrs' => [
                 'id' => 'bx-grid-search-' . $this->_sObject,
-            ),
-        );
+            ]
+        ];
         $sContent .= $oForm->genRow($aInputSearch);
 
         return $sContent;
@@ -250,17 +277,18 @@ class BxBaseModGroupsGridPricesManage extends BxBaseModGroupsGridPrices
 
     protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
     {
-        if(strpos($sFilter, $this->_sParamsDivider) !== false) {
-            list($iRoleId, $sFilter) = explode($this->_sParamsDivider, $sFilter);
-            if(!is_numeric($iRoleId))
-                $iRoleId = 0;
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString("AND `profile_id`=?", $this->_iGroupProfileId);
 
-            $this->setRoleId($iRoleId);
+        if(strpos($sFilter, $this->_sParamsDivider) !== false) {
+            list($sRoleId, $sFilter) = explode($this->_sParamsDivider, $sFilter);
+            if(!empty($sRoleId))
+                $this->setRoleId($this->_roleIdS2I($sRoleId));
         }
 
-        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString("AND `profile_id`=? AND `role_id`=? ", $this->_iGroupProfileId, $this->_iRoleId);
+        if($this->_iRoleId !== false)
+            $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `role_id`=? ", $this->_iRoleId);
 
-        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);;
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
     }
 
     protected function _isVisibleGrid ($a)

+ 1 - 1
modules/base/groups/classes/BxBaseModGroupsGridPricesView.php

@@ -137,7 +137,7 @@ class BxBaseModGroupsGridPricesView extends BxBaseModGroupsGridPrices
 
     protected function _getCellRoleId($mixedValue, $sKey, $aField, $aRow)
     {
-        return parent::_getCellDefault($this->_aRoles[$mixedValue], $sKey, $aField, $aRow);
+        return parent::_getCellDefault(!empty($aRow['caption']) ? $aRow['caption'] : $this->_aRoles[$mixedValue], $sKey, $aField, $aRow);
     }
 
     protected function _getActionChoose ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())

+ 15 - 0
modules/base/groups/classes/BxBaseModGroupsMenuViewActionsAll.php

@@ -26,6 +26,21 @@ class BxBaseModGroupsMenuViewActionsAll extends BxBaseModProfileMenuViewActionsA
                 'add' => 'checkAllowedFanAdd', 
                 'remove' => 'checkAllowedFanRemove'
             ];
+
+        if(($iContextPid = $this->_aContentInfo['profile_id']) && $this->_oModule->isPaidJoinByProfile($iContextPid)) {
+            $aDefault = $this->_oModule->_oDb->getPrices(['type' => 'by_profile_id', 'profile_id' => $iContextPid, 'default' => true]);
+            if(empty($aDefault) || !is_array($aDefault)) {
+                $aPrices = $this->_oModule->_oDb->getPrices(['type' => 'by_profile_id', 'profile_id' => $iContextPid]);
+                if(!empty($aPrices) && is_array($aPrices))
+                    $aDefault = reset($aPrices);
+            }
+
+            //TODO: Check markers parsing!
+            if(!empty($aDefault) && is_array($aDefault))
+                $this->addMarkers([
+                    'title_pay_and_join' => _t('_bx_groups_menu_item_title_pay_and_join', $this->_oModule->_oConfig->getPriceTitle($this->_aContentInfo[$CNF['FIELD_AUTHOR']], $aDefault))
+                ]);
+        }
     }
 
     protected function _isContentPublic($iContentId, $aPublicGroups = [])

+ 11 - 1
modules/base/profile/classes/BxBaseModProfileConfig.php

@@ -85,7 +85,17 @@ class BxBaseModProfileConfig extends BxBaseModGeneralConfig
 
         return $this->_aRoles;
     }
-    
+
+    public function roleIdI2S($iValue)
+    {
+        return 'r' . $iValue;
+    }
+
+    public function roleIdS2I($sValue)
+    {
+        return (int)substr($sValue, 1);
+    }
+
     protected function _initRoles()
     {
         if(empty($this->CNF['OBJECT_PRE_LIST_ROLES'])) 

+ 1 - 1
modules/boonex/artificer/data/template/mod_profile/menu_custom_item_actions.html

@@ -1,4 +1,4 @@
 <span class="__class_wrp__">
-    <a class="__class_link__ bx-stl-mil-gaps-sm flex flex-row flex-nowrap sm:items-center" href="__link__" onclick="__onclick__" title="__title_attr__"__attrs__><span class="bx-mi-icon flex items-center justify-center h-5 w-5"><bx_if:icon><i class="sys-icon __icon__"></i></bx_if:icon><bx_if:image><img class="h-5 w-5" style="background-image:url(__icon_url__)" src="<bx_icon_url:spacer.gif />" /></bx_if:image></span><bx_if:title><span class="bx-mi-text ltr:ml-1.5 ltr:first:ml-0 rtl:mr-1.5 rtl:first:mr-0 whitespace-nowrap truncate">__title__</span></bx_if:title></a>
+    <a class="__class_link__ bx-stl-mil-gaps-sm flex flex-row flex-nowrap sm:items-center" href="__link__" onclick="__onclick__"__attrs__><span class="bx-mi-icon flex items-center justify-center h-5 w-5"><bx_if:icon><i class="sys-icon __icon__"></i></bx_if:icon><bx_if:image><img class="h-5 w-5" style="background-image:url(__icon_url__)" src="<bx_icon_url:spacer.gif />" /></bx_if:image></span><bx_if:title><span class="bx-mi-text ltr:ml-1.5 ltr:first:ml-0 rtl:mr-1.5 rtl:first:mr-0 whitespace-nowrap truncate">__title__</span></bx_if:title></a>
     <bx_if:addon>__addon__</bx_if:addon>
 </span>

+ 1 - 1
modules/boonex/artificer/data/template/system/menu_custom_item.html

@@ -1,4 +1,4 @@
 <span class="__class_wrp__ bx-mi-highlight group flex items-center text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:text-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 text-sm font-normal rounded-md">
-    <a class="__class_link__ block p-2" href="__link__" onclick="__onclick__" title="__title_attr__"__attrs__><bx_include_auto:menu_icon.html /><bx_if:title><span class="bx-def-margin-sec-left-auto">__title__</span></bx_if:title></a>
+    <a class="__class_link__ block p-2" href="__link__" onclick="__onclick__"__attrs__><bx_include_auto:menu_icon.html /><bx_if:title><span class="bx-def-margin-sec-left-auto">__title__</span></bx_if:title></a>
     <bx_if:addon>__addon__</bx_if:addon>
 </span>

+ 13 - 3
modules/boonex/english/data/langs/system/en.xml

@@ -98,6 +98,8 @@
 	<string name="_Please select value"><![CDATA[Please select a value from the list]]></string>
         <string name="_polls_from"><![CDATA[Polls from: {0}]]></string>
 	<string name="_Preview"><![CDATA[Preview]]></string>
+        <string name="_price_recurring"><![CDATA[{0}/{1}]]></string>
+	<string name="_price_single"><![CDATA[{0}]]></string>
         <string name="_report_comment"><![CDATA[reported as '{0}']]></string>
         <string name="_report_comment_with_note"><![CDATA[reported as '{0}' with a note: {1}]]></string>
         <string name="_report_comment_check_in"><![CDATA[check-in]]></string>
@@ -118,8 +120,8 @@
 	<string name="_report_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
 	<string name="_report_err_wrong_type"><![CDATA[Wrong report type.]]></string>
 	<string name="_report_reported_as"><![CDATA[Reported as ]]></string>
-  <string name="_report_reported_by"><![CDATA[Reported by ]]></string>
-  <string name="_report_comments_count"><![CDATA[Comments ({0})]]></string>
+        <string name="_report_reported_by"><![CDATA[Reported by ]]></string>
+        <string name="_report_comments_count"><![CDATA[Comments ({0})]]></string>
 	<string name="_RSS_Feed_Title_Common"><![CDATA[{0} RSS]]></string>
 	<string name="_RSS_Feed_Title_Profile"><![CDATA[{0}'s Recent {1}]]></string>
 	<string name="_Rate"><![CDATA[Rate]]></string>
@@ -2099,6 +2101,14 @@
         <string name="_cmt_rvw_txt_do"><![CDATA[Review]]></string>
         <string name="_copyright"><![CDATA[&copy; {0} Company]]></string>
 	<string name="_delete"><![CDATA[delete]]></string>
+        <string name="_duration_day"><![CDATA[day]]></string>
+        <string name="_duration_day_pl"><![CDATA[days]]></string>
+        <string name="_duration_week"><![CDATA[week]]></string>
+        <string name="_duration_week_pl"><![CDATA[week]]></string>
+        <string name="_duration_month"><![CDATA[month]]></string>
+        <string name="_duration_month_pl"><![CDATA[monthes]]></string>
+        <string name="_duration_year"><![CDATA[year]]></string>
+        <string name="_duration_year_pl"><![CDATA[year]]></string>
 	<string name="_error occured"><![CDATA[Error occurred]]></string>
 	<string name="_from"><![CDATA[from]]></string>
 	<string name="_hidden_comment"><![CDATA[Comment by <b>{0}</b> is hidden.]]></string>
@@ -2517,7 +2527,7 @@ If it is not enabled then please consider implement this optimization, since it
     <string name="_sys_connect_option_approve"><![CDATA[Always approve profiles when joined using this module]]></string>
     <string name="_sys_connect_option_privacy"><![CDATA[Default privacy for created profiles]]></string>
 
-    <string name="_sys_currency"><![CDATA[{0} {1}]]></string>
+    <string name="_sys_currency"><![CDATA[{0}{1}]]></string>
     <string name="_sys_decline"><![CDATA[Decline]]></string>
     <string name="_sys_designbox_0"><![CDATA[Content]]></string>
     <string name="_sys_designbox_1"><![CDATA[Content + Title + Background]]></string>

+ 22 - 12
modules/boonex/russian/data/langs/system/ru.xml

@@ -96,14 +96,16 @@
 	<string name="_Please select value"><![CDATA[Пожалуйста, выберите значение из списка]]></string>
         <string name="_polls_from"><![CDATA[Опросы от: {0}]]></string>
 	<string name="_Preview"><![CDATA[Предпросмотр]]></string>
-  <string name="_report_comment"><![CDATA[подал жалобу на '{0}']]></string>
-  <string name="_report_comment_with_note"><![CDATA[подал жалобу на '{0}' с пометкой: {1}]]></string>
-  <string name="_report_comment_check_in"><![CDATA[Взять в работу]]></string>
-  <string name="_report_comment_check_out"><![CDATA[Закончить работу]]></string>
-  <string name="_report_status_new"><![CDATA[Новый]]></string>
-  <string name="_report_status_check_in"><![CDATA[В обработке]]></string>
-  <string name="_report_status_check_out"><![CDATA[Обработан]]></string>
-  <string name="_report_status_all"><![CDATA[Все]]></string>
+        <string name="_price_recurring"><![CDATA[{0}/{1}]]></string>
+	<string name="_price_single"><![CDATA[{0}]]></string>
+        <string name="_report_comment"><![CDATA[подал жалобу на '{0}']]></string>
+        <string name="_report_comment_with_note"><![CDATA[подал жалобу на '{0}' с пометкой: {1}]]></string>
+        <string name="_report_comment_check_in"><![CDATA[Взять в работу]]></string>
+        <string name="_report_comment_check_out"><![CDATA[Закончить работу]]></string>
+        <string name="_report_status_new"><![CDATA[Новый]]></string>
+        <string name="_report_status_check_in"><![CDATA[В обработке]]></string>
+        <string name="_report_status_check_out"><![CDATA[Обработан]]></string>
+        <string name="_report_status_all"><![CDATA[Все]]></string>
 	<string name="_report_counter"><![CDATA[{0}]]></string>
         <string name="_report_n_reports"><![CDATA[{0} жалоб]]></string>
 	<string name="_report_do_report"><![CDATA[Пожаловаться]]></string>
@@ -116,8 +118,8 @@
 	<string name="_report_err_not_enabled"><![CDATA[Жалоба не может быть принята в данный момент. Пожалуйста, попробуйте позднее.]]></string>
 	<string name="_report_err_wrong_type"><![CDATA[Неправильный тип жалобы.]]></string>
 	<string name="_report_reported_as"><![CDATA[Тип жалобы:]]></string>
-  <string name="_report_reported_by"><![CDATA[Жалоба от ]]></string>
-  <string name="_report_comments_count"><![CDATA[Комментарии ({0})]]></string>
+        <string name="_report_reported_by"><![CDATA[Жалоба от ]]></string>
+        <string name="_report_comments_count"><![CDATA[Комментарии ({0})]]></string>
 	<string name="_RSS_Feed_Title_Common"><![CDATA[{0} RSS]]></string>
 	<string name="_RSS_Feed_Title_Profile"><![CDATA[{0} недавние {1}]]></string>
 	<string name="_Rate"><![CDATA[Оценить]]></string>
@@ -125,7 +127,7 @@
 	<string name="_Read more"><![CDATA[Читать ещё]]></string>
 	<string name="_Reset"><![CDATA[Сбросить]]></string>
 	<string name="_Search"><![CDATA[Поиск]]></string>
-  <string name="_search_in_all_section"><![CDATA[Искать во всех отделах]]></string>
+        <string name="_search_in_all_section"><![CDATA[Искать во всех отделах]]></string>
 	<string name="_Section"><![CDATA[Отдел]]></string>
 	<string name="_Select_one"><![CDATA[Выберите один...]]></string>
 	<string name="_Select_all"><![CDATA[Выбрать всё]]></string>
@@ -2074,6 +2076,14 @@
         <string name="_cmt_rvw_txt_do"><![CDATA[Обозревать]]></string>
 	<string name="_copyright"><![CDATA[&copy; {0} Компания]]></string>
 	<string name="_delete"><![CDATA[удалить]]></string>
+        <string name="_duration_day"><![CDATA[дн.]]></string>
+        <string name="_duration_day_pl"><![CDATA[дн.]]></string>
+        <string name="_duration_week"><![CDATA[нед.]]></string>
+        <string name="_duration_week_pl"><![CDATA[нед.]]></string>
+        <string name="_duration_month"><![CDATA[мес]]></string>
+        <string name="_duration_month_pl"><![CDATA[мес.]]></string>
+        <string name="_duration_year"><![CDATA[г.]]></string>
+        <string name="_duration_year_pl"><![CDATA[г.]]></string>
 	<string name="_error occured"><![CDATA[Произошла ошибка]]></string>
 	<string name="_from"><![CDATA[от]]></string>
 	<string name="_hidden_comment"><![CDATA[Комментарий от <b>{0}</b> спрятан.]]></string>
@@ -2492,7 +2502,7 @@
     <string name="_sys_connect_option_approve"><![CDATA[Всегда одобрять профиль, когда заходят через это соединение]]></string>
     <string name="_sys_connect_option_privacy"><![CDATA[Настройки конфиденциальности для созданных профилей]]></string>
 
-    <string name="_sys_currency"><![CDATA[{0} {1}]]></string>
+    <string name="_sys_currency"><![CDATA[{0}{1}]]></string>
     <string name="_sys_decline"><![CDATA[Отклонить]]></string>
     <string name="_sys_designbox_0"><![CDATA[Содержимое]]></string>
     <string name="_sys_designbox_1"><![CDATA[Содержимое + заголовок + фон]]></string>

+ 1 - 1
template/menu_custom_item.html

@@ -1,4 +1,4 @@
 <span class="__class_wrp__ bx-def-margin-thd-topbottom">
-    <a class="__class_link__" href="__link__" <bx_if:onclick>onclick="__onclick__"</bx_if:onclick> title="__title_attr__"__attrs__><bx_include_auto:menu_icon.html /><bx_if:title><span class="bx-def-margin-sec-left-auto">__title__</span></bx_if:title></a>
+    <a class="__class_link__" href="__link__" <bx_if:onclick>onclick="__onclick__"</bx_if:onclick>__attrs__><bx_include_auto:menu_icon.html /><bx_if:title><span class="bx-def-margin-sec-left-auto">__title__</span></bx_if:title></a>
     <bx_if:addon>__addon__</bx_if:addon>
 </span>