PriceCalculator   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 58
dl 0
loc 205
ccs 52
cts 52
cp 1
rs 10
c 3
b 0
f 0
wmc 26

20 Methods

Rating   Name   Duplication   Size   Complexity  
A getVatRate() 0 3 1
A __construct() 0 5 1
A getDiscount() 0 3 1
A setDecimalPoints() 0 4 1
A setVatRate() 0 4 1
A calculate() 0 12 4
A calculateFromPrice() 0 7 2
A setAmountDiscount() 0 4 1
A setBasePrice() 0 5 1
A calculateFromPriceVat() 0 7 2
A setDiscount() 0 4 1
A round() 0 3 1
A calculateFromBasePrice() 0 7 2
A setPrice() 0 5 1
A getDecimalPoints() 0 3 1
A getBasePrice() 0 3 1
A getPriceVat() 0 3 1
A setPercentDiscount() 0 4 1
A getPrice() 0 3 1
A setPriceVat() 0 5 1
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 int $decimalPoints
14
 */
15 1
final class PriceCalculator implements IPriceCalculator
16
{
17
	use SmartObject;
18
19
	protected float $basePrice = 0.0;
20
21
	protected ?IDiscount $discount = null;
22
23
	protected float $price = 0.0;
24
25
	protected float $vatRate = 0.0;
26
27
	protected float $priceVat = 0.0;
28
29
	protected int $decimalPoints = 2;
30
31
	protected string $calculateFrom = self::FROM_BASEPRICE;
32
33
	public function __construct(float $vatRate = 0.0, float $basePrice = 0.0, ?IDiscount $discount = NULL)
34
	{
35
		$this->setVatRate($vatRate);
36
		$this->setBasePrice($basePrice);
37
		$this->setDiscount($discount);
38
	}
39
40
	/**
41
	 * Get price without VAT and discount.
42
	 */
43
	public function getBasePrice(): float
44
	{
45
		return $this->basePrice;
46
	}
47
48
	/**
49
	 * Set price without VAT and discount.
50
	 */
51
	public function setBasePrice(float $value): IPriceCalculator
52
	{
53
		$this->basePrice = $value;
54 1
		$this->calculateFrom = self::FROM_BASEPRICE;
55
		return $this;
56 1
	}
57 1
58 1
	/**
59 1
	 * Get discount in percent without VAT.
60
	 */
61
	public function getDiscount(): ?IDiscount
62
	{
63
		return $this->discount;
64
	}
65
66 1
	/**
67
	 * Set discount instance.
68
	 */
69
	public function setDiscount(?IDiscount $discount): IPriceCalculator
70
	{
71
		$this->discount = $discount;
72 1
		return $this;
73
	}
74 1
75 1
	/**
76 1
	 * Set amount discount.
77
	 */
78
	public function setAmountDiscount(float $value): IPriceCalculator
79
	{
80
		$this->discount = new Discount\AmountDiscount($value);
81
		return $this;
82
	}
83
84 1
	/**
85
	 * Set percent discount.
86
	 */
87
	public function setPercentDiscount(float $value): IPriceCalculator
88
	{
89
		$this->discount = new Discount\PercentDiscount($value);
90 1
		return $this;
91
	}
92 1
93 1
	/**
94
	 * Get price after discount without VAT.
95
	 */
96
	public function getPrice(): float
97
	{
98
		return $this->price;
99 1
	}
100
101 1
	/**
102 1
	 * Set price after discount without VAT.
103
	 */
104
	public function setPrice(float $value): IPriceCalculator
105
	{
106
		$this->price = $value;
107
		$this->calculateFrom = self::FROM_PRICE;
108 1
		return $this;
109
	}
110 1
111 1
	/**
112
	 * Get VAT rate in percent.
113
	 */
114
	public function getVatRate(): float
115
	{
116
		return $this->vatRate;
117
	}
118
119 1
	/**
120
	 * Set VAT rate in percent.
121
	 */
122
	public function setVatRate(float $value): IPriceCalculator
123
	{
124
		$this->vatRate = $value;
125 1
		return $this;
126
	}
127 1
128 1
	/**
129 1
	 * Get price after discount with VAT.
130
	 */
131
	public function getPriceVat(): float
132
	{
133
		return $this->priceVat;
134
	}
135
136
	/**
137 1
	 * Set price after discount with VAT.
138
	 */
139
	public function setPriceVat(float $value): IPriceCalculator
140
	{
141
		$this->priceVat = $value;
142
		$this->calculateFrom = self::FROM_PRICEVAT;
143 1
		return $this;
144
	}
145 1
146 1
	/**
147
	 * Get decimal point for rounding.
148
	 */
149
	public function getDecimalPoints(): int
150
	{
151
		return $this->decimalPoints;
152
	}
153
154 1
	/**
155
	 * Set decimal point for rounding.
156
	 */
157
	public function setDecimalPoints(int $value): IPriceCalculator
158
	{
159
		$this->decimalPoints = $value;
160 1
		return $this;
161
	}
162 1
163 1
	/**
164 1
	 * Calculate prices and return result.
165
	 */
166
	public function calculate(): PriceCalculatorResult
167
	{
168
		if ($this->calculateFrom === self::FROM_BASEPRICE) {
169
			[$basePrice, $price, $priceVat] = $this->calculateFromBasePrice();
170
		} elseif ($this->calculateFrom === self::FROM_PRICE) {
171
			[$basePrice, $price, $priceVat] = $this->calculateFromPrice();
172 1
		} elseif ($this->calculateFrom === self::FROM_PRICEVAT) {
173
			[$basePrice, $price, $priceVat] = $this->calculateFromPriceVat();
174
		}
175
176
		return new PriceCalculatorResult(
177
			$this, $basePrice, $this->discount, $price, $this->vatRate, $priceVat - $price, $priceVat
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $priceVat does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $price does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $basePrice does not seem to be defined for all execution paths leading up to this point.
Loading history...
178 1
		);
179
	}
180 1
181 1
	/**
182
	 * @return float[]
183
	 */
184
	private function calculateFromBasePrice(): array
185
	{
186
		$basePrice = $this->round($this->basePrice);
187
		$price = $this->round($this->discount ? $this->discount->addDiscount($basePrice) : $basePrice);
188
		$priceVat = $this->round($price * ($this->vatRate / 100 + 1));
189 1
190 1
		return [$basePrice, $price, $priceVat];
191 1
	}
192 1
193 1
	/**
194 1
	 * @return float[]
195
	 */
196
	private function calculateFromPrice(): array
197 1
	{
198 1
		$price = $this->round($this->price);
199
		$basePrice = $this->discount ? $this->round($this->discount->removeDiscount($price)) : $price;
200
		$priceVat = $this->round($price * ($this->vatRate / 100 + 1));
201
202
		return [$basePrice, $price, $priceVat];
203
	}
204
205
	/**
206
	 * @return float[]
207 1
	 */
208 1
	private function calculateFromPriceVat(): array
209 1
	{
210
		$priceVat = $this->round($this->priceVat);
211 1
		$price = $this->round($priceVat / ($this->vatRate / 100 + 1));
212
		$basePrice = $this->discount ? $this->round($this->discount->removeDiscount($price)) : $price;
213
214
		return [$basePrice, $price, $priceVat];
215
	}
216
217
	private function round(float $price): float
218
	{
219 1
		return round($price, $this->decimalPoints);
220 1
	}
221
}
222