Completed
Push — master ( e2e89f...b62e3a )
by Andrii
28:32 queued 13:29
created

BillingContext::priceWithPrepaidAndTarget()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 6
dl 0
loc 4
rs 10
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 hiqdev\php\units\Unit;
9
use PHPUnit\Framework\Assert;
10
11
class BillingContext extends BaseContext
12
{
13
    protected $saleTime;
14
15
    protected $bill;
16
17
    protected array $charges = [];
18
19
    /**
20
     * @Given reseller :reseller
21
     */
22
    public function reseller($reseller)
23
    {
24
        $this->builder->buildReseller($reseller);
25
    }
26
27
    /**
28
     * @Given customer :customer
29
     */
30
    public function customer($customer)
31
    {
32
        $this->builder->buildCustomer($customer);
33
    }
34
35
    /**
36
     * @Given manager :manager
37
     */
38
    public function manager($manager)
39
    {
40
        $this->builder->buildManager($manager);
41
    }
42
43
    /**
44
     * @Given /^(grouping )?(\S+) tariff plan (\S+)/
45
     */
46
    public function plan($grouping, $type, $plan)
47
    {
48
        $this->builder->buildPlan($plan, $type, !empty($grouping));
49
    }
50
51
    protected function fullPrice(array $data)
52
    {
53
        $this->builder->buildPrice($data);
54
    }
55
56
    /**
57
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+) for target (\S+)/
58
     */
59
    public function priceWithTarget($type, $price, $currency, $unit, $target)
60
    {
61
        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...
62
    }
63
64
    /**
65
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+) prepaid (\S+)$/
66
     */
67
    public function priceWithPrepaid($type, $price, $currency, $unit, $prepaid)
68
    {
69
        $prepaid = "$prepaid $unit";
70
        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...
71
    }
72
73
    /**
74
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+) prepaid (\S+) for target (\S+)$/
75
     */
76
    public function priceWithPrepaidAndTarget($type, $price, $currency, $unit, $prepaid, $target)
77
    {
78
        $prepaid = "$prepaid $unit";
79
        return $this->fullPrice(compact('type', 'price', 'currency', 'unit', 'prepaid', 'target'));
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->fullPrice(compact..., 'prepaid', '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...
80
    }
81
82
    /**
83
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+)$/
84
     */
85
    public function price($type, $price, $currency, $unit)
86
    {
87
        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...
88
    }
89
90
    /**
91
     * @Given /price for (\S+) is +(\S+) (\S+) per 1 (\S+) and (\S+) (\S+) per 2 (\S+) for target (\S+)/
92
     */
93
    public function enumPrice($type, $price, $currency, $unit, $price2, $currency2, $unit2, $target)
0 ignored issues
show
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

93
    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...
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

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