Quellcode durchsuchen

Ads: Enhancements. Point ¹2.

AntonLV vor 2 Jahren
Ursprung
Commit
1326cd2d28

+ 23 - 1
modules/base/text/classes/BxBaseModTextTemplate.php

@@ -924,9 +924,10 @@ class BxBaseModTextTemplate extends BxBaseModGeneralTemplate
         $bBadgesCompact = isset($aParams['badges_compact']) ? $aParams['badges_compact'] : false;
 
         $sCoverData = isset($aData['thumb_data']) ? $aData['thumb_data'] : '';
-        
+
         $aTmplVars = array (
             'class' => $this->_getUnitClass($aData,(isset($aParams['template_name']) ? $aParams['template_name'] : '')),
+            'html_id' => $this->_getUnitHtmlId($aData,(isset($aParams['template_name']) ? $aParams['template_name'] : '')),
             'id' => $aData[$CNF['FIELD_ID']],
             'content_url' => $sUrl,
             'bx_if:show_onclick' => [
@@ -958,6 +959,12 @@ class BxBaseModTextTemplate extends BxBaseModGeneralTemplate
                     'title' => $sTitle,
                     'summary_attr' => bx_html_attribute($sSummaryPlain),
                     'content_url' => $sUrl,
+                    'bx_if:show_thumb_onclick' => [
+                        'condition' => false,
+                        'content' => [
+                            'content_onclick' => ''
+                        ]
+                    ],
                     'thumb_url' => $sPhotoThumb ? $sPhotoThumb : '',
                     'gallery_url' => $sPhotoGallery ? $sPhotoGallery : '',
                     'image_settings' => $this->_getImageSettings($sCoverData),
@@ -969,10 +976,18 @@ class BxBaseModTextTemplate extends BxBaseModGeneralTemplate
                 'content' => array (
                     'module_icon' => $CNF['ICON'],
                     'content_url' => $sUrl,
+                    'bx_if:show_no_thumb_onclick' => [
+                        'condition' => false,
+                        'content' => [
+                            'content_onclick' => ''
+                        ]
+                    ],
                     'summary_plain' => $sSummaryPlain,
                     'strecher' => mb_strlen($sSummaryPlain) > 240 ? '' : str_repeat('      ', round((240 - mb_strlen($sSummaryPlain)) / 6)),
                 ),
             ),
+            'unit_content_before' => '',
+            'unit_content_after' => ''
         );
 
         if(isset($aParams['template_vars']) && is_array($aParams['template_vars']))
@@ -1027,6 +1042,13 @@ class BxBaseModTextTemplate extends BxBaseModGeneralTemplate
         return $sResult;
     }
 
+    protected function _getUnitHtmlId($aData, $sTemplateName = 'unit.html')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return str_replace('_', '-', $this->MODULE . '_unit_' . $aData[$CNF['FIELD_ID']]);
+    }
+
     protected function _getHeaderImage($aData)
     {
         return $this->getModule()->getEntryImageData($aData);

+ 3 - 1
modules/base/text/template/unit.html

@@ -1,4 +1,5 @@
-<div class="bx-base-text-unit bx-base-text-unit-ext bx-def-box bx-def-box-round-corners bx-def-color-bg-box mb-3 md:mb-4 lg:mb-6 text-left">
+<div id="__html_id__" class="bx-base-text-unit bx-base-text-unit-ext bx-def-box bx-def-box-round-corners bx-def-color-bg-box mb-3 md:mb-4 lg:mb-6 text-left">
+    <div class="bx-base-text-unit-content-before">__unit_content_before__</div>
     <bx_if:thumb>
         <div class="bx-base-text-unit-cover flex-shrink-0 m-1">
             <img class="bx-base-text-unit-cover bg-cover aspect-video object-cover bx-def-round-corners" alt="__title__" style="background-image:url(__gallery_url__); __image_settings__" src="<bx_icon_url:spacer.gif />" />
@@ -15,4 +16,5 @@
         __summary__
         </div>
     </div>
+    <div class="bx-base-text-unit-content-after">__unit_content_after__</div>
 </div>

+ 5 - 3
modules/base/text/template/unit_gallery.html

@@ -1,7 +1,8 @@
-<div class="__class__ bx-base-text-unit bx-base-text-unit-gallery bx-def-gal-unit-size flex flex-col w-full p-2 box-border">
+<div id="__html_id__" class="__class__ bx-base-text-unit bx-base-text-unit-gallery bx-def-gal-unit-size flex flex-col w-full p-2 box-border">
     <div class="bx-base-text-unit-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box h-full">
+        <div class="bx-base-text-unit-content-before">__unit_content_before__</div>
         <bx_if:thumb>
-            <a href="__content_url__" title="__summary_attr__">
+            <a href="__content_url__" <bx_if:show_thumb_onclick>onclick="javascript:__content_onclick__"</bx_if:show_thumb_onclick> title="__summary_attr__">
                 <div class="shrink-0 m-1">
                     <img class="aspect-video object-cover bg-cover w-full rounded" alt="__title__" style="background-image:url(__gallery_url__); __image_settings__" src="<bx_icon_url:spacer.gif />"  />
                 </div>
@@ -16,12 +17,13 @@
             <div class="bx-base-text-unit-badges pb-1 lg:pb-2">__badges__</div>
             <div class="bx-base-text-unit-title flex-auto max-h-14">
                 <div class="bx-base-tut-title truncate text-left">
-                    <a href="__content_url__" class="text-left">__title__</a>
+                    <a href="__content_url__" <bx_if:show_onclick>onclick="javascript:__content_onclick__"</bx_if:show_onclick> class="text-left">__title__</a>
                 </div>
             </div>
             <div class="bx-base-text-unit-info flex flex-auto flex-col justify-end text-sm text-gray-500 dark:text-gray-400">
                 <bx_if:meta><div class="bx-base-general-unit-meta pt-2">__meta__</div></bx_if:meta>
             </div>
         </div>
+        <div class="bx-base-text-unit-content-after">__unit_content_after__</div>
     </div>
 </div>

+ 4 - 1
modules/boonex/ads/classes/BxAdsConfig.php

@@ -318,7 +318,10 @@ class BxAdsConfig extends BxBaseModTextConfig
                 'txt_cd_ct_product' => '_bx_ads_txt_cd_ct_product',
                 'txt_cd_ct_promotion' => '_bx_ads_txt_cd_ct_promotion',
                 'chart_label_impressions' => '_bx_ads_chart_label_impressions',
-                'chart_label_clicks' => '_bx_ads_chart_label_clicks'
+                'chart_label_clicks' => '_bx_ads_chart_label_clicks',
+                'chart_label_roi_local' => '_bx_ads_chart_label_roi_local',
+                'chart_label_roi_source' => '_bx_ads_chart_label_roi_source',
+                'chart_label_roi_investment' => '_bx_ads_chart_label_roi_investment',
             ),
         ));
         

+ 56 - 2
modules/boonex/ads/classes/BxAdsDb.php

@@ -639,7 +639,7 @@ class BxAdsDb extends BxBaseModTextDb
     	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
 
     	$sSelectClause = "`tl`.*";
-    	$sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+    	$sJoinClause = $sWhereClause = $sGroupClause = $sOrderClause = $sLimitClause = "";
         switch($aParams['type']) {
             case 'id':
             	$aMethod['name'] = 'getRow';
@@ -663,6 +663,18 @@ class BxAdsDb extends BxBaseModTextDb
                     $sLimitClause = "1";
                 }
                 break;
+                
+            case 'entry_id_income':
+                $aMethod['name'] = "getOne";
+                $aMethod['params'][1] = [
+                    'entry_id' => $aParams['entry_id']
+                ];
+
+                $sSelectClause = "SUM(`te`.`" . $CNF['FIELD_PRICE'] . "` * `tl`.`count`)";
+                $sWhereClause = " AND `tl`.`entry_id`=:entry_id";
+                $sJoinClause = " INNER JOIN `" . $CNF['TABLE_ENTRIES'] . "` AS `te` ON `tl`.`entry_id`=`te`.`" . $CNF['FIELD_ID'] . "`";
+                $sGroupClause = "`tl`.`entry_id`";
+                break;
 
             case 'has_by':
                 $aMethod['name'] = "getOne";
@@ -683,13 +695,14 @@ class BxAdsDb extends BxBaseModTextDb
                 break;
         }
 
+        $sGroupClause = !empty($sGroupClause) ? "GROUP BY " . $sGroupClause : $sGroupClause;
         $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : $sOrderClause;
         $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
 
         $aMethod['params'][0] = "SELECT
             " . $sSelectClause . "
             FROM `" . $this->_oConfig->CNF['TABLE_LICENSES'] . "` AS `tl`" . $sJoinClause . "
-            WHERE 1" . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+            WHERE 1" . $sWhereClause . " " . $sGroupClause . " " . $sOrderClause . " " . $sLimitClause;
 
         return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
     }
@@ -755,6 +768,47 @@ class BxAdsDb extends BxBaseModTextDb
         return $this->query($sQuery, $aWhereBindings) !== false;
     }
 
+    public function getPromotionLicense($aParams = [])
+    {
+    	$CNF = &$this->_oConfig->CNF;
+    	$aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+
+    	$sSelectClause = "`tl`.*";
+    	$sJoinClause = $sWhereClause = $sGroupClause = $sOrderClause = $sLimitClause = "";
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause = " AND `tl`.`id`=:id";
+                break;
+
+            case 'entry_id_outcome':
+                $aMethod['name'] = "getOne";
+                $aMethod['params'][1] = [
+                    'entry_id' => $aParams['entry_id']
+                ];
+
+                $sSelectClause = "SUM(`tl`.`amount`)";
+                $sWhereClause = " AND `tl`.`entry_id`=:entry_id";
+                $sGroupClause = "`tl`.`entry_id`";
+                break;
+        }
+
+        $sGroupClause = !empty($sGroupClause) ? "GROUP BY " . $sGroupClause : $sGroupClause;
+        $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : $sOrderClause;
+        $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT
+            " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_PROMO_LICENSES'] . "` AS `tl`" . $sJoinClause . "
+            WHERE 1" . $sWhereClause . " " . $sGroupClause . " " . $sOrderClause . " " . $sLimitClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
     protected function _getEntriesBySearchIds($aParams, &$aMethod, &$sSelectClause, &$sJoinClause, &$sWhereClause, &$sOrderClause, &$sLimitClause)
     {
         $CNF = &$this->_oConfig->CNF;

+ 10 - 1
modules/boonex/ads/classes/BxAdsMenuView.php

@@ -61,8 +61,17 @@ class BxAdsMenuView extends BxBaseModTextMenuView
                 if((float)$this->_aContentInfo[$CNF['FIELD_PRICE']] == 0 || (int)$this->_aContentInfo[$CNF['FIELD_QUANTITY']] <= 0) 
                     break;
 
+                $aCommodity = $this->_oModule->_oDb->getCommodity([
+                    'sample' => 'entry_id', 
+                    'entry_id' => $this->_aContentInfo[$CNF['FIELD_ID']], 
+                    'type' => BX_ADS_COMMODITY_TYPE_PRODUCT, 
+                    'latest' => true
+                ]);
+                if(empty($aCommodity) || !is_array($aCommodity))
+                    break;
+
                 $iAuthorId = (int)$this->_aContentInfo[$CNF['FIELD_AUTHOR']];
-                $aJs = $oPayment->getAddToCartJs($iAuthorId, $this->MODULE, $this->_aContentInfo[$CNF['FIELD_ID']], 1, true);
+                $aJs = $oPayment->getAddToCartJs($iAuthorId, $this->MODULE, $aCommodity['id'], 1, true);
                 if(empty($aJs) || !is_array($aJs))
                     break;
 

+ 5 - 11
modules/boonex/ads/classes/BxAdsModule.php

@@ -63,17 +63,6 @@ class BxAdsModule extends BxBaseModTextModule
         return $aResult;
     }
 
-    public function actionShopifyCall()
-    {
-        $iProfileId = bx_get_logged_profile_id();
-
-        bx_import('SourceShopifyAdmin', $this->_aModule);
-        $oShopify = new BxAdsSourceShopifyAdmin($iProfileId, $this);
-        
-        $aResponse = $oShopify->getProduct('7433957113996');
-        print_r($aResponse); exit;
-    }
-
     public function actionLoadEntryFromSource()
     {
         $sSourceType = bx_process_url_param(bx_process_input(bx_get('source_type')));
@@ -593,6 +582,11 @@ class BxAdsModule extends BxBaseModTextModule
     {
         return $this->_serviceTemplateFunc('entryPromotionSummary', $iContentId);
     }
+    
+    public function serviceEntityPromotionRoi($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc('entryPromotionRoi', $iContentId);
+    }
 
     /**
      * @page service Service Calls

+ 1 - 1
modules/boonex/ads/classes/BxAdsSearchResult.php

@@ -28,7 +28,7 @@ class BxAdsSearchResult extends BxBaseModTextSearchResult
             'object_metatags' => $CNF['OBJECT_METATAGS'],
             'title' => _t('_bx_ads_page_title_browse'),
             'table' => $CNF['TABLE_ENTRIES'],
-            'ownFields' => array('id', 'title', 'text', 'thumb', 'author', 'added', 'price', 'quantity', 'notes_purchased'),
+            'ownFields' => array('id', 'url', 'title', 'text', 'thumb', 'author', 'added', 'price', 'quantity', 'notes_purchased'),
             'searchFields' => array(),
             'restriction' => array(
                 'author' => array('value' => '', 'field' => 'author', 'operator' => '='),

+ 5 - 0
modules/boonex/ads/classes/BxAdsSource.php

@@ -67,6 +67,11 @@ class BxAdsSource extends BxDol
         return [];
     }
 
+    public function getOrders($aParams)
+    {
+        return [];
+    }
+
     /**
      * Internal methods.
      */

+ 62 - 0
modules/boonex/ads/classes/BxAdsSourceShopifyAdmin.php

@@ -28,6 +28,9 @@ require_once('BxAdsSource.php');
  * 3. REST Admin API -> Product
  * https://shopify.dev/docs/api/admin-rest/2023-10/resources/product
  * 
+ * 4. REST Admin API -> Order
+ * https://shopify.dev/docs/api/admin-rest/2023-10/resources/order
+ * 
  */
 class BxAdsSourceShopifyAdmin extends BxAdsSource
 {
@@ -88,6 +91,60 @@ class BxAdsSourceShopifyAdmin extends BxAdsSource
         return $aResult;
     }
 
+    public function getOrders($aParams)
+    {
+        $sSample = $aParams['sample'];
+        $aRequest = [
+            'fields' => 'id,name,created_at,processed_at,current_total_price,current_total_tax,line_items',
+            'financial_status' => isset($aParams['status']) ? $aParams['status'] : 'paid'
+        ];
+
+        switch($sSample) {
+            case 'ids':
+                $aRequest = array_merge($aRequest, [
+                    'ids' => implode(',', $aParams['ids']),
+                ]);
+                break;
+
+            case 'sales_by_product_id':
+                $aRequest = array_merge($aRequest, [
+                    'processed_at_min' => $this->_dateI2S($aParams['date_from']),
+                ]);
+                break;
+        }
+
+        $sOrders = $this->_call('orders.json', $aRequest, 'get');
+        if(empty($sOrders))
+            return [];
+        
+        $aOrders = json_decode($sOrders, true);
+        if(empty($aOrders) || !is_array($aOrders) || empty($aOrders['orders']))
+            return [];
+
+        $aOrders = $aOrders['orders'];
+
+        $aResults = [];
+        foreach($aOrders as $aOrder) 
+            foreach($aOrder['line_items'] as $aLineItem) {
+                if($sSample == 'sales_by_product_id' && $aLineItem['product_id'] != $aParams['product_id'])
+                    continue;
+
+                $aResults[] = [
+                    'id' => $aOrder['id'],
+                    'created' => $aOrder['created_at'],
+                    'processed' => $aOrder['processed_at'],
+                    'name' => $aOrder['name'],
+                    'product_id' => $aLineItem['product_id'],
+                    'product_price' => (float)$aLineItem['price'],
+                    'product_discounted' => (float)$aLineItem['pre_tax_price'],
+                    'quantity' => (int)$aLineItem['quantity'],
+                    'amount' => (int)$aLineItem['quantity'] * (float)$aLineItem['pre_tax_price']
+                ];
+            }
+
+        return $aResults;
+    }
+
     /**
      * Internal methods.
      */
@@ -101,4 +158,9 @@ class BxAdsSourceShopifyAdmin extends BxAdsSource
 
         return bx_file_get_contents($this->_sEndpoint . $sRequest, $aParams, $sMethod, $aHeaders);
     }
+    
+    protected function _dateI2S($iTimestamp)
+    {
+        return date("Y-m-d", $iTimestamp);
+    }
 }

+ 92 - 10
modules/boonex/ads/classes/BxAdsTemplate.php

@@ -116,9 +116,76 @@ class BxAdsTemplate extends BxBaseModTextTemplate
             $aTmplVarsDataSet['backgroundColor'][] = '#' . dechex(rand(0x000000, 0xFFFFFF));
         }
 
+        if($this->_bIsApi)
+            return [
+                'labels' => $aTmplVarsDataLabels,
+                'dataset' => $aTmplVarsDataSet
+            ];
+
         $this->addJs(['chart.min.js']);
         $this->addCss(['chart.css']);
         return $this->parseHtmlByName('chart_stats.html', [
+            'chart_id' => $this->MODULE . '_chart_summary',
+            'chart_data' => json_encode([
+                'labels' => $aTmplVarsDataLabels,
+                'datasets' => [$aTmplVarsDataSet]
+            ])
+        ]);
+    }
+
+    public function entryPromotionRoi($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aTmplVarsDataLabels = $aTmplVarsDataSet = [];
+        
+        //--- Get income local.
+        $sTitleLocal = bx_html_attribute(_t($CNF['T']['chart_label_roi_local']));
+        $iValueLocal = (int)$this->_oDb->getLicense(['type' => 'entry_id_income', 'entry_id' => $aContentInfo[$CNF['FIELD_ID']]]);
+
+        $aTmplVarsDataLabels[] = $sTitleLocal . ' - ' . $iValueLocal;
+        $aTmplVarsDataSet['data'][] = $iValueLocal;
+        $aTmplVarsDataSet['backgroundColor'][] = '#' . dechex(rand(0x000000, 0xFFFFFF));
+
+        //--- Get income external (from source)
+        if($this->_oConfig->isSources()) {
+            $oSource = $this->_oModule->getObjectSource($aContentInfo[$CNF['FIELD_SOURCE_TYPE']], $aContentInfo[$CNF['FIELD_AUTHOR']]);
+            if($oSource !== false && !empty($aContentInfo[$CNF['FIELD_SOURCE']])) {
+                $aOrders = $oSource->getOrders([
+                    'sample' => 'sales_by_product_id', 
+                    'product_id' => $aContentInfo[$CNF['FIELD_SOURCE']], 
+                    'date_from' => $aContentInfo[$CNF['FIELD_ADDED']]
+                ]);
+
+                $sTitleSource = bx_html_attribute(_t($CNF['T']['chart_label_roi_source']));
+                $iValueSource = 0;
+                foreach($aOrders as $aOrder)
+                    $iValueSource += $aOrder['amount'];
+
+                $aTmplVarsDataLabels[] = $sTitleSource . ' - ' . $iValueSource;
+                $aTmplVarsDataSet['data'][] = $iValueSource;
+                $aTmplVarsDataSet['backgroundColor'][] = '#' . dechex(rand(0x000000, 0xFFFFFF));
+            }
+        }
+
+        //--- Get investments
+        $sTitleInvestment = bx_html_attribute(_t($CNF['T']['chart_label_roi_investment']));
+        $iValueInvestment = (int)$this->_oDb->getPromotionLicense(['type' => 'entry_id_outcome', 'entry_id' => $aContentInfo[$CNF['FIELD_ID']]]);
+
+        $aTmplVarsDataLabels[] = $sTitleInvestment . ' - ' . $iValueInvestment;
+        $aTmplVarsDataSet['data'][] = $iValueInvestment;
+        $aTmplVarsDataSet['backgroundColor'][] = '#' . dechex(rand(0x000000, 0xFFFFFF));
+
+        if($this->_bIsApi)
+            return [
+                'labels' => $aTmplVarsDataLabels,
+                'dataset' => $aTmplVarsDataSet
+            ];
+
+        $this->addJs(['chart.min.js']);
+        $this->addCss(['chart.css']);
+        return $this->parseHtmlByName('chart_stats.html', [
+            'chart_id' => $this->MODULE . '_chart_roi',
             'chart_data' => json_encode([
                 'labels' => $aTmplVarsDataLabels,
                 'datasets' => [$aTmplVarsDataSet]
@@ -206,31 +273,46 @@ class BxAdsTemplate extends BxBaseModTextTemplate
 
         $aResult = parent::getUnit($aData, $aParams);
         
-        if($this->_oConfig->isSources() && !empty($aData[$CNF['FIELD_URL']])) 
+        if($this->_oConfig->isSources() && !empty($aData[$CNF['FIELD_URL']])) {
             $aResult = array_merge($aResult, [
                 'content_url' => $aData[$CNF['FIELD_URL']],
             ]);
 
+            if($aResult['bx_if:thumb']['condition'])
+                $aResult['bx_if:thumb']['content'] = array_merge($aResult['bx_if:thumb']['content'], [
+                    'content_url' => $aData[$CNF['FIELD_URL']],
+                ]);
+        }
+
         if($this->_oConfig->isPromotion()) {
             $sJsObject = $this->_oConfig->getJsObject('main');
 
+            $sContentUrl = 'javascript:void(0)';
+            $sContentOnclick = 'return ' . $sJsObject . '.registerClick(this, ' . $aData[$CNF['FIELD_ID']] . ')';
+
             $aResult = array_merge($aResult, [
-                'content_url' => 'javascript:void(0)',
+                'content_url' => $sContentUrl,
                 'bx_if:show_onclick' => [
                     'condition' => true,
                     'content' => [
-                        'content_onclick' => 'return ' . $sJsObject . '.registerClick(this, ' . $aData[$CNF['FIELD_ID']] . ')'
-                    ]
-                ],
-                'bx_if:show_tracker' => [
-                    'condition' => true,
-                    'content' => [
-                        'js_object' => $sJsObject,
-                        'id' => $aData[$CNF['FIELD_ID']]
+                        'content_onclick' => $sContentOnclick
                     ]
                 ],
+                'unit_content_after' => $this->_wrapInTagJsCode($sJsObject . '.registerTraker(' . $aData[$CNF['FIELD_ID']] . ');'),
             ]);
+
+            if($aResult['bx_if:thumb']['condition'])
+                $aResult['bx_if:thumb']['content'] = array_merge($aResult['bx_if:thumb']['content'], [
+                    'content_url' => $sContentUrl,
+                    'bx_if:show_thumb_onclick' => [
+                        'condition' => true,
+                        'content' => [
+                            'content_onclick' => $sContentOnclick
+                        ]
+                    ],
+                ]);
         }
+
         return $aResult;
     }
 

+ 5 - 0
modules/boonex/ads/install/langs/en.xml

@@ -220,6 +220,8 @@
     <string name="_bx_ads_page_block_title_entry_promotion_growth"><![CDATA[Promotion for <a href="{entry_link}">{title}</a>]]></string>
     <string name="_bx_ads_page_block_title_sys_entry_promotion_summary"><![CDATA[Promotion (Summary)]]></string>
     <string name="_bx_ads_page_block_title_entry_promotion_summary"><![CDATA[Summary]]></string>
+    <string name="_bx_ads_page_block_title_sys_entry_promotion_roi"><![CDATA[ROI]]></string>
+    <string name="_bx_ads_page_block_title_entry_promotion_roi"><![CDATA[ROI]]></string>
     <string name="_bx_ads_page_block_title_entry_reviews"><![CDATA[Reviews]]></string>
     <string name="_bx_ads_page_block_title_entry_reviews_link"><![CDATA[Reviews to <a href="{entry_link}">{title}</a>]]></string>
     <string name="_bx_ads_page_block_title_entry_reviews_rating"><![CDATA[Rating]]></string>
@@ -462,6 +464,9 @@
     <string name="_bx_ads_chart_promotion_growth_speed"><![CDATA[Ad Promotion: Growth Speed]]></string>
     <string name="_bx_ads_chart_label_impressions"><![CDATA[Impressions]]></string>
     <string name="_bx_ads_chart_label_clicks"><![CDATA[Clicks]]></string>
+    <string name="_bx_ads_chart_label_roi_local"><![CDATA[Local income]]></string>
+    <string name="_bx_ads_chart_label_roi_source"><![CDATA[External income]]></string>
+    <string name="_bx_ads_chart_label_roi_investment"><![CDATA[Investments]]></string>
 
     <string name="_bx_ads_search_extended"><![CDATA[Ads Search]]></string>
     <string name="_bx_ads_search_extended_cmts"><![CDATA[Ads Comments Search]]></string>

+ 4 - 3
modules/boonex/ads/install/sql/enable.sql

@@ -95,11 +95,12 @@ INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `t
 
 -- PAGE: view entry promotion
 INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
-('bx_ads_view_entry_promotion', '_bx_ads_page_title_sys_view_entry_promotion', '_bx_ads_page_title_view_entry_promotion', 'bx_ads', 2, 2147483647, 1, 'view-ad-promotion', '', '', '', '', 0, 1, 0, 'BxAdsPageEntry', 'modules/boonex/ads/classes/BxAdsPageEntry.php');
+('bx_ads_view_entry_promotion', '_bx_ads_page_title_sys_view_entry_promotion', '_bx_ads_page_title_view_entry_promotion', 'bx_ads', 12, 2147483647, 1, 'view-ad-promotion', '', '', '', '', 0, 1, 0, 'BxAdsPageEntry', 'modules/boonex/ads/classes/BxAdsPageEntry.php');
 
 INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
-('bx_ads_view_entry_promotion', 1, 'bx_ads', '_bx_ads_page_block_title_sys_entry_promotion_growth', '_bx_ads_page_block_title_entry_promotion_growth', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:23:"entity_promotion_growth";}', 0, 0, 1),
-('bx_ads_view_entry_promotion', 2, 'bx_ads', '_bx_ads_page_block_title_sys_entry_promotion_summary', '_bx_ads_page_block_title_entry_promotion_summary', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:24:"entity_promotion_summary";}', 0, 0, 1);
+('bx_ads_view_entry_promotion', 2, 'bx_ads', '_bx_ads_page_block_title_sys_entry_promotion_growth', '_bx_ads_page_block_title_entry_promotion_growth', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:23:"entity_promotion_growth";}', 0, 0, 1),
+('bx_ads_view_entry_promotion', 3, 'bx_ads', '_bx_ads_page_block_title_sys_entry_promotion_summary', '_bx_ads_page_block_title_entry_promotion_summary', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:24:"entity_promotion_summary";}', 0, 0, 1),
+('bx_ads_view_entry_promotion', 3, 'bx_ads', '_bx_ads_page_block_title_sys_entry_promotion_roi', '_bx_ads_page_block_title_entry_promotion_roi', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:20:"entity_promotion_roi";}', 0, 0, 2);
 
 -- PAGE: popular entries
 INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 

+ 5 - 0
modules/boonex/russian/data/langs/bx_ads/ru.xml

@@ -219,6 +219,8 @@
     <string name="_bx_ads_page_block_title_entry_promotion_growth"><![CDATA[Реклама <a href="{entry_link}">{title}</a> объявления]]></string>
     <string name="_bx_ads_page_block_title_sys_entry_promotion_summary"><![CDATA[Реклама (Сводка)]]></string>
     <string name="_bx_ads_page_block_title_entry_promotion_summary"><![CDATA[Сводка]]></string>
+    <string name="_bx_ads_page_block_title_sys_entry_promotion_roi"><![CDATA[Рентабельность инвестиций]]></string>
+    <string name="_bx_ads_page_block_title_entry_promotion_roi"><![CDATA[Рентабельность инвестиций]]></string>
     <string name="_bx_ads_page_block_title_entry_reviews"><![CDATA[Обзоры]]></string>
     <string name="_bx_ads_page_block_title_entry_reviews_link"><![CDATA[Обзоры к <a href="{entry_link}">{title}</a>]]></string>
     <string name="_bx_ads_page_block_title_entry_reviews_rating"><![CDATA[Рейтинг]]></string>
@@ -458,6 +460,9 @@
     <string name="_bx_ads_chart_promotion_growth_speed"><![CDATA[Реклама объявления: Скорость развития]]></string>
     <string name="_bx_ads_chart_label_impressions"><![CDATA[Показы]]></string>
     <string name="_bx_ads_chart_label_clicks"><![CDATA[Клики]]></string>
+    <string name="_bx_ads_chart_label_roi_local"><![CDATA[Локальный доход]]></string>
+    <string name="_bx_ads_chart_label_roi_source"><![CDATA[Внешний доход]]></string>
+    <string name="_bx_ads_chart_label_roi_investment"><![CDATA[Вложения]]></string>
 
     <string name="_bx_ads_search_extended"><![CDATA[Поиск объявлений]]></string>
     <string name="_bx_ads_search_extended_cmts"><![CDATA[Поиск комментариев к объявлениям]]></string>

+ 20 - 20
template/chart_stats.html

@@ -1,24 +1,24 @@
 <div class="bx-chart-stats bx-def-font-align-center">
     <div class="bx-chart-stats-graph">
-        <canvas class="bx-canvas" id="bx_chart_stats_graph" width="100%"></canvas>
-	    <script language="javascript">
-	    	var oStatsChart = new Chart($("#bx_chart_stats_graph"), {
-	    		type: 'doughnut',
-	    		data: __chart_data__,
-	    		options: {
-	    		    legend: {
-	    		        position: 'bottom'
-	    		    },
-	    		    padding: {
-	    		        left: 0,
-	    		        right: 0,
-	    		        top: 0,
-	    		        bottom: 0
-	    		    },
-	    		    maintainAspectRatio: false
-	    		},
-	    	});
-	    	$("#bx_chart_stats_graph").height(450);
-	    </script>
+        <canvas class="bx-canvas" id="__chart_id__" width="100%"></canvas>
+        <script language="javascript">
+            var oStatsChart = new Chart($("#__chart_id__"), {
+                    type: 'doughnut',
+                    data: __chart_data__,
+                    options: {
+                        legend: {
+                            position: 'bottom'
+                        },
+                        padding: {
+                            left: 0,
+                            right: 0,
+                            top: 0,
+                            bottom: 0
+                        },
+                        maintainAspectRatio: false
+                    },
+            });
+            $("#__chart_id__").height(450);
+        </script>
     </div>
 </div>

+ 1 - 0
template/scripts/BxBaseChartServices.php

@@ -165,6 +165,7 @@ class BxBaseChartServices extends BxDol
         $oTemplate->addCss(array('chart.css'));
 
         return $oTemplate->parseHtmlByName('chart_stats.html', array(
+            'chart_id' => 'bx_chart_stats_graph',
             'chart_data' => json_encode(array(
                 'labels' => $aTmplVarsDataLabels,
                 'datasets' => array($aTmplVarsDataSet)