Completed
Push — master ( 6d1c9a...5c8380 )
by Tomáš
01:28
created

PriceCalculator::calculate()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 4
nc 4
nop 0
1
<?php declare(strict_types=1);
2
3
namespace Sunfox\PriceCalculator;
4
5
use Nette\SmartObject;
6
7
/**
8
 * @property float $basePrice
9
 * @property IDiscount|NULL $discount
10
 * @property float $price
11
 * @property float $vatRate
12
 * @property float $priceVat
13
 * @property float $decimalPoints
14
 */
15
final class PriceCalculator implements IPriceCalculator
16
{
17
	use SmartObject;
18
19
	/**
20
	 * @var float
21
	 */
22
	protected $basePrice = 0.0;
23
24
	/**
25
	 * @var IDiscount|NULL
26
	 */
27
	protected $discount;
28
29
	/**
30
	 * @var float
31
	 */
32
	protected $price = 0.0;
33
34
	/**
35
	 * @var float
36
	 */
37
	protected $vatRate = 0.0;
38
39
	/**
40
	 * @var float
41
	 */
42
	protected $priceVat = 0.0;
43
44
	/**
45
	 * @var int
46
	 */
47
	protected $decimalPoints = 2;
48
49
	/**
50
	 * @var string
51
	 */
52
	protected $calculateFrom = self::FROM_BASEPRICE;
53
54
	public function __construct(float $vatRate = 0.0, float $basePrice = 0.0, ?IDiscount $discount = NULL)
55
	{
56
		$this->setVatRate($vatRate);
57
		$this->setBasePrice($basePrice);
58
		$this->setDiscount($discount);
59
	}
60
61
	/**
62
	 * Get price without VAT and discount.
63
	 */
64
	public function getBasePrice(): float
65
	{
66
		return $this->basePrice;
67
	}
68
69
	/**
70
	 * Set price without VAT and discount.
71
	 */
72
	public function setBasePrice(float $value): self
73
	{
74
		$this->basePrice = $value;
75
		$this->calculateFrom = self::FROM_BASEPRICE;
76
		return $this;
77
	}
78
79
	/**
80
	 * Get discount in percent without VAT.
81
	 */
82
	public function getDiscount(): IDiscount
83
	{
84
		return $this->discount;
85
	}
86
87
	/**
88
	 * Set discount instance.
89
	 */
90
	public function setDiscount(?IDiscount $discount): self
91
	{
92
		$this->discount = $discount;
93
		return $this;
94
	}
95
96
	/**
97
	 * Set amount discount.
98
	 */
99
	public function setAmountDiscount(float $value): self
100
	{
101
		$this->discount = new Discount\AmountDiscount($value);
102
		return $this;
103
	}
104
105
	/**
106
	 * Set percent discount.
107
	 */
108
	public function setPercentDiscount(float $value): self
109
	{
110
		$this->discount = new Discount\PercentDiscount($value);
111
		return $this;
112
	}
113
114
	/**
115
	 * Get price after discount without VAT.
116
	 */
117
	public function getPrice(): float
118
	{
119
		return $this->price;
120
	}
121
122
	/**
123
	 * Set price after discount without VAT.
124
	 */
125
	public function setPrice(float $value): self
126
	{
127
		$this->price = $value;
128
		$this->calculateFrom = self::FROM_PRICE;
129
		return $this;
130
	}
131
132
	/**
133
	 * Get VAT rate in percent.
134
	 */
135
	public function getVatRate(): float
136
	{
137
		return $this->vatRate;
138
	}
139
140
	/**
141
	 * Set VAT rate in percent.
142
	 */
143
	public function setVatRate(float $value): self
144
	{
145
		$this->vatRate = $value;
146
		return $this;
147
	}
148
149
	/**
150
	 * Get price after discount with VAT.
151
	 */
152
	public function getPriceVat(): float
153
	{
154
		return $this->priceVat;
155
	}
156
157
	/**
158
	 * Set price after discount with VAT.
159
	 */
160
	public function setPriceVat(float $value): self
161
	{
162
		$this->priceVat = $value;
163
		$this->calculateFrom = self::FROM_PRICEVAT;
164
		return $this;
165
	}
166
167
	/**
168
	 * Get decimal point for rounding.
169
	 */
170
	public function getDecimalPoints(): float
171
	{
172
		return $this->decimalPoints;
173
	}
174
175
	/**
176
	 * Set decimal point for rounding.
177
	 */
178
	public function setDecimalPoints(int $value): self
179
	{
180
		$this->decimalPoints = $value;
181
		return $this;
182
	}
183
184
	/**
185
	 * Calculate prices and return result.
186
	 */
187
	public function calculate(): PriceCalculatorResult
188
	{
189
		if ($this->calculateFrom === self::FROM_BASEPRICE) {
190
            [$basePrice, $price, $priceVat] = $this->calculateFromBasePrice();
0 ignored issues
show
Bug introduced by
The variable $basePrice does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $price does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $priceVat does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
191
		} elseif ($this->calculateFrom === self::FROM_PRICE) {
192
            [$basePrice, $price, $priceVat] = $this->calculateFromPrice();
193
		} elseif ($this->calculateFrom === self::FROM_PRICEVAT) {
194
            [$basePrice, $price, $priceVat] = $this->calculateFromPriceVat();
195
		}
196
197
		return new PriceCalculatorResult(
198
			$this, $basePrice, $this->discount, $price, $this->vatRate, $priceVat - $price, $priceVat
199
		);
200
	}
201
202
    private function calculateFromBasePrice(): array
203
    {
204
        $basePrice = $this->round($this->basePrice);
205
        $price = $this->round($this->discount ? $this->discount->addDiscount($basePrice) : $basePrice);
206
        $priceVat = $this->round($price * ($this->vatRate / 100 + 1));
207
208
        return [$basePrice, $price, $priceVat];
209
	}
210
211
    private function calculateFromPrice(): array
212
    {
213
        $price = $this->round($this->price);
214
        $basePrice = $this->discount ? $this->round($this->discount->removeDiscount($price)) : $price;
215
        $priceVat = $this->round($price * ($this->vatRate / 100 + 1));
216
217
        return [$basePrice, $price, $priceVat];
218
    }
219
220
    private function calculateFromPriceVat(): array
221
    {
222
        $priceVat = $this->round($this->priceVat);
223
        $price = $this->round($priceVat / ($this->vatRate / 100 + 1));
224
        $basePrice = $this->discount ? $this->round($this->discount->removeDiscount($price)) : $price;
225
226
        return [$basePrice, $price, $priceVat];
227
    }
228
229
    private function round(float $price): float
230
    {
231
        return round($price, $this->decimalPoints);
232
	}
233
}
234