Issues (258)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

Components/BasketHelper.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * (c) shopware AG <[email protected]>
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 */
7
8
namespace ShopwarePlugins\Connect\Components;
9
10
use Shopware\Connect\Gateway\PDO;
11
use Shopware\Connect\Struct\CheckResult;
12
use Shopware\Connect\SDK;
13
use Shopware\Connect\Struct\Message;
14
use Shopware\Connect\Struct\Product;
15
16
/**
17
 * Handles the basket manipulation. Most of it is done by modifying the template variables shown to the user.
18
 * Once we have new basket and order core classes, this should be refactored.
19
 *
20
 * Class BasketHelper
21
 * @package ShopwarePlugins\Connect\Components
22
 */
23
class BasketHelper
24
{
25
    const REMOTE_SHIPPING = 'remote';
26
27
    /**
28
     * The basket array decorated by this class
29
     * @var array
30
     */
31
    protected $basket;
32
33
    /**
34
     * Array of connect product structs
35
     * @var array
36
     */
37
    protected $connectProducts = [];
38
39
    /**
40
     * connect content as formated by shopware
41
     *
42
     * @var array
43
     */
44
    protected $connectContent = [];
45
46
    /**
47
     * Array of connect shops affected by this basket
48
     *
49
     * @var array
50
     */
51
    protected $connectShops = [];
52
53
    /**
54
     * @var \Shopware\Connect\Struct\CheckResult
55
     */
56
    protected $checkResult;
57
58
    /**
59
     * The original shopware shipping costs
60
     *
61
     * @var float
62
     */
63
    protected $originalShippingCosts = 0;
64
65
    /**
66
     * Should there be a connect hint in the template
67
     *
68
     * @var bool
69
     */
70
    protected $showCheckoutShopInfo;
71
72
    /**
73
     * @var \Shopware\Connect\SDK
74
     */
75
    protected $sdk;
76
77
    /**
78
     * @var \Enlight_Components_Db_Adapter_Pdo_Mysql
79
     */
80
    protected $database;
81
82
    /**
83
     * @var Helper
84
     */
85
    protected $helper;
86
87
    /**
88
     * @var \Shopware\Connect\Gateway\PDO
89
     */
90
    protected $connectGateway;
91
92
    /**
93
     * Indicates if the basket has only connect products or not
94
     *
95
     * @var bool
96
     */
97
    protected $onlyConnectProducts = false;
98
99
    /**
100
     * @param \Enlight_Components_Db_Adapter_Pdo_Mysql $database
101
     * @param \Shopware\Connect\SDK $sdk
102
     * @param Helper $helper
103
     * @param $showCheckoutShopInfo
104
     */
105
    public function __construct(
106
        \Enlight_Components_Db_Adapter_Pdo_Mysql $database,
107
        SDK $sdk,
108
        Helper $helper,
109
        PDO $connectGateway,
110
        $showCheckoutShopInfo
111
    ) {
112
        $this->database = $database;
113
        $this->sdk = $sdk;
114
        $this->helper = $helper;
115
        $this->connectGateway = $connectGateway;
116
        $this->showCheckoutShopInfo = $showCheckoutShopInfo;
117
    }
118
119
    /**
120
     * Prepare the basket for connect
121
     *
122
     * @return void
123
     */
124
    public function prepareBasketForConnect()
125
    {
126
        $this->buildProductsArray();
127
        $this->buildShopsArray();
128
    }
129
130
    /**
131
     * Build array of connect products. This will remove connect products from the 'content' array
132
     */
133
    protected function buildProductsArray()
134
    {
135
        $this->connectProducts = [];
136
        $this->connectContent = [];
137
138
        $this->basket['contentOrg'] = $this->basket['content'];
139
140
        foreach ($this->basket['content'] as $key => &$row) {
141
            if (!empty($row['mode'])) {
142
                continue;
143
            }
144
145
            $articleDetailId = $row['additional_details']['articleDetailsID'];
146
            if ($this->helper->isRemoteArticleDetailDBAL($articleDetailId) === false) {
147
                continue;
148
            }
149
150
            $shopProductId = $this->helper->getShopProductId($articleDetailId);
151
            $products = $this->getHelper()->getRemoteProducts([$shopProductId->sourceId], $shopProductId->shopId);
152
            if (empty($products)) {
153
                continue;
154
            }
155
            $product = reset($products);
156
            if ($product === null || $product->shopId === null) {
157
                continue;
158
            }
159
            $row['connectShopId'] = $product->shopId;
160
            $this->connectProducts[$product->shopId][$product->sourceId] = $product;
161
            $this->connectContent[$product->shopId][$product->sourceId] = $row;
162
163
            //if($actionName == 'cart') {
164
            unset($this->basket['content'][$key]);
165
            //}
166
        }
167
    }
168
169
    /**
170
     * Build array of connect remote shops
171
     */
172
    protected function buildShopsArray()
173
    {
174
        $this->connectShops = [];
175
176
        $this->basket['content'] = array_values($this->basket['content']);
177
        foreach ($this->connectContent as $shopId => $items) {
178
            $this->connectShops[$shopId] = $this->getSdk()->getShop($shopId);
179
        }
180
    }
181
182
    /**
183
     * Returns the quantity of a given product in the sw basket
184
     *
185
     * @param \Shopware\Connect\Struct\Product $product
186
     * @return mixed
187
     */
188
    public function getQuantityForProduct(Product $product)
189
    {
190
        if (isset($this->connectContent[$product->shopId]) &&
191
            isset($this->connectContent[$product->shopId][$product->sourceId])
192
        ) {
193
            return (int) $this->connectContent[$product->shopId][$product->sourceId]['quantity'];
194
        } elseif (isset($this->basket['content'][$product->sourceId])) {
195
            return (int) $this->basket['content'][$product->sourceId]['quantity'];
196
        }
197
198
        return 1;
199
    }
200
201
    /**
202
     * This method will check, if any *real* products from the local shop are in the basket. If this is not the
203
     * case, this method will:
204
     *
205
     * - set the first connect shop as content of the default basket ($basket['content'])
206
     * - remove any surcharges, vouchers and  discount from the original basket(!)
207
     *
208
     * @return bool|mixed
209
     */
210
    public function fixBasket()
211
    {
212
        // Filter out basket items which cannot be purchased on their own
213
        $content = array_filter($this->basket['content'], function ($item) {
214
            switch ((int) $item['modus']) {
215
                    case 0: // Default products
216
                    case 1: // Premium products
217
                        return true;
218
                    default:
219
                        return false;
220
                }
221
        });
222
223
        // If only connect products are in the basket, do the basket fix
224
        if (empty($content)) {
225
            $this->onlyConnectProducts = true;
226
227
            $connectContent = $this->getConnectContent();
228
            if ($this->customerHasToPayLocalShipping($connectContent) === false) {
229
                $this->basket = $this->removeDefaultShipping($this->basket);
230
            }
231
232
            reset($connectContent);
233
            $shopId = current(array_keys($connectContent));
234
235
            $config = $this->getConfig();
236
            if ($config->getConfig('removeBasketAdditions'))
237
            {
238
                $this->removeNonProductsFromBasket();
239
            }
240
241
            if (count($this->basket['content']) == 0) {
242
                // Make the first connect shop the default basket-content
243
                $this->basket['content'] = $connectContent[$shopId];
244
                unset($this->connectContent[$shopId]);
245
            }
246
247
            return $shopId;
248
        }
249
250
        return false;
251
    }
252
253
    /**
254
     * Verifies that some of suppliers as shippingCosts type
255
     * different from "remote". Then endcustomer must pay
256
     * merchant shipping costs
257
     *
258
     * @param array $connectContent
259
     * @return bool
260
     */
261
    private function customerHasToPayLocalShipping(array $connectContent)
262
    {
263
        $useLocalShipping = false;
264
265
        foreach (array_keys($connectContent) as $shopId) {
266
            $shopConfiguration = $this->connectGateway->getShopConfiguration($shopId);
267
            if ($shopConfiguration === null) {
268
                continue;
269
            }
270
271
            if ($shopConfiguration->importedProductsShippingCostType != self::REMOTE_SHIPPING) {
272
                $useLocalShipping = true;
273
                break;
274
            }
275
        }
276
277
        return $useLocalShipping;
278
    }
279
280
    /**
281
     * Remove shipping costs from given basket
282
     *
283
     * @param array $basket
284
     * @return array
285
     */
286
    private function removeDefaultShipping(array $basket)
287
    {
288
        $basket['AmountNumeric'] -= $basket['sShippingcosts'];
289
        $basket['AmountNetNumeric'] -= $basket['sShippingcostsNet'];
290
291
        $basketHasTax = $this->hasTax();
292
        if (!empty($this->basket['sAmountWithTax'])) {
293
            if ($basketHasTax) {
294
                $this->basket['sAmountWithTax'] -= $basket['sShippingcosts'];
295
            } else {
296
                $this->basket['sAmountWithTax'] -= $basket['sShippingcostsNet'];
297
            }
298
        }
299
300
        if ($basketHasTax) {
301
            $basket['sAmount'] -= $basket['sShippingcosts'];
302
        } else {
303
            $basket['sAmount'] -= $basket['sShippingcostsNet'];
304
        }
305
306
        $basket['sShippingcosts'] = 0;
307
        $basket['sShippingcostsNet'] = 0;
308
        $basket['sShippingcostsWithTax'] = 0;
309
310
        return $basket;
311
    }
312
313
    /**
314
     * Removes non-connect products from the database and fixes the basket variables
315
     */
316
    protected function removeNonProductsFromBasket()
317
    {
318
        $removeItems = [
319
            'ids' => [],
320
            'price' => 0,
321
            'netprice' => 0,
322
            'sessionId' => null
323
        ];
324
325
        // Build array of ids and amount to fix the basket later
326
        foreach ($this->basket['content'] as  $key => $product) {
327
            $removeItems['ids'][] = $product['id'];
328
            $removeItems['price'] += $product['price'] * $product['quantity'];
329
            $removeItems['amountWithTax'] += $product['amountWithTax'] * $product['quantity'];
330
            $removeItems['netprice'] += $product['netprice'] * $product['quantity'];
331
            $removeItems['tax'] += str_replace(',', '.', $product['tax']) * $product['quantity'];
332
            $removeItems['sessionId'] = $product['sessionID'];
333
334
            // Remove surcharge, cannot be deleted with SQL
335
            if ($product['modus'] == 4) {
336
                unset($this->basket['content'][$key]);
337
            }
338
        }
339
340
        if (empty($removeItems['ids'])) {
341
            return;
342
        }
343
344
        // Fix basket prices
345
        $this->basket['AmountNumeric'] -= $removeItems['price'];
346
        $this->basket['AmountNetNumeric'] -= $removeItems['netprice'];
347
        $this->basket['sAmount'] -= $removeItems['price'];
348
        $this->basket['Amount'] = str_replace(',', '.', $this->basket['Amount']) - $removeItems['price'];
349
350
        $this->basket['sAmountTax'] -= $removeItems['tax'];
351
        if (!empty($this->basket['sAmountWithTax'])) {
352
            if ($this->hasTax()) {
353
                $this->basket['sAmountWithTax'] -= $removeItems['price'];
354
            } else {
355
                $this->basket['sAmountWithTax'] -= $removeItems['amountWithTax'];
356
                $this->basket['AmountWithTaxNumeric'] -= $removeItems['amountWithTax'];
357
                $this->basket['AmountWithTax'] = $this->basket['AmountWithTaxNumeric'];
358
                $this->basket['amountnet'] = $this->basket['amount'];
359
            }
360
        }
361
362
        // Remove items from basket
363
        $this->getDatabase()->query(
364
            'DELETE FROM s_order_basket WHERE sessionID = ? and id IN (?)',
365
            [
366
                $removeItems['sessionId'],
367
                implode(',', $removeItems['ids'])
368
            ]
369
        );
370
371
        // Filter out basket items - surcharge
372
        $this->basket['contentOrg'] = array_filter($this->basket['contentOrg'], function ($item) {
373
            switch ((int) $item['modus']) {
374
                case 4: // Surcharge
375
                    return false;
376
                default:
377
                    return true;
378
            }
379
        });
380
    }
381
382
    /**
383
     * @todo: This function is basically a copy of the same function in Controllers/Frontend/Checkout.
384
     * As that function cannot be called, I copied it for the time being - this should be refactored
385
     *
386
     * @param  $basket array returned from this->getBasket
387
     * @return array
388
     */
389
    public function getTaxRates($basket)
390
    {
391
        $result = [];
392
393
        // The original method also calculates the tax rates of the shipping costs - this
394
        // is done in a separate methode here
395
396
        if (empty($basket['content'])) {
397
            ksort($result, SORT_NUMERIC);
398
399
            return $result;
400
        }
401
402
        foreach ($basket['content'] as $item) {
403
            if (!empty($item['tax_rate'])) {
404
            } elseif (!empty($item['taxPercent'])) {
405
                $item['tax_rate'] = $item['taxPercent'];
406
            } elseif ($item['modus'] == 2) {
407
                // Ticket 4842 - dynamic tax-rates
408
                $resultVoucherTaxMode = Shopware()->Db()->fetchOne(
409
                    'SELECT taxconfig FROM s_emarketing_vouchers WHERE ordercode=?',
410
                    [$item['ordernumber']]
411
                );
412
                // Old behaviour
413
                if (empty($resultVoucherTaxMode) || $resultVoucherTaxMode == 'default') {
414
                    $tax = Shopware()->Config()->get('sVOUCHERTAX');
415
                } elseif ($resultVoucherTaxMode == 'auto') {
416
                    // Automatically determinate tax
417
                    $tax = Shopware()->Modules()->Basket()->getMaxTax();
418
                } elseif ($resultVoucherTaxMode == 'none') {
419
                    // No tax
420
                    $tax = '0';
421
                } elseif (intval($resultVoucherTaxMode)) {
422
                    // Fix defined tax
423
                    $tax = Shopware()->Db()->fetchOne(
424
                        'SELECT tax FROM s_core_tax WHERE id = ?',
425
                        [$resultVoucherTaxMode]
426
                    );
427
                }
428
                $item['tax_rate'] = $tax;
0 ignored issues
show
The variable $tax does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
429
            } else {
430
                // Ticket 4842 - dynamic tax-rates
431
                $taxAutoMode = Shopware()->Config()->get('sTAXAUTOMODE');
432
                if (!empty($taxAutoMode)) {
433
                    $tax = Shopware()->Modules()->Basket()->getMaxTax();
434
                } else {
435
                    $tax = Shopware()->Config()->get('sDISCOUNTTAX');
436
                }
437
                $item['tax_rate'] = $tax;
438
            }
439
440
            // Ignore 0 % tax
441
            if (empty($item['tax_rate']) || empty($item['tax'])) {
442
                continue;
443
            }
444
            $taxKey = number_format(floatval($item['tax_rate']), 2);
445
            $result[$taxKey] += str_replace(',', '.', $item['tax']);
446
        }
447
448
        ksort($result, SORT_NUMERIC);
449
450
        return $result;
451
    }
452
453
    /**
454
     * Returns an array of tax positions in the same way, as shopware does in the sTaxRates.
455
     * This will only take connect products returned by getConnectContent() into account,
456
     * so that connect positions moved into basket['content'] earlier are not calculated twice.
457
     *
458
     * @return array
459
     */
460
    public function getConnectTaxRates()
461
    {
462
        $taxes = [];
463
464
        foreach ($this->getConnectContent() as $shopId => $products) {
465
            foreach ($products as $product) {
466
                $vat = (string) number_format($product['tax_rate'], 2);
467
                if (!isset($taxes[$vat])) {
468
                    $taxes[$vat] = 0;
469
                }
470
471
                if ($this->hasTax()) {
472
                    $taxes[$vat] += $product['priceNumeric'] - $product['netprice'];
473
                } else {
474
                    $taxes[$vat] += $product['amountWithTax'] - ($product['netprice'] * $product['quantity']);
475
                }
476
            }
477
        }
478
479
        return $taxes;
480
    }
481
482
    /**
483
     * Will merge/add various arrays of "sTaxRates" like arrays into one array
484
     *
485
     * @param array $taxRates
486
     * @return array
487
     */
488
    public function getMergedTaxRates(array $taxRates)
489
    {
490
        $result = [];
491
492
        foreach ($taxRates as $taxRate) {
493
            foreach ($taxRate as $vat => $amount) {
494
                if (!isset($result[$vat])) {
495
                    $result[$vat] = 0;
496
                }
497
                $result[$vat] += $amount;
498
            }
499
        }
500
501
        return $result;
502
    }
503
504
    /**
505
     * Increase the basket's shipping costs and amount by the total value of connect shipping costs
506
     *
507
     * @param \Shopware\Connect\Struct\CheckResult $checkResult
508
     */
509
    public function recalculate(CheckResult $checkResult)
510
    {
511
        $this->checkResult = $checkResult;
512
        $this->basket['sAmount'] = number_format($this->basket['sAmount'], 2, '.', '');
513
514
        $shippingCostsNet = 0;
515
        $shippingCostsWithTax = 0;
516
517
        /** @var \Shopware\Connect\Struct\Shipping $shipping */
518
        foreach ($this->checkResult->shippingCosts as $shipping) {
519
            $shopConfiguration = $this->connectGateway->getShopConfiguration($shipping->shopId);
520
            if ($shopConfiguration->importedProductsShippingCostType == self::REMOTE_SHIPPING) {
521
                $shippingCostsNet += $shipping->shippingCosts;
522
                $shippingCostsWithTax += $shipping->grossShippingCosts;
523
            }
524
        }
525
        $shippingCostsNet = number_format($shippingCostsNet, 2, '.', '');
526
        $shippingCostsWithTax = number_format($shippingCostsWithTax, 2, '.', '');
527
528
        $basketHasTax = $this->hasTax();
529
530
        // Set the shipping cost tax rate for shopware
531
532
        $this->setOriginalShippingCosts($this->basket['sShippingcosts']);
533
534
        // Update shipping costs
535
        if ($basketHasTax) {
536
            $this->basket['sShippingcosts'] += $shippingCostsWithTax;
537
        } else {
538
            $this->basket['sShippingcosts'] += $shippingCostsNet;
539
        }
540
        $this->basket['sShippingcostsNet'] += $shippingCostsNet;
541
        $this->basket['sShippingcostsWithTax'] += $shippingCostsWithTax;
542
543
        $this->basket['AmountNetNumeric'] += $shippingCostsNet;
544
545
        if (!empty($this->basket['sAmountWithTax'])) {
546
            if ($basketHasTax) {
547
                $this->basket['sAmountWithTax'] += $this->basket['sShippingcostsWithTax'];
548
            } else {
549
                $this->basket['sAmountWithTax'] += $shippingCostsWithTax;
550
            }
551
        }
552
553
        if ($basketHasTax) {
554
            $this->basket['sAmount'] += $shippingCostsWithTax;
555
        } else {
556
            $this->basket['sAmount'] += $shippingCostsNet;
557
        }
558
559
        $this->basket['sAmountTax'] += $this->basket['sShippingcostsWithTax'] - $shippingCostsNet;
560
561
        // Core workaround: Shopware tries to re-calculate the shipping tax rate from the net price
562
        // \Shopware_Models_Document_Order::processOrder
563
        // Therefore we need to round the net price
564
        $this->basket['sShippingcostsNet'] = round($this->basket['sShippingcostsNet'], 2);
565
566
567
        // Recalculate the tax rates
568
        $this->basket['sTaxRates'] = $this->getMergedTaxRates(
569
            [
570
                $this->getTaxRates($this->basket),
571
                $this->getConnectTaxRates(),
572
                $this->getShippingCostsTaxRates()
573
            ]
574
        );
575
576
        //@todo:stefan Check for better solution
577
        $this->basket['AmountWithTaxNumeric'] = $this->basket['sAmountWithTax'];
578
        $this->basket['AmountNumeric'] = $this->basket['sAmount'];
579
    }
580
581
    /**
582
     * Returns the tax rate of the shipping costs and also sets the the net shipping cost amount(!)
583
     */
584
    public function getShippingCostsTaxRates()
585
    {
586
        $taxAmount = $this->basket['sShippingcostsWithTax'] - $this->basket['sShippingcostsNet'];
587
588
        $taxRate = number_format($this->getMaxTaxRate(), 2, '.', '');
589
        $this->basket['sShippingcostsNet'] = $this->basket['sShippingcostsWithTax'] / (($taxRate/100)+1);
590
591
        return [
592
            (string) $taxRate => $taxAmount
593
        ];
594
    }
595
596
    /**
597
     * Get the highest tax rate from basket - currently only this is supported by SW
598
     *
599
     * @return int
600
     */
601
    public function getMaxTaxRate()
602
    {
603
        $taxRate = 0;
604
        foreach ($this->getConnectContent() as $shopId => $products) {
605
            foreach ($products as $product) {
606
                if ($product['tax_rate'] > $taxRate) {
607
                    $taxRate = $product['tax_rate'];
608
                }
609
            }
610
        }
611
612
        foreach ($this->basket['content'] as $product) {
613
            if ($product['tax_rate'] > $taxRate) {
614
                $taxRate = $product['tax_rate'];
615
            }
616
        }
617
618
        return $taxRate;
619
    }
620
621
    /**
622
     * Return array of variables which need to be available in the default template
623
     *
624
     * @return array
625
     */
626
    public function getDefaultTemplateVariables()
627
    {
628
        return [
629
            'sBasket' => $this->basket,
630
            'sShippingcosts' => $this->basket['sShippingcosts'],
631
            'sAmount' => $this->basket['sAmount'],
632
            'sAmountWithTax' => $this->basket['sAmountWithTax'],
633
            'sAmountNet' => $this->basket['AmountNetNumeric']
634
        ];
635
    }
636
637
    /**
638
     * Return array of connect specific template variables
639
     *
640
     * @param $connectMessages array Messages to show
641
     * @return array
642
     */
643
    public function getConnectTemplateVariables(array $connectMessages)
644
    {
645
        $snippets = Shopware()->Snippets()->getNamespace('frontend/checkout/error_messages');
646
647
        /** @var Message $message */
648
        foreach ($connectMessages as $message) {
649
            if ($message->message == 'Availability of product %product changed to %availability.') {
650
651
                $this->determineProductTitle($message);
652
653
                if ($message->values['availability'] == 0) {
654
                    $message->message = $snippets->get(
655
                        'connect_product_out_of_stock_message_detailed',
656
                        'Das Produkt "%ptitle" in Ihrer Bestellung ist aktuell nicht lieferbar. Bitte entfernen Sie das Produkt um fortzufahren.'
657
                    );
658
                } else {
659
                    $message->message = $snippets->get(
660
                        'connect_product_lower_stock_message_detailed',
661
                        'Der Lagerbestand von Produkt "%ptitle" hat sich auf %availability geändert.'
662
                    );
663
                }
664
            }
665
        }
666
667
        return [
668
            'connectContent' => $this->getConnectContent(),
669
            'connectShops' => $this->getConnectShops(),
670
            'connectMessages' => $connectMessages,
671
            'connectShippingCosts' => $this->getConnectGrossShippingCosts(),
672
            'connectShippingCostsOrg' => $this->getOriginalShippingCosts(),
673
            'connectShopInfo' => $this->showCheckoutShopInfo,
674
            'addBaseShop' => $this->onlyConnectProducts ? 0 : 1,
675
        ];
676
    }
677
678
    private function determineProductTitle(Message $message)
679
    {
680
        if (isset($message->values['shopId'])) {
681
            $product = $this->getConnectProducts()[$message->values['shopId']][$message->values['product']];
682
            $message->values['ptitle'] = $product->title;
683
            return;
684
        }
685
686
        //sdk version < v2.0.12
687
        foreach ($this->getConnectProducts() as $supplierArray) {
688
            foreach ($supplierArray as $product) {
689
                if ($product->sourceId == $message->values['product'] && $product->availability == 0) {
690
                    $message->values['ptitle'] = $product->title;
691
                    return;
692
                }
693
            }
694
        }
695
    }
696
697
    /**
698
     * Modifies a given OrderVariables ArrayObject
699
     *
700
     * @param $variables \ArrayObject
701
     * @return \ArrayObject
702
     */
703
    public function getOrderVariablesForSession($variables)
704
    {
705
        // Get a copy of the basket array in order to not mess up the state of the basket array
706
        $basket = $this->basket;
707
        $newVariables = $this->getDefaultTemplateVariables();
708
709
        // We need the manipulated content as the order is created from the session
710
        $basket['content'] = $basket['contentOrg'];
711
        unset($basket['contentOrg']);
712
713
714
        // Replace the original session array with the new one
715
        $variables->exchangeArray(array_merge(
716
            $variables->getArrayCopy(),
717
            $newVariables,
718
            ['sBasket' => $basket]
719
        ));
720
721
        return $variables;
722
    }
723
724
    /**
725
     * Find all percentaged vouchers for a given individual code
726
     *
727
     * @param $voucherCode
728
     * @return mixed
729
     */
730 View Code Duplication
    public function findPercentagedIndividualVouchers($voucherCode)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
731
    {
732
        $builder = Shopware()->Models()->createQueryBuilder();
733
734
        $builder->select('voucher')
735
            ->from('Shopware\Models\Voucher\Voucher', 'voucher')
736
            ->innerJoin('voucher.codes', 'codes', 'WITH', 'codes.code LIKE :voucherCode')
737
            ->where('voucher.percental = true')
738
            ->setParameter('voucherCode', $voucherCode);
739
740
        return $builder->getQuery()->getResult();
741
    }
742
743
    /**
744
     * Find all vouchers matching the code
745
     *
746
     * @param $voucherCode
747
     * @return mixed
748
     */
749 View Code Duplication
    public function findPercentagedVouchers($voucherCode)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
750
    {
751
        $builder = Shopware()->Models()->createQueryBuilder();
752
753
        $builder->select('voucher')
754
            ->from('Shopware\Models\Voucher\Voucher', 'voucher')
755
            ->where('voucher.voucherCode LIKE :voucherCode')
756
            ->andWhere('voucher.percental = true')
757
            ->setParameter('voucherCode', $voucherCode);
758
759
        return $builder->getQuery()->getResult();
760
    }
761
762
    /**
763
     * @return \Shopware\Connect\SDk
764
     */
765
    public function getSdk()
766
    {
767
        return $this->sdk;
768
    }
769
770
    /**
771
     * @return Helper
772
     */
773
    public function getHelper()
774
    {
775
        return $this->helper;
776
    }
777
778
    /**
779
     * @param mixed $basket
780
     */
781
    public function setBasket($basket)
782
    {
783
        $this->basket = $basket;
0 ignored issues
show
Documentation Bug introduced by
It seems like $basket of type * is incompatible with the declared type array of property $basket.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
784
        $this->prepareBasketForConnect();
785
    }
786
787
    /**
788
     * @return mixed
789
     */
790
    public function getBasket()
791
    {
792
        return $this->basket;
793
    }
794
795
    /**
796
     * @param array $connectContent
797
     */
798
    public function setConnectContent($connectContent)
799
    {
800
        $this->connectContent = $connectContent;
801
    }
802
803
    /**
804
     * @return array
805
     */
806
    public function getConnectContent()
807
    {
808
        return $this->connectContent;
809
    }
810
811
    /**
812
     * @param array $connectProducts
813
     */
814
    public function setConnectProducts($connectProducts)
815
    {
816
        $this->connectProducts = $connectProducts;
817
    }
818
819
    /**
820
     * @return array
821
     */
822
    public function getConnectProducts()
823
    {
824
        return $this->connectProducts;
825
    }
826
827
    /**
828
     * @param array $connectShops
829
     */
830
    public function setConnectShops($connectShops)
831
    {
832
        $this->connectShops = $connectShops;
833
    }
834
835
    /**
836
     * @return array
837
     */
838
    public function getConnectShops()
839
    {
840
        return $this->connectShops;
841
    }
842
843
    /**
844
     * @return array
845
     */
846
    public function getConnectGrossShippingCosts()
847
    {
848
        $result = [];
849
        if (!$this->checkResult instanceof CheckResult) {
850
            return $result;
851
        }
852
853
        foreach ($this->checkResult->shippingCosts as $shipping) {
854
            if ($this->hasTax()) {
855
                $result[$shipping->shopId] = $shipping->grossShippingCosts;
856
            } else {
857
                $result[$shipping->shopId] = $shipping->shippingCosts;
858
            }
859
        }
860
861
        return $result;
862
    }
863
864
    /**
865
     * @param mixed $originalShippingCosts
866
     */
867
    public function setOriginalShippingCosts($originalShippingCosts)
868
    {
869
        $this->originalShippingCosts = $originalShippingCosts;
870
    }
871
872
    /**
873
     * @return mixed
874
     */
875
    public function getOriginalShippingCosts()
876
    {
877
        return $this->originalShippingCosts;
878
    }
879
880
    /**
881
     * @param \Enlight_Components_Db_Adapter_Pdo_Mysql $database
882
     */
883
    public function setDatabase($database)
884
    {
885
        $this->database = $database;
886
    }
887
888
    /**
889
     * @return \Enlight_Components_Db_Adapter_Pdo_Mysql
890
     */
891
    public function getDatabase()
892
    {
893
        return $this->database;
894
    }
895
896
    /**
897
     * Returns "Gross price displayed in frontend" value
898
     * @return bool
899
     */
900
    protected function hasTax()
901
    {
902
        $customerGroup = Shopware()->Session()->sUserGroup;
903
        if (!$customerGroup) {
904
            $customerGroup = 'EK';
905
        }
906
907
        $repository = Shopware()->Models()->getRepository('Shopware\Models\Customer\Group');
908
        $groupModel = $repository->findOneBy(['key' => $customerGroup]);
909
910
        return $groupModel->getTax();
911
    }
912
913
    /**
914
     * @return \Shopware\Connect\Struct\CheckResult
915
     */
916
    public function getCheckResult()
917
    {
918
        return $this->checkResult ?: new CheckResult();
919
    }
920
921
    /**
922
     * @param \Shopware\Connect\Struct\CheckResult $checkResult
923
     */
924
    public function setCheckResult(CheckResult $checkResult)
925
    {
926
        $this->checkResult = $checkResult;
927
    }
928
929
    private function getConfig()
930
    {
931
        return ConfigFactory::getConfigInstance();
932
    }
933
}
934