ht_pagantis   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 296
Duplicated Lines 0 %

Importance

Changes 13
Bugs 0 Features 0
Metric Value
eloc 180
c 13
b 0
f 0
dl 0
loc 296
rs 9.76
wmc 33

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getExtraConfig() 0 13 3
B ht_pagantis() 0 20 7
A getConfig() 0 6 1
A isEnabled() 0 2 1
A isPromoted() 0 13 3
C execute() 0 162 13
A getProductPrice() 0 6 1
A remove() 0 2 1
A check() 0 2 1
A install() 0 2 1
A keys() 0 2 1
1
<?php
2
/*
3
  $Id$
4
5
  osCommerce, Open Source E-Commerce Solutions
6
  http://www.oscommerce.com
7
8
  Copyright (c) 2010 osCommerce
9
10
  Released under the GNU General Public License
11
*/
12
13
define('TABLE_PAGANTIS_CONFIG', 'pagantis_config');
14
define('MODULE_HEADER_TAGS_PAGANTIS_SDK', 'https://cdn.pagantis.com/js/pg-v2/sdk.js');
15
16
class ht_pagantis {
17
    var $code = 'ht_pagantis';
18
    var $group = 'header_tags';
19
    var $title;
20
    var $description;
21
    var $enabled = false;
22
    var $langCode = null;
23
24
    /**
25
     * ht_pagantis constructor.
26
     */
27
    function ht_pagantis() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
28
        $this->title = MODULE_HEADER_TAGS_PAGANTIS_TITLE;
29
        $this->description = MODULE_HEADER_TAGS_PAGANTIS_DESCRIPTION;
30
        $this->sort_order = 0;
0 ignored issues
show
Bug Best Practice introduced by
The property sort_order does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
31
32
        if (defined('MODULE_HEADER_TAGS_PAGANTIS_STATUS')
33
            && defined('MODULE_PAYMENT_PAGANTIS_STATUS')
34
            && defined('MODULE_PAYMENT_PAGANTIS_SIMULATOR')
35
        ) {
36
            $this->enabled = ((MODULE_HEADER_TAGS_PAGANTIS_STATUS == 'True') &&
0 ignored issues
show
introduced by
The condition MODULE_HEADER_TAGS_PAGANTIS_STATUS == 'True' is always false.
Loading history...
37
                (MODULE_PAYMENT_PAGANTIS_STATUS == 'True') &&
0 ignored issues
show
Bug introduced by
The constant MODULE_PAYMENT_PAGANTIS_STATUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
38
                (MODULE_PAYMENT_PAGANTIS_SIMULATOR == 'True')) ;
0 ignored issues
show
Bug introduced by
The constant MODULE_PAYMENT_PAGANTIS_SIMULATOR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
39
        }
40
41
        $this->extraConfig = $this->getExtraConfig();
0 ignored issues
show
Bug Best Practice introduced by
The property extraConfig does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
42
        $this->pk = $this->getConfig('MODULE_PAYMENT_PAGANTIS_PK');
0 ignored issues
show
Bug Best Practice introduced by
The property pk does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
43
        $this->sdkFile = MODULE_HEADER_TAGS_PAGANTIS_SDK;
0 ignored issues
show
Bug Best Practice introduced by
The property sdkFile does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
44
45
        if (defined('MODULE_HEADER_TAGS_PAGANTIS_LANG_CODE')) {
46
            $this->langCode = MODULE_HEADER_TAGS_PAGANTIS_LANG_CODE;
47
        }
48
    }
49
50
    /**
51
     * @return array
52
     */
53
    private function getExtraConfig()
54
    {
55
        $checkTable = tep_db_query("SHOW TABLES LIKE '".TABLE_PAGANTIS_CONFIG."'");
0 ignored issues
show
Bug introduced by
The function tep_db_query was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
        $checkTable = /** @scrutinizer ignore-call */ tep_db_query("SHOW TABLES LIKE '".TABLE_PAGANTIS_CONFIG."'");
Loading history...
56
        $response = array();
57
        if (tep_db_num_rows($checkTable) > 0) {
0 ignored issues
show
Bug introduced by
The function tep_db_num_rows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

57
        if (/** @scrutinizer ignore-call */ tep_db_num_rows($checkTable) > 0) {
Loading history...
58
            $query       = "select * from ".TABLE_PAGANTIS_CONFIG;
59
            $result      = tep_db_query($query);
60
            $response    = array();
61
            while ($resultArray = tep_db_fetch_array($result)) {
0 ignored issues
show
Bug introduced by
The function tep_db_fetch_array was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

61
            while ($resultArray = /** @scrutinizer ignore-call */ tep_db_fetch_array($result)) {
Loading history...
62
                $response[$resultArray['config']] = $resultArray['value'];
63
            }
64
        }
65
        return $response;
66
    }
67
68
    /**
69
     * @param string $config
70
     * @return array
71
     */
72
    private function getConfig($config = '')
73
    {
74
        $query       = "select * from ".TABLE_CONFIGURATION . " where configuration_key ='" . $config . "'";
0 ignored issues
show
Bug introduced by
The constant TABLE_CONFIGURATION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
75
        $result      = tep_db_query($query);
0 ignored issues
show
Bug introduced by
The function tep_db_query was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
        $result      = /** @scrutinizer ignore-call */ tep_db_query($query);
Loading history...
76
        $resultArray = tep_db_fetch_array($result);
0 ignored issues
show
Bug introduced by
The function tep_db_fetch_array was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

76
        $resultArray = /** @scrutinizer ignore-call */ tep_db_fetch_array($result);
Loading history...
77
        return $resultArray['configuration_value'];
78
    }
79
80
    /**
81
     * @return int
82
     */
83
    private function getProductPrice()
84
    {
85
        $query       = "select products_price from products where products_id ='" . urlencode($_GET['products_id']) . "'";
86
        $result      = tep_db_query($query);
0 ignored issues
show
Bug introduced by
The function tep_db_query was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

86
        $result      = /** @scrutinizer ignore-call */ tep_db_query($query);
Loading history...
87
        $resultArray = tep_db_fetch_array($result);
0 ignored issues
show
Bug introduced by
The function tep_db_fetch_array was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

87
        $resultArray = /** @scrutinizer ignore-call */ tep_db_fetch_array($result);
Loading history...
88
        return (int)$resultArray['products_price'];
89
    }
90
91
    /**
92
     * Execute function
93
     */
94
    function execute()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
95
    {
96
        global $order, $oscTemplate;
97
98
        ob_start();
99
        $productId = $GLOBALS["HTTP_GET_VARS"]["products_id"];
100
        $checkoutPage = strpos($_SERVER[REQUEST_URI], "checkout_payment.php") > 0;
0 ignored issues
show
Bug introduced by
The constant REQUEST_URI was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
101
102
        if (isset($productId) && $checkoutPage!='1') {
103
            $productPrice = $this->getProductPrice();
104
            $pagantisDisplayMinAmount = $this->extraConfig['PAGANTIS_DISPLAY_MIN_AMOUNT'];
105
            $pagantisDisplayMaxAmount = $this->extraConfig['PAGANTIS_SIMULATOR_DISPLAY_MAX_AMOUNT'];
106
            if (($productPrice > (int)$pagantisDisplayMaxAmount  && (int)$pagantisDisplayMaxAmount != '0') ||
107
                $productPrice < (int)$pagantisDisplayMinAmount) {
108
                return false;
109
            }
110
        }
111
        //Show promoted html
112
        if ($this->isPromoted($productId) && $checkoutPage!='1') {
113
            echo "<style> #promotedText{margin-left: 10%;} .pmt-no-interest{color: #00c1d5 }</style>";
114
            echo "<div id='promotedText' style='display:none'><br/>".$this->extraConfig['PAGANTIS_PROMOTED_PRODUCT_CODE']."</div>";
115
            echo '<script>'. PHP_EOL;
116
            echo '        function loadPromoted()'. PHP_EOL;
117
            echo '        {'. PHP_EOL;
118
            echo 'var positionSelector = \'' . $this->extraConfig['PAGANTIS_SIMULATOR_CSS_POSITION_SELECTOR']. '\';'. PHP_EOL;
119
            echo 'if (positionSelector === \'default\') {'. PHP_EOL;
120
            echo 'positionSelector = \'.buttonSet\''. PHP_EOL;
121
            echo '}'. PHP_EOL;
122
            echo 'var docFather = document.querySelector(positionSelector);'.PHP_EOL;
123
            echo 'if (typeof docFather != \'undefined\') {'. PHP_EOL;
124
            echo 'var promotedNode = document.getElementById("promotedText");'.PHP_EOL;
125
            echo 'docFather.appendChild(promotedNode);'.PHP_EOL;
126
            echo 'promotedNode.style.display=""' . PHP_EOL;
127
            echo '               clearInterval(window.OSPromotedId);'. PHP_EOL;
128
            echo '               return true;'. PHP_EOL;
129
            echo '       }'. PHP_EOL;
130
            echo '               return false;'. PHP_EOL;
131
            echo '       }'. PHP_EOL;
132
            echo '       window.OSPromotedId = setInterval(function () {'. PHP_EOL;
133
            echo '          loadPromoted();'. PHP_EOL;
134
            echo '       }, 2000);'. PHP_EOL;
135
            echo '</script>'. PHP_EOL;
136
        }
137
138
        if (isset($productId) || $checkoutPage) {
139
            $simulatorCode = 'pgSDK';
140
141
            //Promoted amount on checkout page
142
            $promotedAmount = 0;
143
            foreach ((array)$order->products as $item) {
144
                $productId = explode('{', $item['id'], 1);
145
                $productId = array_shift($productId);
146
                $promotedProduct = $this->isPromoted($productId);
147
                if ($promotedProduct) {
148
                    $promotedAmount+=number_format(($item['price'] * $item['qty']), 2);
149
                }
150
            }
151
152
            echo "<script src='".$this->sdkFile."'></script>". PHP_EOL;
153
            echo '<style>#bodyContent>form>div>iframe {float: right; width: 280px !important; margin-right: -90px;} .contentContainer {clear: both;}</style>'. PHP_EOL;
154
            echo '<script>'. PHP_EOL;
155
            echo '        function loadSimulator()'. PHP_EOL;
156
            echo '        {'. PHP_EOL;
157
            echo '           if (typeof '.$simulatorCode.' != \'undefined\') {'. PHP_EOL;
158
            echo '               var sdk = '.$simulatorCode.';'. PHP_EOL;
159
            echo '               var positionSelector = \'' . $this->extraConfig['PAGANTIS_SIMULATOR_CSS_POSITION_SELECTOR']. '\';'. PHP_EOL;
160
            echo '               var priceSelector = \'' . $this->extraConfig['PAGANTIS_SIMULATOR_CSS_PRICE_SELECTOR']. '\';'. PHP_EOL;
161
            echo '               var checkoutPriceSelector = \'' . $this->extraConfig['PAGANTIS_SIMULATOR_CSS_PRICE_SELECTOR']. '\';'. PHP_EOL;
162
            echo '               var quantitySelector = \'' . $this->extraConfig['PAGANTIS_SIMULATOR_CSS_QUANTITY_SELECTOR']. '\';'. PHP_EOL;
163
            echo '               var checkoutPage =     \'' . $checkoutPage.'\';'. PHP_EOL;
164
            echo '               var promotedAmount =     \'' . $promotedAmount.'\';'. PHP_EOL;
165
            echo '               var langCode =     \'' . $this->langCode.'\';'. PHP_EOL;
166
167
            echo '               if (positionSelector === \'default\') {'. PHP_EOL;
168
            echo '                   positionSelector = \'#bodyContent>form>div\''. PHP_EOL;
169
            echo '               }'. PHP_EOL;
170
171
            echo '               if (priceSelector === \'default\') {'. PHP_EOL;
172
            echo '                   priceSelector = \'#bodyContent>form>div>h1:first-child\''. PHP_EOL;
173
            echo '               }'. PHP_EOL;
174
175
            echo '               if (checkoutPriceSelector == \'default\' && checkoutPage == \'1\')  {'. PHP_EOL;
176
            echo '                   priceSelector = \'#columnRight > .infoBoxContainer > .infoBoxContents > tbody > tr:last-child > td\';'. PHP_EOL;
177
            echo '               }'. PHP_EOL;
178
179
            echo '               product_simulator = {};'. PHP_EOL;
180
            echo '               product_simulator.locale = \'' . strtolower($this->langCode) . '\';'. PHP_EOL;
181
            echo '               product_simulator.country = \'' . strtolower($this->langCode) . '\';'. PHP_EOL;
182
            echo '               product_simulator.publicKey = \'' . $this->pk . '\';'. PHP_EOL;
0 ignored issues
show
Bug introduced by
Are you sure $this->pk of type array can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
            echo '               product_simulator.publicKey = \'' . /** @scrutinizer ignore-type */ $this->pk . '\';'. PHP_EOL;
Loading history...
183
            echo '               product_simulator.selector = positionSelector;'. PHP_EOL;
184
            echo '               product_simulator.numInstalments = \'' . $this->extraConfig['PAGANTIS_SIMULATOR_START_INSTALLMENTS'] . '\';'. PHP_EOL;
185
            echo '               product_simulator.type = ' . $this->extraConfig['PAGANTIS_SIMULATOR_DISPLAY_TYPE'] . ';'. PHP_EOL;
186
            echo '               product_simulator.skin = ' . $this->extraConfig['PAGANTIS_SIMULATOR_DISPLAY_SKIN'] . ';'. PHP_EOL;
187
            echo '               product_simulator.position = ' . $this->extraConfig['PAGANTIS_SIMULATOR_DISPLAY_CSS_POSITION'] . ';'. PHP_EOL;
188
            echo '               product_simulator.amountParserConfig = {};'. PHP_EOL;
189
            echo '               product_simulator.amountParserConfig.thousandSeparator = "' . $this->extraConfig['PAGANTIS_SIMULATOR_THOUSANDS_SEPARATOR'] . '";'. PHP_EOL;
190
            echo '               product_simulator.amountParserConfig.decimalSeparator = "' . $this->extraConfig['PAGANTIS_SIMULATOR_DECIMAL_SEPARATOR'] .  '";'. PHP_EOL;
191
192
            //Amount in product page
193
            echo '               var promotedProduct = \'' . $this->isPromoted($productId) .'\';'. PHP_EOL;
194
            echo '               if(checkoutPage != \'1\' ) {'. PHP_EOL;
195
            echo '               product_simulator.itemAmountSelector = priceSelector;'. PHP_EOL;
196
            echo '                   if(promotedProduct == \'1\') { ' . PHP_EOL;
197
            echo '                    product_simulator.itemPromotedAmountSelector = priceSelector;'. PHP_EOL;
198
            echo '                   }' . PHP_EOL;
199
            echo '               }';
200
201
            //Amount in checkout page
202
            echo '               if(checkoutPage == \'1\' ) { ' . PHP_EOL;
203
            echo '                  product_simulator.totalAmountSelector = priceSelector;'. PHP_EOL;
204
            echo '                  if(promotedAmount != \'0\' && checkoutPage == \'1\' ) { ' . PHP_EOL;
205
            echo '                      product_simulator.totalPromotedAmount = promotedAmount;'. PHP_EOL;
206
            echo '                  }' . PHP_EOL;
207
            echo '                  product_simulator.selector = \'.buttonSet\';' . PHP_EOL;
208
            echo '                  product_simulator.type = ' .$this->extraConfig['PAGANTIS_SIMULATOR_DISPLAY_TYPE_CHECKOUT'] . PHP_EOL;
209
            echo '               }' . PHP_EOL;
210
            echo '               sdk.simulator.init(product_simulator);'. PHP_EOL;
211
            echo '               clearInterval(window.OSSimulatorId);'. PHP_EOL;
212
            echo '               return true;'. PHP_EOL;
213
            echo '           }'. PHP_EOL;
214
            echo '           return false;'. PHP_EOL;
215
            echo '       }'. PHP_EOL;
216
217
            //Invoke to main method
218
            echo '       window.OSSimulatorId = setInterval(function () {'. PHP_EOL;
219
            echo '          loadSimulator();'. PHP_EOL;
220
            echo '       }, 2500);'. PHP_EOL;
221
            echo '</script>'. PHP_EOL;
222
223
            //Checkout simulator
224
            if ($checkoutPage) {
225
                echo '<script>' . PHP_EOL;
226
227
                echo 'function checkSelected(value)'. PHP_EOL;
228
                echo '{ '. PHP_EOL;
229
                echo 'var simulator = document.getElementsByClassName("buttonSet");'  . PHP_EOL;
230
                echo ' if(simulator == "undefined") { return false;  } '. PHP_EOL;
231
                echo 'var pagantisCheckbox = document.querySelector("input[value=\'pagantis\']"); ' . PHP_EOL;
232
                echo 'var grandparentNode = pagantisCheckbox.parentNode.parentNode;' . PHP_EOL;
233
                echo 'if(grandparentNode == value) { var status="" } ' . PHP_EOL;
234
                echo 'else { var status="none";} '. PHP_EOL;
235
                echo 'simulator[0].style.display=status; ' . PHP_EOL;
236
                echo '}'. PHP_EOL;
237
238
                echo 'function showSimulator()'. PHP_EOL;
239
                echo '{'. PHP_EOL;
240
                echo 'var elements = document.querySelectorAll("tr[class^=\'moduleRow\']");' . PHP_EOL;
241
                echo 'if(elements == null) { return false };' . PHP_EOL;
242
                echo 'for(var i = 0, max = elements.length; i < max; i++) { elements[i].onclick = function() {
243
                        checkSelected(this);
244
                    } }' . PHP_EOL;
245
                echo 'clearInterval(window.OSdisplayId);';
246
                echo 'return true;'. PHP_EOL;
247
                echo '};'. PHP_EOL;
248
249
                echo '       window.OSdisplayId = setInterval(function () {'. PHP_EOL;
250
                echo '          showSimulator();'. PHP_EOL;
251
                echo '       }, 2000);'. PHP_EOL;
252
                echo '</script>'. PHP_EOL;
253
            }
254
        }
255
        $oscTemplate->addBlock(ob_get_clean(), $this->group);
256
    }
257
258
    /**
259
     * @return bool
260
     */
261
    function isEnabled() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
262
        return $this->enabled;
263
    }
264
265
    /**
266
     * @return bool
267
     */
268
    function check() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
269
        return defined('MODULE_HEADER_TAGS_PAGANTIS_STATUS');
270
    }
271
272
    /**
273
     * install
274
     */
275
    function install() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
276
        tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable Pagantis Module', 'MODULE_HEADER_TAGS_PAGANTIS_STATUS', 'True', '', '6', '1', 'tep_cfg_select_option(array(\'True\', \'False\'), ', now())");
0 ignored issues
show
Bug introduced by
The constant TABLE_CONFIGURATION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The function tep_db_query was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

276
        /** @scrutinizer ignore-call */ 
277
        tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable Pagantis Module', 'MODULE_HEADER_TAGS_PAGANTIS_STATUS', 'True', '', '6', '1', 'tep_cfg_select_option(array(\'True\', \'False\'), ', now())");
Loading history...
277
278
    }
279
280
    /**
281
     * remove
282
     */
283
    function remove() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
284
        tep_db_query("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
0 ignored issues
show
Bug introduced by
The function tep_db_query was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

284
        /** @scrutinizer ignore-call */ 
285
        tep_db_query("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
Loading history...
Bug introduced by
The constant TABLE_CONFIGURATION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
285
    }
286
287
    /**
288
     * @return array
289
     */
290
    function keys() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
291
        return array('MODULE_HEADER_TAGS_PAGANTIS_STATUS');
292
    }
293
294
    /**
295
     * @param $productId
296
     *
297
     * @return bool
298
     */
299
    private function isPromoted($productId)
300
    {
301
        if (!isset($productId)) {
302
            return false;
303
        }
304
305
        if ($this->extraConfig['PAGANTIS_PROMOTION'] == '') {
306
            $promotedProducts = array();
307
        } else {
308
            $promotedProducts = array_values((array)unserialize($this->extraConfig['PAGANTIS_PROMOTION']));
309
        }
310
311
        return (in_array($productId, $promotedProducts));
312
    }
313
}
314