Passed
Pull Request — master (#75)
by
unknown
13:40
created

ProgressivePrice::getPrice()   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 0
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace hiqdev\php\billing\price;
6
7
use hiqdev\php\billing\plan\PlanInterface;
8
use hiqdev\php\billing\target\TargetInterface;
9
use hiqdev\php\billing\type\TypeInterface;
10
use hiqdev\php\units\Quantity;
11
use hiqdev\php\units\QuantityInterface;
12
use Money\Currencies\ISOCurrencies;
13
use Money\Currency;
14
use Money\Money;
15
use Money\Parser\DecimalMoneyParser;
16
17
class ProgressivePrice extends AbstractPrice implements PriceWithThresholdsInterface,
18
    PriceWithMoneyInterface,
19
    PriceWithQuantityInterface,
20
    PriceWithCurrencyInterface
21
{
22
    use HasMoney;
23
24
    protected ProgressivePriceThresholdList $thresholds;
25
26
    protected QuantityInterface $prepaid;
27
28
    public function __construct(
29
        $id,
30
        TypeInterface $type,
31
        TargetInterface $target,
32
        QuantityInterface $prepaid,
33
        Money $price,
34
        ProgressivePriceThresholdList $thresholds,
35
        ?PlanInterface $plan = null
36
    )
37
    {
38
        parent::__construct($id, $type, $target, $plan);
39
        $this->thresholds = $thresholds;
40
        $this->price = $price;
41
        $this->prepaid = $prepaid;
42
    }
43
44
    public function getThresholds(): ProgressivePriceThresholdList
45
    {
46
        return $this->thresholds;
47
    }
48
49
    public function getPrepaid(): QuantityInterface
50
    {
51
        return $this->prepaid;
52
    }
53
54
    /**
55
     * @inheritDoc
56
     */
57
    public function calculateUsage(QuantityInterface $quantity): ?QuantityInterface
58
    {
59
        $usage = $quantity->subtract($this->prepaid);
60
61
        if ($usage->isPositive()) {
62
            return $quantity;
63
        }
64
65
        return Quantity::create($this->prepaid->getUnit()->getName(), 0);
66
    }
67
68
    /**
69
     * @inheritDoc
70
     */
71
    public function calculatePrice(QuantityInterface $quantity): ?Money
72
    {
73
        return $this->price;
74
    }
75
76
    /**
77
     * @var ProgressivePriceCalculationTrace[]
78
     */
79
    private array $calculationTraces = [];
80
81
    /**
82
     * @return ProgressivePriceCalculationTrace[]
83
     * @internal A debug method to see intermediate calculations
84
     * after the latest call to calculateSum()
85
     */
86
    public function getCalculationTraces(): array
87
    {
88
        return $this->calculationTraces;
89
    }
90
91
    public function calculateSum(QuantityInterface $quantity): ?Money
92
    {
93
        $this->calculationTraces = [];
94
95
        $result = $this->price->multiply(0);
96
        $remainingUsage = $this->calculateUsage($quantity);
97
        if ($remainingUsage->getQuantity() === 0) {
98
            return $result;
99
        }
100
101
        $totalBilledUsage = $this->prepaid;
102
        $thresholds = $this->thresholds->withAdded(
103
            ProgressivePriceThreshold::createFromObjects($this->price, $this->prepaid)
104
        )->get();
105
106
        foreach ($thresholds as $threshold) {
107
            $quantity = $threshold->quantity();
108
            if ($quantity->compare($remainingUsage) >= 0) {
109
                $quantity = $remainingUsage;
110
            }
111
            $billedUsage = $remainingUsage->subtract($quantity)->convert($threshold->unit());
112
            $price = $threshold->price();
113
114
            $chargedAmount = $price->money()
115
                                   ->multiply((string)$billedUsage->getQuantity())
116
                                   ->divide((string)($price->multiplier()));
117
118
            $this->calculationTraces[] = new ProgressivePriceCalculationTrace(
119
                $threshold, $billedUsage, $chargedAmount
120
            );
121
122
            $result = $result->add($chargedAmount);
123
            $remainingUsage = $remainingUsage->subtract($billedUsage);
124
            $totalBilledUsage = $totalBilledUsage->add($billedUsage);
125
        }
126
127
        return $result;
128
    }
129
}
130