Passed
Pull Request — master (#99)
by
unknown
02:46
created

ProgressivePriceTest::testProgressivePriceSerialization()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 44
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 30
c 0
b 0
f 0
dl 0
loc 44
rs 9.44
cc 2
nc 2
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace hiqdev\php\billing\tests\unit\price;
6
7
use Generator;
8
use hiqdev\php\billing\price\ProgressivePrice;
9
use hiqdev\php\billing\price\ProgressivePriceThresholdList;
10
use hiqdev\php\billing\target\Target;
11
use hiqdev\php\billing\type\Type;
12
use hiqdev\php\units\Quantity;
13
use Money\Currencies\ISOCurrencies;
14
use Money\Currency;
15
use Money\Parser\DecimalMoneyParser;
16
use PHPUnit\Framework\TestCase;
17
18
19
class ProgressivePriceTest extends TestCase
20
{
21
    private Quantity $usage;
22
    private DecimalMoneyParser $moneyParser;
23
24
    protected function setUp(): void
25
    {
26
        parent::setUp();
27
28
        $this->usage = Quantity::mbps(720);
29
        $this->moneyParser = new DecimalMoneyParser(new ISOCurrencies());
30
    }
31
32
    private function createProgressivePrice(string $prepaid, string $startPrice, array $thresholdsArray): ProgressivePrice
33
    {
34
        $type = new Type('2222', 'cdn_traf95_max');
35
        $target = new Target('2222', 'overuse,cdn_traf95_max', 'ProgressivePrice');
36
        $prepaid = Quantity::mbps($prepaid);
37
        $money = $this->moneyParser->parse($startPrice, new Currency('EUR'));
38
        $thresholds = ProgressivePriceThresholdList::fromScalarsArray($thresholdsArray);
39
40
        return new ProgressivePrice('2222', $type, $target, $prepaid, $money, $thresholds);
41
    }
42
43
    /** @dataProvider progressivePriceProvider */
44
    public function testUsageIsConvertedToThresholdUnits(
45
        array $thresholdsArray,
46
        int $expectedAmount,
47
        string $startPrice,
48
        string $prepaid = '0',
49
        array $expectedTrace = [],
50
    ): void {
51
        $this->usage = Quantity::gbps(0.72);
52
        $price = $this->createProgressivePrice(
53
            prepaid: $prepaid,
54
            startPrice: $startPrice,
55
            thresholdsArray: $thresholdsArray
56
        );
57
58
        $amount = $price->calculateSum($this->usage);
59
        $this->assertEquals($expectedAmount, $amount->getAmount());
60
        $trace = array_map(fn($trace) => $trace->__toString(), $price->getCalculationTraces());
61
        $this->assertSame($expectedTrace, $trace);
62
    }
63
64
    /** @dataProvider progressivePriceProvider */
65
    public function testProgressivePriceCalculation(
66
        array $thresholdsArray,
67
        int $expectedAmount,
68
        string $startPrice,
69
        string $prepaid = '0',
70
        array $expectedTrace = [],
71
    ): void {
72
        $price = $this->createProgressivePrice(
73
            prepaid: $prepaid,
74
            startPrice: $startPrice,
75
            thresholdsArray: $thresholdsArray
76
        );
77
78
        $usage = $price->calculateUsage($this->usage);
79
        $this->assertSame($this->usage->getQuantity(), $usage->getQuantity());
80
81
        $amount = $price->calculateSum($this->usage);
82
        $this->assertEquals($expectedAmount, $amount->getAmount());
83
84
        $trace = array_map(fn($trace) => $trace->__toString(), $price->getCalculationTraces());
85
        $this->assertSame($expectedTrace, $trace);
86
    }
87
88
    /**
89
     * @dataProvider progressivePriceProvider
90
     */
91
    public function testProgressivePriceSerialization(
92
        array $inputThresholdsArray,
93
        int $expectedAmount,
94
        string $startPrice,
95
        string $prepaid = '0'
96
    ): void {
97
        $price = $this->createProgressivePrice(
98
            prepaid: $prepaid,
99
            startPrice: $startPrice,
100
            thresholdsArray: $inputThresholdsArray
101
        );
102
103
        $unserialized = json_decode(json_encode($price), true);
104
        $this->assertArrayHasKey('id', $unserialized);
105
        $this->assertArrayHasKey('type', $unserialized);
106
        $this->assertArrayHasKey('target', $unserialized);
107
        $this->assertArrayHasKey('thresholds', $unserialized);
108
        $this->assertArrayHasKey('price', $unserialized);
109
        $this->assertArrayHasKey('prepaid', $unserialized);
110
111
        $this->assertSame($price->getId(), $unserialized['id']);
112
113
        $this->assertSame($price->getType()->getId(), $unserialized['type']['id']);
114
        $this->assertSame($price->getType()->getName(), $unserialized['type']['name']);
115
116
        $this->assertSame($price->getTarget()->getId(), $unserialized['target']['id']);
117
        $this->assertSame($price->getTarget()->getType(), $unserialized['target']['type']);
118
        $this->assertSame($price->getTarget()->getName(), $unserialized['target']['name']);
119
120
        $this->assertSame($price->getPrice()->getAmount(), $unserialized['price']['amount']);
121
        $this->assertSame($price->getPrice()->getCurrency()->getCode(), $unserialized['price']['currency']);
122
123
        $this->assertSame($price->getPrepaid()->getQuantity(), $unserialized['prepaid']['quantity']);
124
        $this->assertSame($price->getPrepaid()->getUnit()->getName(), $unserialized['prepaid']['unit']);
125
126
        $thresholdsArray = $price->getThresholds()->get();
127
        $unserializedThresholds = array_reverse($unserialized['thresholds']);
128
        $this->assertCount(count($inputThresholdsArray), $unserializedThresholds);
129
        foreach ($thresholdsArray as $index => $threshold) {
130
            $val = (new \ReflectionObject($threshold))->getProperty('price')->getValue($threshold);
131
            $this->assertSame($val, $unserializedThresholds[$index]['price']);
132
            $this->assertSame($threshold->price()->getCurrency()->getCode(), $unserializedThresholds[$index]['currency']);
133
            $this->assertSame($threshold->quantity()->getQuantity(), $unserializedThresholds[$index]['quantity']);
134
            $this->assertSame($threshold->quantity()->getUnit()->getName(), $unserializedThresholds[$index]['unit']);
135
        }
136
    }
137
138
    private function progressivePriceProvider(): Generator
139
    {
140
        yield 'Simple case' => [
141
            'thresholds' => [
142
                ['price' => '0.0085', 'currency' => 'EUR', 'quantity' => '0', 'unit' => 'mbps'],
143
                ['price' => '0.0080', 'currency' => 'EUR', 'quantity' => '500', 'unit' => 'mbps'],
144
                ['price' => '0.0075', 'currency' => 'EUR', 'quantity' => '600', 'unit' => 'mbps'],
145
                ['price' => '0.0070', 'currency' => 'EUR', 'quantity' => '700', 'unit' => 'mbps'],
146
                ['price' => '0.0065', 'currency' => 'EUR', 'quantity' => '800', 'unit' => 'mbps'],
147
            ],
148
            'money' => 594,
149
            'price' => '0.0085',
150
            'prepaid' => '0',
151
            'trace' => [
152
                '0mbps * 0.0065 = 0.00',
153
                '20mbps * 0.0070 = 0.14',
154
                '100mbps * 0.0075 = 0.75',
155
                '100mbps * 0.0080 = 0.80',
156
                '500mbps * 0.0085 = 4.25',
157
                '0mbps * 0.01 = 0.00',
158
            ],
159
        ];
160
161
        yield 'Different prices for the same quantity – take higher price' => [
162
            'thresholds' => [
163
                ['price' => '6', 'currency' => 'EUR', 'quantity' => '0', 'unit' => 'mbps'],
164
                ['price' => '4', 'currency' => 'EUR', 'quantity' => '100', 'unit' => 'mbps'], // Here the qty is the same
165
                ['price' => '5000', 'currency' => 'EUR', 'quantity' => '0.1', 'unit' => 'gbps'], // as here, despite units are different
166
                ['price' => '3', 'currency' => 'EUR', 'quantity' => '200', 'unit' => 'mbps'],
167
            ],
168
            'money' => 266000,
169
            'price' => '6',
170
            'prepaid' => '0',
171
            'trace' => [
172
                '520mbps * 3 = 1,560.00',
173
                '0.1gbps * 5000 = 500.00',
174
                '0mbps * 4 = 0.00',
175
                '100mbps * 6 = 600.00',
176
                '0mbps * 6 = 0.00',
177
            ],
178
        ];
179
180
        yield 'Bill without prepaid amount' => [
181
            'thresholds' => [
182
                ['price' => '6', 'currency' => 'EUR', 'quantity' => '100', 'unit' => 'mbps'],
183
                ['price' => '5', 'currency' => 'EUR', 'quantity' => '200', 'unit' => 'mbps'],
184
                ['price' => '4', 'currency' => 'EUR', 'quantity' => '300', 'unit' => 'mbps'],
185
                ['price' => '3', 'currency' => 'EUR', 'quantity' => '400', 'unit' => 'mbps'],
186
            ],
187
            'money' => 306000,
188
            'price' => '6',
189
            'prepaid' => '0',
190
            'trace' => [
191
                '320mbps * 3 = 960.00',
192
                '100mbps * 4 = 400.00',
193
                '100mbps * 5 = 500.00',
194
                '100mbps * 6 = 600.00',
195
                '100mbps * 6 = 600.00',
196
            ],
197
        ];
198
199
        yield 'Bill with prepaid amount' => [
200
            'thresholds' => [
201
                ['price' => '1', 'currency' => 'EUR', 'quantity' => '20', 'unit' => 'mbps'],
202
                ['price' => '0.9', 'currency' => 'EUR', 'quantity' => '30', 'unit' => 'mbps'],
203
                ['price' => '856.00', 'currency' => 'EUR', 'quantity' => '0.1', 'unit' => 'gbps'],
204
                ['price' => '0.5521', 'currency' => 'EUR', 'quantity' => '130.5', 'unit' => 'mbps'],
205
            ],
206
            'result' => 43487,
207
            'price' => '1.03',
208
            'prepaid' => '10',
209
            'trace' => [
210
                '589.5mbps * 0.5521 = 325.46',
211
                '0.0305gbps * 856.00 = 26.11',
212
                '70mbps * 0.9 = 63.00',
213
                '10mbps * 1 = 10.00',
214
                '10mbps * 1.03 = 10.30',
215
            ],
216
        ];
217
    }
218
219
    /**
220
     * @dataProvider progressivePriceProviderSmallUsage
221
     */
222
    public function testProgressivePriceSmallUsage(
223
        array $inputThresholdsArray,
224
        int $expectedAmount,
225
        string $startPrice,
226
        string $prepaid = '0'
227
    ): void {
228
        $price = $this->createProgressivePrice(
229
            prepaid: $prepaid,
230
            startPrice: $startPrice,
231
            thresholdsArray: $inputThresholdsArray
232
        );
233
        $this->usage = Quantity::bps(6043);
234
        $usage = $price->calculateUsage($this->usage);
235
        $this->assertSame($this->usage->getQuantity(), $usage->getQuantity());
236
237
        $amount = $price->calculateSum($this->usage);
238
        $this->assertEquals($expectedAmount, $amount->getAmount());
239
    }
240
241
    private function progressivePriceProviderSmallUsage(): Generator
242
    {
243
        yield 'Simple case' => [
244
            'thresholds' => [
245
                ['price' => '10', 'currency' => 'EUR', 'quantity' => '0', 'unit' => 'gbps'],
246
            ],
247
            'money' => 0,
248
            'price' => '1',
249
            'prepaid' => '0',
250
            'trace' => [
251
                '6043bps * 0.00000001 = 0.00',
252
            ],
253
        ];
254
    }
255
}
256