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

PriceFacade::getInner()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\Checkout\Cart\Facade;
4
5
use Shopware\Core\Checkout\Cart\CartException;
6
use Shopware\Core\Checkout\Cart\Facade\Traits\PriceFactoryTrait;
7
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
8
use Shopware\Core\Checkout\Cart\Price\Struct\CalculatedPrice;
9
use Shopware\Core\Checkout\Cart\Price\Struct\CartPrice;
10
use Shopware\Core\Checkout\Cart\Price\Struct\PriceCollection as CalculatedPriceCollection;
11
use Shopware\Core\Checkout\Cart\Price\Struct\QuantityPriceDefinition;
12
use Shopware\Core\Checkout\Cart\Tax\Struct\CalculatedTaxCollection;
13
use Shopware\Core\Checkout\Cart\Tax\Struct\TaxRuleCollection;
14
use Shopware\Core\Framework\DataAbstractionLayer\Entity;
15
use Shopware\Core\Framework\DataAbstractionLayer\Pricing\Price;
16
use Shopware\Core\Framework\DataAbstractionLayer\Pricing\PriceCollection;
17
use Shopware\Core\Framework\Log\Package;
18
use Shopware\Core\System\SalesChannel\SalesChannelContext;
19
20
/**
21
 * The PriceFacade is a wrapper around a price.
22
 *
23
 * @script-service cart_manipulation
24
 * @script-service product
25
 */
26
#[Package('checkout')]
27
class PriceFacade
28
{
29
    use PriceFactoryTrait;
30
31
    /**
32
     * @internal
33
     */
34
    public function __construct(
35
        protected Entity|LineItem $item,
36
        protected CalculatedPrice $price,
37
        protected ScriptPriceStubs $priceStubs,
38
        protected SalesChannelContext $context
39
    ) {
40
    }
41
42
    /**
43
     * @internal
44
     */
45
    public function getInner(): CalculatedPrice
46
    {
47
        return $this->price;
48
    }
49
50
    /**
51
     * `getTotal()` returns the total price for the line-item.
52
     *
53
     * @return float The total price as float.
54
     */
55
    public function getTotal(): float
56
    {
57
        return $this->price->getTotalPrice();
58
    }
59
60
    /**
61
     * `getUnit()` returns the unit price for the line-item.
62
     * This is equivalent to the total price of the line-item with the quantity 1.
63
     *
64
     * @return float The price per unit as float.
65
     */
66
    public function getUnit(): float
67
    {
68
        return $this->price->getUnitPrice();
69
    }
70
71
    /**
72
     * `getQuantity()` returns the quantity that was used to calculate the total price.
73
     *
74
     * @return int Returns the quantity.
75
     */
76
    public function getQuantity(): int
77
    {
78
        return $this->price->getQuantity();
79
    }
80
81
    /**
82
     * `getTaxes()` returns the calculated taxes of the price.
83
     *
84
     * @return CalculatedTaxCollection Returns the calculated taxes.
85
     */
86
    public function getTaxes(): CalculatedTaxCollection
87
    {
88
        return $this->price->getCalculatedTaxes();
89
    }
90
91
    /**
92
     * `getRules()` returns the tax rules that were used to calculate the price.
93
     *
94
     * @return TaxRuleCollection Returns the tax rules.
95
     */
96
    public function getRules(): TaxRuleCollection
97
    {
98
        return $this->price->getTaxRules();
99
    }
100
101
    /**
102
     * `change()` allows a price overwrite of the current price scope. The provided price will be recalculated
103
     * over the quantity price calculator to consider quantity, tax rule and cash rounding configurations.
104
     *
105
     * @example pricing-cases/product-pricing.twig 40 5 Overwrite prices with a static defined collection
106
     *
107
     * @param PriceCollection $price The provided price can be a fetched price from the database or generated over the `PriceFactory` statically
108
     */
109
    public function change(PriceCollection $price): void
110
    {
111
        $value = $this->getPriceForTaxState($price, $this->context);
112
113
        $definition = new QuantityPriceDefinition(
114
            $value,
115
            $this->price->getTaxRules(),
116
            $this->getQuantity()
117
        );
118
119
        $this->overwrite($definition);
120
    }
121
122
    /**
123
     * `plus()` allows a price addition of the current price scope. The provided price will be recalculated via the quantity price calculator.
124
     * The provided price is interpreted as a unit price and will be added to the current unit price. The total price
125
     * is calculated afterwards considering quantity, tax rule and cash rounding configurations.
126
     *
127
     * @example pricing-cases/product-pricing.twig 14 5 Plus a static defined price to the existing calculated price
128
     *
129
     * @param PriceCollection $price The provided price can be a fetched price from the database or generated over the `PriceFactory` statically
130
     */
131
    public function plus(PriceCollection $price): void
132
    {
133
        $value = $this->getPriceForTaxState($price, $this->context);
134
135
        $definition = new QuantityPriceDefinition(
136
            $this->price->getUnitPrice() + abs($value),
137
            $this->price->getTaxRules(),
138
            $this->getQuantity()
139
        );
140
141
        $this->overwrite($definition);
142
    }
143
144
    /**
145
     * `minus()` allows a price subtraction of the current price scope. The provided price will be recalculated via the quantity price calculator.
146
     * The provided price is interpreted as a unit price and will reduce to the current unit price. The total price
147
     * is calculated afterwards considering quantity, tax rule and cash rounding configurations.
148
     *
149
     * @example pricing-cases/product-pricing.twig 22 5 Minus a static defined price to the existing calculated price
150
     *
151
     * @param PriceCollection $price The provided price can be a fetched price from the database or generated over the `PriceFactory` statically
152
     */
153
    public function minus(PriceCollection $price): void
154
    {
155
        $value = $this->getPriceForTaxState($price, $this->context);
156
157
        $definition = new QuantityPriceDefinition(
158
            $this->price->getUnitPrice() - abs($value),
159
            $this->price->getTaxRules(),
160
            $this->getQuantity()
161
        );
162
163
        $this->overwrite($definition);
164
    }
165
166
    /**
167
     * `discount()` allows a percentage discount calculation of the current price scope. The provided value will be ensured to be negative via `abs(value) * -1`.
168
     * The provided discount is interpreted as a percentage value and will be applied to the unit price and the total price as well.
169
     *
170
     * @example pricing-cases/product-pricing.twig 30 1 Adds a 10% discount to the existing calculated price
171
     *
172
     * @param float $value The percentage value of the discount. The value will be ensured to be negative via `abs(value) * -1`.
173
     */
174
    public function discount(float $value): void
175
    {
176
        $definition = new QuantityPriceDefinition($this->price->getUnitPrice(), $this->price->getTaxRules());
177
        $definition->setIsCalculated(true);
178
179
        $unit = $this->priceStubs->calculateQuantity($definition, $this->context);
180
181
        $discount = $this->priceStubs->calculatePercentage(\abs($value), new CalculatedPriceCollection([$unit]), $this->context);
182
183
        $definition = new QuantityPriceDefinition(
184
            $this->price->getUnitPrice() - $discount->getUnitPrice(),
185
            $this->price->getTaxRules(),
186
            $this->getQuantity()
187
        );
188
189
        $this->overwrite($definition);
190
    }
191
192
    /**
193
     * `surcharge()` allows a percentage surcharge calculation of the current price scope. The provided value will be ensured to be negative via `abs(value)`.
194
     * The provided surcharge is interpreted as a percentage value and will be applied to the unit price and the total price as well.
195
     *
196
     * @example pricing-cases/product-pricing.twig 34 1 Adds a 10% surcharge to the existing calculated price
197
     *
198
     * @param float $value The percentage value of the surcharge. The value will be ensured to be negative via `abs(value)`.
199
     */
200
    public function surcharge(float $value): void
201
    {
202
        $definition = new QuantityPriceDefinition($this->price->getUnitPrice(), $this->price->getTaxRules());
203
        $definition->setIsCalculated(true);
204
205
        $unit = $this->priceStubs->calculateQuantity($definition, $this->context);
206
207
        $discount = $this->priceStubs->calculatePercentage(\abs($value), new CalculatedPriceCollection([$unit]), $this->context);
208
209
        $definition = new QuantityPriceDefinition(
210
            $this->price->getUnitPrice() + $discount->getUnitPrice(),
211
            $this->price->getTaxRules(),
212
            $this->getQuantity()
213
        );
214
215
        $this->overwrite($definition);
216
    }
217
218
    protected function getPriceForTaxState(PriceCollection $price, SalesChannelContext $context): float
219
    {
220
        $currency = $price->getCurrencyPrice($this->context->getCurrencyId());
221
222
        if (!$currency instanceof Price) {
223
            throw CartException::invalidPriceDefinition();
224
        }
225
226
        if ($context->getTaxState() === CartPrice::TAX_STATE_GROSS) {
227
            return $currency->getGross();
228
        }
229
230
        return $currency->getNet();
231
    }
232
233
    private function overwrite(QuantityPriceDefinition $definition): void
234
    {
235
        if ($this->item instanceof LineItem) {
236
            $this->item->markModifiedByApp();
237
238
            $this->item->setPriceDefinition($definition);
239
        }
240
241
        $new = $this->priceStubs->calculateQuantity($definition, $this->context);
242
243
        $this->price->overwrite(
244
            $new->getUnitPrice(),
245
            $new->getTotalPrice(),
246
            $new->getCalculatedTaxes(),
247
        );
248
    }
249
}
250