Passed
Push — trunk ( b03e0c...bc72f3 )
by Christian
13:43 queued 13s
created

ScriptPriceStubs::calculateQuantity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\Checkout\Cart\Facade;
4
5
use Doctrine\DBAL\Connection;
6
use Shopware\Core\Checkout\Cart\CartException;
7
use Shopware\Core\Checkout\Cart\Price\PercentagePriceCalculator;
8
use Shopware\Core\Checkout\Cart\Price\QuantityPriceCalculator;
9
use Shopware\Core\Checkout\Cart\Price\Struct\CalculatedPrice;
10
use Shopware\Core\Checkout\Cart\Price\Struct\PriceCollection as CalculatedPriceCollection;
11
use Shopware\Core\Checkout\Cart\Price\Struct\QuantityPriceDefinition;
12
use Shopware\Core\Defaults;
13
use Shopware\Core\Framework\DataAbstractionLayer\Pricing\Price;
14
use Shopware\Core\Framework\DataAbstractionLayer\Pricing\PriceCollection;
15
use Shopware\Core\Framework\Log\Package;
16
use Shopware\Core\Framework\Uuid\Uuid;
17
use Shopware\Core\System\SalesChannel\SalesChannelContext;
18
use Symfony\Contracts\Service\ResetInterface;
19
20
/**
21
 * @internal PriceFacade is public api, this class is only a service layer for better testing and re-usability for internal logic
22
 */
23
#[Package('checkout')]
24
class ScriptPriceStubs implements ResetInterface
25
{
26
    /**
27
     * @var array<string, string>
28
     */
29
    private array $currencies = [];
30
31
    public function __construct(
32
        private readonly Connection $connection,
33
        private readonly QuantityPriceCalculator $quantityCalculator,
34
        private readonly PercentagePriceCalculator $percentageCalculator
35
    ) {
36
    }
37
38
    public function calculateQuantity(QuantityPriceDefinition $definition, SalesChannelContext $context): CalculatedPrice
39
    {
40
        return $this->quantityCalculator->calculate($definition, $context);
41
    }
42
43
    public function calculatePercentage(float $percentage, CalculatedPriceCollection $prices, SalesChannelContext $context): CalculatedPrice
44
    {
45
        return $this->percentageCalculator->calculate($percentage, $prices, $context);
46
    }
47
48
    /**
49
     * // script value (only use case: shop owner defines a script)
50
     * set price = services.cart.price.create({
51
     *      'default': { gross: 100, net: 84.03},
52
     *      'USD': { gross: 59.5 net: 50 }
53
     * });
54
     *      => default will be validate on function call (shop owner has to define it)
55
     *      => we cannot calculate the net/gross equivalent value because we do not know how the price will be taxed
56
     *
57
     * // storage value (custom fields, product.price, etc)
58
     * set price = {
59
     *      { gross: 100, net: 50, currencyId: {currency-id} },
60
     *      { gross: 90, net: 40, currencyId: {currency-id} },
61
     * }; => default is validate when persisting as storage
62
     *
63
     * @param array<string, array{gross:float, net:float, linked?:bool}> $price
64
     */
65
    public function build(array $price): PriceCollection
66
    {
67
        $collection = new PriceCollection();
68
69
        $price = $this->validatePrice($price);
70
71
        foreach ($price as $id => $value) {
72
            $collection->add(
73
                new Price($id, $value['net'], $value['gross'], $value['linked'] ?? false)
74
            );
75
        }
76
77
        return $collection;
78
    }
79
80
    public function reset(): void
81
    {
82
        $this->currencies = [];
83
    }
84
85
    public function getRules(string $taxId): void
0 ignored issues
show
Unused Code introduced by
The parameter $taxId is not used and could be removed. ( Ignorable by Annotation )

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

85
    public function getRules(/** @scrutinizer ignore-unused */ string $taxId): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
86
    {
87
    }
88
89
    /**
90
     * @param array<string, array{gross:float, net:float, linked?:bool}> $price
91
     *
92
     * @return array<string, array{gross:float, net:float, linked?:bool}>
93
     */
94
    private function validatePrice(array $price): array
95
    {
96
        $price = $this->resolveIsoCodes($price);
97
98
        if (!\array_key_exists(Defaults::CURRENCY, $price)) {
99
            throw CartException::invalidPriceDefinition();
100
        }
101
102
        foreach ($price as $id => $value) {
103
            if (!Uuid::isValid($id)) {
104
                throw CartException::invalidPriceDefinition();
105
            }
106
107
            if (!\array_key_exists('gross', $value)) {
108
                throw CartException::invalidPriceDefinition();
109
            }
110
111
            if (!\array_key_exists('net', $value)) {
112
                throw CartException::invalidPriceDefinition();
113
            }
114
        }
115
116
        return $price;
117
    }
118
119
    /**
120
     * @param array<string, array{gross:float, net:float, linked?:bool, currencyId?:string}> $prices
121
     *
122
     * @return array<string, array{gross:float, net:float, linked?:bool, currencyId?:string}>
123
     */
124
    private function resolveIsoCodes(array $prices): array
125
    {
126
        if (empty($this->currencies)) {
127
            /** @var array<string, string> $currencies */
128
            $currencies = $this->connection->fetchAllKeyValue('SELECT iso_code, LOWER(HEX(id)) FROM currency');
129
            $this->currencies = $currencies;
130
        }
131
132
        $mapped = [];
133
        foreach ($prices as $iso => $value) {
134
            if ($iso === 'default') {
135
                $mapped[Defaults::CURRENCY] = $value;
136
137
                continue;
138
            }
139
140
            if (\array_key_exists('currencyId', $value)) {
141
                $mapped[$value['currencyId']] = $value;
142
143
                continue;
144
            }
145
146
            if (\array_key_exists($iso, $this->currencies)) {
147
                $mapped[$this->currencies[$iso]] = $value;
148
            }
149
        }
150
151
        return $mapped;
152
    }
153
}
154