Passed
Push — master ( e39bb0...54e3cc )
by Dmitry
14:48
created

ProgressivePriceThresholds   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 43
c 1
b 0
f 0
dl 0
loc 107
rs 10
wmc 17

10 Methods

Rating   Name   Duplication   Size   Complexity  
A get() 0 4 1
A add() 0 5 1
A prepareThresholds() 0 7 2
A __construct() 0 14 2
A checkUnit() 0 13 3
A appendThresholds() 0 3 1
A checkCurrency() 0 14 3
A getPriceRate() 0 3 1
A jsonSerialize() 0 4 1
A __toArray() 0 7 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace hiqdev\php\billing\price;
6
7
use JsonSerializable;
8
use hiqdev\php\units\Quantity;
9
use InvalidArgumentException;
10
use Money\Money;
11
12
final class ProgressivePriceThresholds implements JsonSerializable
13
{
14
    /** @var ProgressivePriceThreshold[] */
15
    private array $thresholds;
16
17
    private int $priceRate = 0;
18
19
    /**
20
     * @param ProgressivePriceThreshold[] $thresholds
21
     */
22
   public function __construct(
23
       array $thresholds
24
   )
25
   {
26
       foreach ($thresholds as $threshold) {
27
           $this->add(ProgressivePriceThreshold::createFromScalar(
28
                    (string) $threshold['price'],
29
                    (string) $threshold['currency'],
30
                    (string) $threshold['quantity'],
31
                    (string) $threshold['unit'],
32
               )
33
           );
34
       }
35
       $this->priceRate = MoneyBuilder::calculatePriceMultiplier((string)$threshold['price']);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $threshold seems to be defined by a foreach iteration on line 26. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
36
   }
37
38
   public function add(ProgressivePriceThreshold $threshold): void
39
   {
40
      $this->checkCurrency($threshold->price());
41
      $this->checkUnit($threshold->quantity());
42
      $this->appendThresholds($threshold);
43
   }
44
45
    public function get(): array
46
    {
47
        $this->prepareThresholds();
48
        return $this->thresholds;
49
    }
50
51
    public function getPriceRate(): int
52
    {
53
        return $this->priceRate;
54
    }
55
56
    private function prepareThresholds(): void
57
    {
58
        usort($this->thresholds, function (ProgressivePriceThreshold $a, ProgressivePriceThreshold $b) {
59
            if ($b->quantity()->equals($a->quantity())) {
60
                return $b->price()->getAmount() <=> $a->price()->getAmount();
61
            }
62
            return $b->quantity()->getQuantity() <=> $a->quantity()->getQuantity();
63
        });
64
    }
65
66
    private function checkCurrency(Money $price): void
67
    {
68
        if (empty($this->thresholds)) {
69
            return;
70
        }
71
72
        $last = $this->thresholds[array_key_last($this->thresholds)];
73
74
        if (!$last->price()->getCurrency()->equals($price->getCurrency())
75
        ) {
76
            throw new InvalidArgumentException(sprintf(
77
                "Progressive price with threshold currency %s is not valid to other threshold currency %s",
78
                $last->price()->getCurrency()->getCode(),
79
                $price->getCurrency()->getCode()
80
            ));
81
        }
82
    }
83
84
    private function checkUnit(Quantity $prepaid): void
85
    {
86
        if (empty($this->thresholds)) {
87
            return;
88
        }
89
90
        $last = $this->thresholds[array_key_last($this->thresholds)];
91
92
        if (!$last->quantity()->getUnit()->isConvertible($prepaid->getUnit())) {
93
            throw new InvalidArgumentException(sprintf(
94
                "Progressive price with threshold unit %s is not convertible to other threshold unit %s",
95
                $last->quantity()->getUnit()->getName(),
96
                $prepaid->getUnit()->getName()
97
            ));
98
        }
99
    }
100
101
    private function appendThresholds(ProgressivePriceThreshold $threshold): void
102
    {
103
        $this->thresholds[] = $threshold;
104
    }
105
106
    public function __toArray(): array
107
    {
108
        $result = [];
109
        foreach ($this->thresholds as $threshold) {
110
            $result[] = $threshold->__toArray();
111
        }
112
        return $result;
113
    }
114
115
    #[\ReturnTypeWillChange]
116
    public function jsonSerialize()
117
    {
118
        return $this->thresholds;
119
    }
120
}
121