Passed
Push — master ( ae6cde...76a869 )
by Andrii
17:57
created

BillingContext::prepareSum()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace hiqdev\php\billing\tests\behat\bootstrap;
4
5
use DateTimeImmutable;
6
use hiqdev\php\billing\bill\BillInterface;
7
use hiqdev\php\billing\charge\ChargeInterface;
8
use PHPUnit\Framework\Assert;
9
10
class BillingContext extends BaseContext
11
{
12
    protected $saleTime;
13
14
    protected $bill;
15
16
    protected array $charges = [];
17
18
    /**
19
     * @Given reseller :reseller
20
     */
21
    public function reseller($reseller)
22
    {
23
        $this->builder->buildReseller($reseller);
24
    }
25
26
    /**
27
     * @Given customer :customer
28
     */
29
    public function customer($customer)
30
    {
31
        $this->builder->buildCustomer($customer);
32
    }
33
34
    /**
35
     * @Given manager :manager
36
     */
37
    public function manager($manager)
38
    {
39
        $this->builder->buildManager($manager);
40
    }
41
42
    /**
43
     * @Given /^(grouping )?(\S+) tariff plan (\S+)/
44
     */
45
    public function plan($grouping, $type, $plan)
46
    {
47
        $this->builder->buildPlan($plan, $type, !empty($grouping));
48
    }
49
50
    protected function fullPrice(array $data)
51
    {
52
        $this->builder->buildPrice($data);
53
    }
54
55
    /**
56
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+) for target (\S+)/
57
     */
58
    public function priceWithObject($type, $price, $currency, $unit, $target)
59
    {
60
        return $this->fullPrice(compact('type', 'price', 'currency', 'unit', 'target'));
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->fullPrice(compact...cy', 'unit', 'target')) targeting hiqdev\php\billing\tests...ingContext::fullPrice() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
61
    }
62
63
    /**
64
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+) prepaid (\S+)/
65
     */
66
    public function priceWithPrepaid($type, $price, $currency, $unit, $prepaid)
67
    {
68
        $prepaid = "$prepaid $unit";
69
        return $this->fullPrice(compact('type', 'price', 'currency', 'unit', 'prepaid'));
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->fullPrice(compact...y', 'unit', 'prepaid')) targeting hiqdev\php\billing\tests...ingContext::fullPrice() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
70
    }
71
72
    /**
73
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+)$/
74
     */
75
    public function price($type, $price, $currency, $unit)
76
    {
77
        return $this->fullPrice(compact('type', 'price', 'currency', 'unit'));
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->fullPrice(compact...', 'currency', 'unit')) targeting hiqdev\php\billing\tests...ingContext::fullPrice() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
78
    }
79
80
    /**
81
     * @Given /price for (\S+) is +(\S+) (\S+) per 1 (\S+) and (\S+) (\S+) per 2 (\S+) for target (\S+)/
82
     */
83
    public function enumPrice($type, $price, $currency, $unit, $price2, $currency2, $unit2, $target)
0 ignored issues
show
Unused Code introduced by
The parameter $unit2 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

83
    public function enumPrice($type, $price, $currency, $unit, $price2, $currency2, /** @scrutinizer ignore-unused */ $unit2, $target)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $currency2 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

83
    public function enumPrice($type, $price, $currency, $unit, $price2, /** @scrutinizer ignore-unused */ $currency2, $unit2, $target)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
84
    {
85
        $sums = [1 => $price, 2 => $price2];
86
        return $this->fullPrice(compact('type', 'sums', 'currency', 'unit', 'target'));
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->fullPrice(compact...cy', 'unit', 'target')) targeting hiqdev\php\billing\tests...ingContext::fullPrice() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
87
    }
88
89
    /**
90
     * @Given /^remove and recreate tariff plan (\S+)/
91
     */
92
    public function recreatePlan($plan)
93
    {
94
        $this->builder->recreatePlan($plan);
95
    }
96
97
    /**
98
     * @Given /sale (\S+) for (\S+) plan:(\S+) time:(\S+)/
99
     */
100
    public function sale($id, $target, $plan, $time): void
101
    {
102
        $this->saleTime = $this->prepareTime($time);
103
        $this->builder->buildSale($id, $target, $plan, $this->saleTime);
104
    }
105
106
107
    /**
108
     * @Given /purchase target (\S+) by plan (\S+) at (.+)$/
109
     */
110
    public function purchaseTarget(string $target, string $plan, string $time): void
111
    {
112
        $time = $this->prepareTime($time);
113
        $this->builder->buildPurchase($target, $plan, $time);
114
    }
115
116
    /**
117
     * @Given /resource consumption for (\S+) is (\d+) (\S+) for target (\S+) at (.+)$/
118
     */
119
    public function setConsumption(string $type, int $amount, string $unit, string $target, string $time): void
120
    {
121
        $this->builder->setConsumption($type, $amount, $unit, $target, $time);
122
    }
123
124
    /**
125
     * @Given /perform billing for time (\S+) for sales/
126
     */
127
    public function performBilling(string $time): void
128
    {
129
        $this->builder->performBilling($time);
130
    }
131
132
    /**
133
     * @Given /bill +for (\S+) is +(\S+) (\S+) per (\S+) (\S+) for target (\S+)$/
134
     */
135
    public function bill($type, $sum, $currency, $quantity, $unit, $target)
136
    {
137
        $quantity = $this->prepareQuantity($quantity);
138
        $sum = $this->prepareSum($sum, $quantity);
139
        $bill = $this->findBill([
140
            'type' => $type,
141
            'target' => $target,
142
            'sum' => "$sum $currency",
143
            'quantity' => "$quantity $unit",
144
        ]);
145
        Assert::assertSame($type, $bill->getType()->getName());
146
        Assert::assertSame($target, $bill->getTarget()->getFullName());
147
        Assert::assertEquals($sum*100, $bill->getSum()->getAmount());
148
        Assert::assertSame($currency, $bill->getSum()->getCurrency()->getCode());
149
        Assert::assertEquals($quantity, $bill->getQuantity()->getQuantity());
150
        Assert::assertSame($unit, $bill->getQuantity()->getUnit()->getName());
151
    }
152
153
    public function findBill(array $params): BillInterface
154
    {
155
        $bills = $this->builder->findBills($params);
156
        $this->bill = reset($bills);
157
        $this->charges = $this->bill->getCharges();
158
159
        return $this->bill;
160
    }
161
162
    /**
163
     * @Given /bills number is (\d+) for (\S+) for target (\S+)/
164
     */
165
    public function billsNumber($number, $type, $target)
166
    {
167
        $count = count($this->builder->findBills([
168
            'type' => $type,
169
            'target' => $target,
170
        ]));
171
172
        Assert::assertEquals($number, $count);
173
    }
174
175
    /**
176
     * @Given /charge for (\S+) is +(\S+) (\S+) per (\S+) (\S+) for target (\S+)$/
177
     */
178
    public function chargeWithTarget($type, $amount, $currency, $quantity, $unit, $target)
179
    {
180
        $quantity = $this->prepareQuantity($quantity);
181
        $amount = $this->prepareSum($amount, $quantity);
182
        $charge = $this->findCharge($type, $target);
183
        Assert::assertNotNull($charge);
184
        Assert::assertSame($type, $charge->getType()->getName());
185
        Assert::assertSame($target, $charge->getTarget()->getFullName());
186
        Assert::assertEquals($amount*100, $charge->getSum()->getAmount());
187
        Assert::assertSame($currency, $charge->getSum()->getCurrency()->getCode());
188
        Assert::assertEquals($quantity, $charge->getUsage()->getQuantity());
189
        Assert::assertSame($unit, $charge->getUsage()->getUnit()->getName());
190
    }
191
192
    /**
193
     * @Given /charge for (\S+) is +(\S+) (\S+) per (\S+) (\S+)$/
194
     */
195
    public function charge($type, $amount, $currency, $quantity, $unit)
196
    {
197
        $this->chargeWithTarget($type, $amount, $currency, $quantity, $unit, null);
198
    }
199
200
    public function findCharge($type, $target): ?ChargeInterface
201
    {
202
        foreach ($this->charges as $charge) {
203
            if ($charge->getType()->getName() !== $type) {
204
                continue;
205
            }
206
            if ($charge->getTarget()->getFullName() !== $target) {
207
                continue;
208
            }
209
            return $charge;
210
        }
211
212
        return null;
213
    }
214
215
    public function getNextCharge(): ChargeInterface
216
    {
217
        $charge = current($this->charges);
218
        next($this->charges);
219
220
        return $charge;
221
    }
222
223
    private function prepareTime($time)
224
    {
225
        if ($time === 'midnight second day of this month') {
226
            return date("Y-m-02");
227
        }
228
        if ($time[0] === 'Y') {
229
            return date($time);
230
        }
231
232
        return $time;
233
    }
234
235
    private function prepareQuantity($quantity)
236
    {
237
        if ($quantity[0] === 's') {
238
            return $this->getSaleQuantity();
239
        }
240
        return $quantity;
241
    }
242
243
    private function prepareSum($sum, $quantity)
244
    {
245
        if ($sum[0] === 's') {
246
            $sum = round(substr($sum, 1) * $quantity*100)/100;
247
        }
248
249
        return $sum;
250
    }
251
252
    public function getSaleQuantity()
253
    {
254
        return $this->days2quantity(new DateTimeImmutable($this->saleTime));
255
    }
256
257
    private function days2quantity(DateTimeImmutable $from)
258
    {
259
        $till = new DateTimeImmutable('first day of next month midnight');
260
        $diff = $from->diff($till);
261
        if ($diff->m) {
262
            return 1;
263
        }
264
265
        return $diff->d/date('t');
266
    }
267
}
268