Passed
Push — master ( e39bb0...54e3cc )
by Dmitry
14:48
created

BillingContext::chargeWithTarget()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 1 Features 0
Metric Value
cc 1
eloc 10
c 5
b 1
f 0
nc 1
nop 8
dl 0
loc 12
rs 9.9332

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
 * PHP Billing Library
4
 *
5
 * @link      https://github.com/hiqdev/php-billing
6
 * @package   php-billing
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2017-2020, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\php\billing\tests\behat\bootstrap;
12
13
use Behat\Gherkin\Node\TableNode;
14
use BehatExpectException\ExpectException;
15
use DateTimeImmutable;
16
use hiqdev\php\billing\bill\BillInterface;
17
use hiqdev\php\billing\charge\ChargeInterface;
18
use PHPUnit\Framework\Assert;
19
20
class BillingContext extends BaseContext
21
{
22
    use ExpectException {
23
        mayFail as protected;
24
        shouldFail as protected;
25
        assertCaughtExceptionMatches as protected;
26
    }
27
28
    protected $saleTime;
29
30
    protected $bill;
31
32
    protected $charges = [];
33
34
    protected array $progressivePrice = [];
35
36
    /**
37
     * @Given reseller :reseller
38
     */
39
    public function reseller($reseller)
40
    {
41
        $this->builder->buildReseller($reseller);
42
    }
43
44
    /**
45
     * @Given customer :customer
46
     */
47
    public function customer($customer)
48
    {
49
        $this->builder->buildCustomer($customer);
50
    }
51
52
    /**
53
     * @Given manager :manager
54
     */
55
    public function manager($manager)
56
    {
57
        $this->builder->buildManager($manager);
0 ignored issues
show
Bug introduced by
The method buildManager() does not exist on hiqdev\php\billing\tests...tstrap\BuilderInterface. ( Ignorable by Annotation )

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

57
        $this->builder->/** @scrutinizer ignore-call */ 
58
                        buildManager($manager);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
58
    }
59
60
    /**
61
     * @Given /^(\S+ )?(\S+) tariff plan (\S+)/
62
     */
63
    public function plan($prefix, $type, $plan)
64
    {
65
        $prefix = strtr($prefix, ' ', '_');
66
        $grouping = $prefix === 'grouping_';
67
        $type = $grouping ? $type : $prefix.$type;
68
        $this->builder->buildPlan($plan, $type, $grouping);
69
    }
70
71
    protected function fullPrice(array $data)
72
    {
73
        if (!empty($data['price'])) {
74
            $data['rate'] = $data['price'];
75
        }
76
        $this->builder->buildPrice($data);
77
    }
78
79
    /**
80
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+) for target (.+)$/
81
     */
82
    public function priceWithTarget($type, $price, $currency, $unit, $target)
83
    {
84
        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...
85
    }
86
87
    /**
88
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+) prepaid (\S+)$/
89
     */
90
    public function priceWithPrepaid($type, $price, $currency, $unit, $prepaid)
91
    {
92
        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...
93
    }
94
95
    /**
96
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+) prepaid (\S+) for target (\S+)$/
97
     */
98
    public function priceWithPrepaidAndTarget($type, $price, $currency, $unit, $prepaid, $target)
99
    {
100
        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...
101
    }
102
103
    /**
104
     * @Given /price for (\S+) is +(\S+) (\S+) per (\S+)$/
105
     */
106
    public function price($type, $price, $currency, $unit)
107
    {
108
        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...
109
    }
110
111
    /**
112
     * @Given /price for (\S+) is +(\S+) (\S+) per 1 (\S+) and (\S+) (\S+) per 2 (\S+) for target (\S+)/
113
     */
114
    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

114
    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

114
    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...
115
    {
116
        $sums = [1 => $price, 2 => $price2];
117
118
        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...
119
    }
120
121
    /**
122
     * @Given /progressive price for (\S+) is +(\S+) (\S+) per (\S+) (\S+) (\S+) (\S+)$/
123
     */
124
    public function progressivePrice($type, $price, $currency, $unit, $sign, $quantity, $perUnit): void
0 ignored issues
show
Unused Code introduced by
The parameter $perUnit 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

124
    public function progressivePrice($type, $price, $currency, $unit, $sign, $quantity, /** @scrutinizer ignore-unused */ $perUnit): void

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 $sign 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

124
    public function progressivePrice($type, $price, $currency, $unit, /** @scrutinizer ignore-unused */ $sign, $quantity, $perUnit): void

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...
125
    {
126
        if (empty($this->progressivePrice[$type])) {
127
            $this->progressivePrice[$type] = [
128
                'price' => 0,
129
                'currency' => $currency,
130
                'unit' => $unit,
131
                'thresholds' =>[
132
                    [
133
                        'price' => $price,
134
                        'currency' => $currency,
135
                        'quantity' => $quantity,
136
                        'unit' => $unit,
137
                    ],
138
                ] ,
139
            ];
140
        } else {
141
            array_push(
142
                $this->progressivePrice[$type]['thresholds'],
143
                [
144
                    'price' => $price,
145
                    'currency' => $currency,
146
                    'quantity' => $quantity,
147
                    'unit' => $unit,
148
                ]
149
            );
150
        }
151
    }
152
153
    /**
154
     * @Given /^build progressive price/
155
     */
156
    public function buildProgressivePrices()
157
    {
158
        foreach ($this->progressivePrice as $type => $price) {
159
            $this->fullPrice([
160
                'type' => $type,
161
                'price' => 0,
162
                'currency' => $price['currency'],
163
                'unit' => $price['unit'],
164
                'data' => ['thresholds' => $price['thresholds'], 'class' => 'ProgressivePrice'],
165
            ]);
166
        }
167
    }
168
169
    /**
170
     * @Given /^remove and recreate tariff plan (\S+)/
171
     */
172
    public function recreatePlan($plan)
173
    {
174
        $this->builder->recreatePlan($plan);
175
    }
176
177
    /**
178
     * @Given /sale target (\S+) by plan (\S+) at (\S+)/
179
     */
180
    public function sale($target, $plan, $time): void
181
    {
182
        $this->saleTime = $this->prepareTime($time);
183
        $this->builder->buildSale($target, $plan, $this->saleTime);
0 ignored issues
show
Bug introduced by
It seems like $this->saleTime can also be of type null; however, parameter $time of hiqdev\php\billing\tests...rInterface::buildSale() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

183
        $this->builder->buildSale($target, $plan, /** @scrutinizer ignore-type */ $this->saleTime);
Loading history...
184
    }
185
    /**
186
     * @When /^sale close is requested for target "([^"]*)" at "([^"]*)", assuming current time is "([^"]*)"$/
187
     */
188
    public function saleClose(string $target, string $time, ?string $wallTime)
0 ignored issues
show
Unused Code introduced by
The parameter $wallTime 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

188
    public function saleClose(string $target, string $time, /** @scrutinizer ignore-unused */ ?string $wallTime)

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 $target 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

188
    public function saleClose(/** @scrutinizer ignore-unused */ string $target, string $time, ?string $wallTime)

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 $time 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

188
    public function saleClose(string $target, /** @scrutinizer ignore-unused */ string $time, ?string $wallTime)

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...
189
    {
190
        throw new PendingException();
0 ignored issues
show
Bug introduced by
The type hiqdev\php\billing\tests...tstrap\PendingException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
191
    }
192
193
    /**
194
     * @Then /^target "([^"]*)" has exactly (\d+) sale for customer$/
195
     */
196
    public function targetHasExactlyNSaleForCustomer(string $target, string $count)
0 ignored issues
show
Unused Code introduced by
The parameter $target 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

196
    public function targetHasExactlyNSaleForCustomer(/** @scrutinizer ignore-unused */ string $target, string $count)

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...
197
    {
198
        // TODO: implement
199
        // $sales = $this->builder->findSales(['target-name' => $target]);
200
201
        Assert::assertCount($count, $sales);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sales seems to be never defined.
Loading history...
Bug introduced by
$count of type string is incompatible with the type integer expected by parameter $expectedCount of PHPUnit\Framework\Assert::assertCount(). ( Ignorable by Annotation )

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

201
        Assert::assertCount(/** @scrutinizer ignore-type */ $count, $sales);
Loading history...
202
    }
203
204
    /**
205
     * @Given /purchase target (\S+) by plan (\S+) at ([-:\w\s]+)$/
206
     */
207
    public function purchaseTarget(string $target, string $plan, string $time): void
208
    {
209
        $time = $this->prepareTime($time);
210
        $this->builder->buildPurchase($target, $plan, $time);
211
    }
212
213
    /**
214
     * @Given /^purchase target "([^"]*)" by plan "([^"]*)" at "([^"]*)" with the following initial uses:$/
215
     */
216
    public function purchaseTargetWithInitialUses(string $target, string $plan, string $time, TableNode $usesTable): void
217
    {
218
        $time = $this->prepareTime($time);
219
        $uses = array_map(static function (array $row) {
220
            return [
221
                'type' => $row['type'],
222
                'unit' => $row['unit'],
223
                'amount' => $row['amount'],
224
            ];
225
        }, $usesTable->getColumnsHash());
226
227
        $this->mayFail(
228
            fn() => $this->builder->buildPurchase($target, $plan, $time, $uses)
229
        );
230
    }
231
232
    /**
233
     * @Given /resource consumption for (\S+) is +(\S+) (\S+) for target (\S+) at (.+)$/
234
     */
235
    public function setConsumption(string $type, int $amount, string $unit, string $target, string $time): void
236
    {
237
        $time = $this->prepareTime($time);
238
        $this->builder->setConsumption($type, $amount, $unit, $target, $time);
0 ignored issues
show
Bug introduced by
The method setConsumption() does not exist on hiqdev\php\billing\tests...tstrap\BuilderInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to hiqdev\php\billing\tests...tstrap\BuilderInterface. ( Ignorable by Annotation )

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

238
        $this->builder->/** @scrutinizer ignore-call */ 
239
                        setConsumption($type, $amount, $unit, $target, $time);
Loading history...
239
    }
240
241
    /**
242
     * @Given /recalculate autotariff for target (\S+)( +at (\S+))?$/
243
     */
244
    public function recalculateAutoTariff(string $target, string $time = null): void
245
    {
246
        $this->builder->clientSetAutoTariff($target, $time);
0 ignored issues
show
Bug introduced by
The method clientSetAutoTariff() does not exist on hiqdev\php\billing\tests...tstrap\BuilderInterface. ( Ignorable by Annotation )

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

246
        $this->builder->/** @scrutinizer ignore-call */ 
247
                        clientSetAutoTariff($target, $time);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
247
    }
248
249
    /**
250
     * @Given /perform billing at (\S+)/
251
     */
252
    public function performBilling(string $time): void
253
    {
254
        $this->builder->performBilling($this->prepareTime($time));
255
    }
256
257
    /**
258
     * @Given /action for (\S+) is +(\S+) (\S+) +for target (.+?)( +at (\S+))?$/
259
     */
260
    public function setAction(string $type, int $amount, string $unit, string $target, string $at = null, string $time = null): void
0 ignored issues
show
Unused Code introduced by
The parameter $at 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

260
    public function setAction(string $type, int $amount, string $unit, string $target, /** @scrutinizer ignore-unused */ string $at = null, string $time = null): void

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...
261
    {
262
        $time = $this->prepareTime($time);
263
        $this->builder->setAction($type, $amount, $unit, $target, $time);
0 ignored issues
show
Bug introduced by
It seems like $time can also be of type null; however, parameter $time of hiqdev\php\billing\tests...rInterface::setAction() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

263
        $this->builder->setAction($type, $amount, $unit, $target, /** @scrutinizer ignore-type */ $time);
Loading history...
264
    }
265
266
    /**
267
     * @Given /perform calculation( at (\S+))?/
268
     */
269
    public function performCalculation(string $at = null, string $time = null): array
0 ignored issues
show
Unused Code introduced by
The parameter $at 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

269
    public function performCalculation(/** @scrutinizer ignore-unused */ string $at = null, string $time = null): array

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...
270
    {
271
        $this->charges = $this->builder->performCalculation($this->prepareTime($time));
0 ignored issues
show
Bug introduced by
It seems like $this->prepareTime($time) can also be of type null; however, parameter $time of hiqdev\php\billing\tests...e::performCalculation() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

271
        $this->charges = $this->builder->performCalculation(/** @scrutinizer ignore-type */ $this->prepareTime($time));
Loading history...
272
        return $this->charges;
273
    }
274
275
    /**
276
     * @Given /bill +for (\S+) is +(\S+) (\S+) per (\S+) (\S+) for target (.+?)( +at (.+))?$/
277
     */
278
    public function billWithTime($type, $sum, $currency, $quantity, $unit, $target, $at = null, $time = null)
0 ignored issues
show
Unused Code introduced by
The parameter $at 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

278
    public function billWithTime($type, $sum, $currency, $quantity, $unit, $target, /** @scrutinizer ignore-unused */ $at = null, $time = null)

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...
279
    {
280
        $this->builder->flushEntitiesCacheByType('bill');
281
282
        $quantity = $this->prepareQuantity($quantity);
283
        $sum = $this->prepareSum($sum, $quantity);
284
        $time = $this->prepareTime($time);
285
        $bill = $this->findBill([
286
            'type' => $type,
287
            'target' => $target,
288
            'sum' => "$sum $currency",
289
            'quantity' => "$quantity $unit",
290
            'time' => $time,
291
        ]);
292
        Assert::assertSame($type, $bill->getType()->getName(), "Bill type mismatch: expected $type, got {$bill->getType()->getName()}");
293
        Assert::assertSame($target, $bill->getTarget()->getFullName(), "Bill target mismatch: expected $target, got {$bill->getTarget()->getFullName()}");
294
        Assert::assertEquals(bcmul($sum, 100), $bill->getSum()->getAmount(), "Bill sum mismatch: expected $sum, got {$bill->getSum()->getAmount()}");
295
        Assert::assertSame($currency, $bill->getSum()->getCurrency()->getCode(), "Bill currency mismatch: expected $currency, got {$bill->getSum()->getCurrency()->getCode()}");
296
        Assert::assertEquals((float)$quantity, (float)$bill->getQuantity()->getQuantity(), "Bill quantity mismatch: expected $quantity, got {$bill->getQuantity()->getQuantity()}");
297
        Assert::assertEquals(strtolower($unit), strtolower($bill->getQuantity()->getUnit()->getName()), "Bill unit mismatch: expected $unit, got {$bill->getQuantity()->getUnit()->getName()}");
298
        if ($time) {
299
            Assert::assertEquals(new DateTimeImmutable($time), $bill->getTime(), "Bill time mismatch: expected $time, got {$bill->getTime()->format(DATE_ATOM)}");
300
        }
301
    }
302
303
    public function findBill(array $params): BillInterface
304
    {
305
        $bills = $this->builder->findBills($params);
306
        $this->bill = reset($bills);
307
        $this->charges = $this->bill->getCharges();
308
309
        return $this->bill;
310
    }
311
312
    /**
313
     * @Given /bills number is (\d+) for (\S+) for target (.+?)( +at (\S+))?$/
314
     */
315
    public function billsNumberWithTime($number, $type, $target, $at = null, $time = null)
0 ignored issues
show
Unused Code introduced by
The parameter $at 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

315
    public function billsNumberWithTime($number, $type, $target, /** @scrutinizer ignore-unused */ $at = null, $time = null)

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...
316
    {
317
        $count = count($this->builder->findBills(array_filter([
318
            'type' => $type,
319
            'target' => $target,
320
            'time' => $this->prepareTime($time),
321
        ])));
322
323
        Assert::assertEquals($number, $count);
324
    }
325
326
    /**
327
     * @Given /charges number is (\d+)/
328
     */
329
    public function chargesNumber($number)
330
    {
331
        Assert::assertEquals($number, count($this->charges));
332
    }
333
334
    /**
335
     * @Given /charge for (\S+) is +(\S+) (\S+) per (\S+) (\S+)$/
336
     */
337
    public function charge($type, $amount, $currency, $quantity, $unit)
338
    {
339
        $this->chargeWithTarget($type, $amount, $currency, $quantity, $unit, null);
340
    }
341
342
    /**
343
     * @Given /charge for (\S+) is +(\S+) (\S+) per +(\S+) (\S+) +for target (.+?)( +at (\S+))?$/
344
     */
345
    public function chargeWithTarget($type, $amount, $currency, $quantity, $unit, $target, $at = null, $time = null)
0 ignored issues
show
Unused Code introduced by
The parameter $time 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

345
    public function chargeWithTarget($type, $amount, $currency, $quantity, $unit, $target, $at = null, /** @scrutinizer ignore-unused */ $time = null)

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 $at 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

345
    public function chargeWithTarget($type, $amount, $currency, $quantity, $unit, $target, /** @scrutinizer ignore-unused */ $at = null, $time = null)

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...
346
    {
347
        $quantity = $this->prepareQuantity($quantity);
348
        $amount = $this->prepareSum($amount, $quantity);
349
        $charge = $this->findCharge($type, $target);
350
        Assert::assertNotNull($charge);
351
        Assert::assertSame($type, $charge->getType()->getName());
352
        Assert::assertSame($target, $charge->getTarget()->getFullName());
353
        Assert::assertEquals(bcmul($amount, 100), (int)$charge->getSum()->getAmount());
354
        Assert::assertSame($currency, $charge->getSum()->getCurrency()->getCode());
355
        Assert::assertEquals((float)$quantity, (float)$charge->getUsage()->getQuantity());
356
        Assert::assertEquals(strtolower($unit), strtolower($charge->getUsage()->getUnit()->getName()));
357
    }
358
359
    public function findCharge($type, $target): ?ChargeInterface
360
    {
361
        foreach ($this->charges as $charge) {
362
            if ($charge->getType()->getName() !== $type) {
363
                continue;
364
            }
365
            if ($charge->getTarget()->getFullName() !== $target) {
366
                continue;
367
            }
368
369
            return $charge;
370
        }
371
372
        return null;
373
    }
374
375
    public function getNextCharge(): ChargeInterface
376
    {
377
        $charge = current($this->charges);
378
        next($this->charges);
379
380
        return $charge;
381
    }
382
383
    /**
384
     * @return string|false|null
385
     */
386
    protected function prepareTime(string $time = null)
387
    {
388
        if ($time === null) {
389
            return null;
390
        }
391
392
        if ($time === 'midnight second day of this month') {
393
            return date('Y-m-02');
394
        }
395
        if (strncmp($time, 'pY', 1) === 0) {
396
            return date(substr($time, 1), strtotime('-1 year'));
397
        }
398
        if (str_contains($time, 'nm')) {
399
            $format = str_replace('nm', 'm', $time);
400
            return date($format, strtotime('next month'));
401
        }
402
        if (str_contains($time, 'pm')) {
403
            $time = str_replace('pm', 'm', $time);
404
            $time = date($time, strtotime('-1 month'));
405
        }
406
        if (strncmp($time, 'Y', 1) === 0) {
407
            return date($time);
408
        }
409
410
        return $time;
411
    }
412
413
    private function prepareQuantity($quantity)
414
    {
415
        if ($quantity[0] === 's') {
416
            return $this->getSaleQuantity();
417
        }
418
419
        return $quantity;
420
    }
421
422
    private function prepareSum($sum, $quantity)
423
    {
424
        if ($sum[0] === 's') {
425
            $sum = round(substr($sum, 1) * $quantity*100)/100;
426
        }
427
428
        return $sum;
429
    }
430
431
    public function getSaleQuantity()
432
    {
433
        return $this->days2quantity(new DateTimeImmutable($this->saleTime));
434
    }
435
436
    private function days2quantity(DateTimeImmutable $from)
437
    {
438
        $till = new DateTimeImmutable('first day of next month midnight');
439
        $diff = $from->diff($till);
440
        if ($diff->m) {
441
            return 1;
442
        }
443
444
        return $diff->d/date('t');
445
    }
446
447
    /**
448
     * @When /^tariff plan change is requested for target "([^"]*)" to plan "([^"]*)" at "([^"]*)"$/
449
     */
450
    public function tariffPlanChangeIsRequestedForTarget(string $target, string $planName, string $date)
451
    {
452
        $this->mayFail(fn () => $this->builder->targetChangePlan($target, $planName, $this->prepareTime($date)));
453
    }
454
455
    /**
456
     * @When /^tariff plan change is requested for target "([^"]*)" to plan "([^"]*)" at "([^"]*)", assuming current time is "([^"]*)"$/
457
     */
458
    public function tariffPlanChangeIsRequestedForTargetAtSpecificTime(string $target, string $planName, string $date, ?string $wallTime = null)
459
    {
460
        $this->mayFail(fn () => $this->builder->targetChangePlan($target, $planName, $this->prepareTime($date), $this->prepareTime($wallTime)));
461
    }
462
463
    /**
464
     * @Then /^target "([^"]*)" is sold to customer by plan "([^"]*)" since "([^"]*)"(?: till "([^"]*)")?$/
465
     */
466
    public function targetIsSoldToCustomerByPlanSinceTill(string $target, string $planName, string $saleDate, ?string $saleCloseDate = null)
467
    {
468
        $sales = $this->builder->findHistoricalSales([
469
            'target' => $target,
470
        ]);
471
472
        $saleDateTime = new DateTimeImmutable('@' . strtotime($this->prepareTime($saleDate)));
473
        $saleCloseDateTime = $saleCloseDate ? new DateTimeImmutable('@' . strtotime($this->prepareTime($saleCloseDate))) : null;
474
475
        foreach ($sales as $sale) {
476
            /** @noinspection PhpBooleanCanBeSimplifiedInspection */
477
            $saleExists = true
478
                && str_contains($sale->getPlan()->getName(), $planName)
479
                && $sale->getTime()->format(DATE_ATOM) === $saleDateTime->format(DATE_ATOM)
480
                && (
481
                    ($saleCloseDate === null && $sale->getCloseTime() === null)
482
                    ||
483
                    ($saleCloseDate !== null && $sale->getCloseTime()->format(DATE_ATOM) === $saleCloseDateTime->format(DATE_ATOM))
484
                );
485
486
            if ($saleExists) {
487
                return;
488
            }
489
        }
490
491
        Assert::fail('Requested sale does not exist');
492
    }
493
494
    /**
495
     * @Then /^target "([^"]*)" has exactly (\d+) sales for customer$/
496
     */
497
    public function targetHasExactlySalesForCustomer(string $target, int $count)
498
    {
499
        $sales = $this->builder->findHistoricalSales([
500
            'target' => $target,
501
        ]);
502
503
        Assert::assertCount($count, $sales);
504
    }
505
506
    /**
507
     * @Then /^caught error is "([^"]*)"$/
508
     */
509
    public function caughtErrorIs(string $errorMessage): void
510
    {
511
        $this->assertCaughtExceptionMatches(\Throwable::class, $errorMessage);
512
    }
513
514
    /**
515
     * @Given /^target "([^"]*)"$/
516
     */
517
    public function target(string $target)
518
    {
519
        $this->builder->buildTarget($target);
520
    }
521
522
    /**
523
     * @Then /^flush entities cache$/
524
     */
525
    public function flushEntitiesCache()
526
    {
527
        $this->builder->flushEntitiesCache();
528
    }
529
530
    /**
531
     * @Given /^target "([^"]*)" has the following uses:$/
532
     */
533
    public function targetHasTheFollowingUses(string $target, TableNode $usesTable)
534
    {
535
        foreach ($usesTable->getColumnsHash() as $row) {
536
            $uses = $this->builder->findUsage($row['time'], $target, $row['type']);
537
            Assert::assertCount(1, $uses);
538
539
            $use = reset($uses);
540
            Assert::assertSame(
541
                $row['unit'], $use['unit'],
542
                sprintf('Exptected unit to be %s, got %s instead', $row['unit'], $use['unit'])
543
            );
544
            Assert::assertEquals(
545
                $row['amount'], $use['total'],
546
                sprintf('Exptected total to be %s, got %s instead', $row['amount'], $use['total'])
547
            );
548
        }
549
    }
550
}
551