Completed
Pull Request — master (#15)
by Klochok
10:32
created

BillingContext::enumPrice()   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 8
dl 0
loc 4
rs 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 priceWithObject($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+)$/
75
     */
76
    public function price($type, $price, $currency, $unit)
77
    {
78
        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...
79
    }
80
81
    /**
82
     * @Given /price for (\S+) is +(\S+) (\S+) per 1 (\S+) and (\S+) (\S+) per 2 (\S+) for target (\S+)/
83
     */
84
    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

84
    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

84
    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...
85
    {
86
        $sums = [1 => $price, 2 => $price2];
87
        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...
88
    }
89
90
    /**
91
     * @Given /^remove and recreate tariff plan (\S+)/
92
     */
93
    public function recreatePlan($plan)
94
    {
95
        $this->builder->recreatePlan($plan);
96
    }
97
98
    /**
99
     * @Given /sale (\S+) for (\S+) plan:(\S+) time:(\S+)/
100
     */
101
    public function sale($id, $target, $plan, $time): void
102
    {
103
        $this->saleTime = $this->prepareTime($time);
104
        $this->builder->buildSale($id, $target, $plan, $this->saleTime);
105
    }
106
107
    /**
108
     * @Given /sale server (\S+) plan (\S+) at (\S+)/
109
     */
110
    public function saleServer(string $server, string $plan, string $time): void
111
    {
112
        $time = $this->prepareTime($time);
113
        $this->builder->buildServerSale($server, $plan, $time);
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
    private function prepareTime(string $time)
238
    {
239
        if ($time === 'midnight second day of this month') {
240
            return date("Y-m-02");
241
        }
242
        if (strpos($time, 'Y') === 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