Passed
Push — master ( a8b983...5b3176 )
by Adrien
10:48
created

InvoicerTest::providerCreateOrder()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 203
Code Lines 129

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 129
nc 1
nop 0
dl 0
loc 203
rs 8
c 1
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace ApplicationTest\Service;
6
7
use Application\DBAL\Types\PaymentMethodType;
8
use Application\DBAL\Types\ProductTypeType;
9
use Application\Model\AbstractProduct;
10
use Application\Model\Order;
11
use Application\Model\OrderLine;
12
use Application\Model\Product;
13
use Application\Model\Subscription;
14
use Application\Service\Invoicer;
15
use ApplicationTest\Traits\TestWithTransactionAndUser;
16
use Money\Money;
17
use PHPUnit\Framework\TestCase;
18
19
class InvoicerTest extends TestCase
20
{
21
    use TestWithTransactionAndUser;
22
23
    /**
24
     * @dataProvider providerCreateOrder
25
     */
26
    public function testCreateOrder(array $input, array $expectedOrderLines): void
27
    {
28
        $input['orderLines'] = $this->hydrateTestData($input['orderLines']);
29
30
        global $container;
31
        /** @var Invoicer $invoicer */
32
        $invoicer = $container->get(Invoicer::class);
33
        $order = $invoicer->createOrder($input);
34
35
        $actualOrderLines = $this->extractOrderLines($order);
0 ignored issues
show
Bug introduced by
It seems like $order can also be of type null; however, parameter $order of ApplicationTest\Service\...st::extractOrderLines() does only seem to accept Application\Model\Order, 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

35
        $actualOrderLines = $this->extractOrderLines(/** @scrutinizer ignore-type */ $order);
Loading history...
36
        self::assertSame($expectedOrderLines, $actualOrderLines);
37
    }
38
39
    /**
40
     * @dataProvider providerUpdateOrderLineAndTransactionLine
41
     */
42
    public function testUpdateOrderLineAndTransactionLine(string $originalOrder, ?array $newProduct, array $expectedOrderLines): void
43
    {
44
        $input = $this->providerCreateOrder()[$originalOrder][0];
45
        $input['orderLines'] = $this->hydrateTestData($input['orderLines']);
46
47
        global $container;
48
        /** @var Invoicer $invoicer */
49
        $invoicer = $container->get(Invoicer::class);
50
        $order = $invoicer->createOrder($input);
51
52
        if ($newProduct) {
53
            $product = $this->hydrateProduct($newProduct);
54
        } else {
55
            $product = $input['orderLines'][0]['product'];
56
        }
57
58
        $line = [
59
            'quantity' => '100',
60
            'isCHF' => true,
61
            'type' => ProductTypeType::DIGITAL,
62
            'product' => $product,
63
            'additionalEmails' => [],
64
        ];
65
66
        $invoicer->updateOrderLineAndTransactionLine($order->getOrderLines()->first(), $line);
67
68
        $actualOrderLines = $this->extractOrderLines($order);
0 ignored issues
show
Bug introduced by
It seems like $order can also be of type null; however, parameter $order of ApplicationTest\Service\...st::extractOrderLines() does only seem to accept Application\Model\Order, 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

68
        $actualOrderLines = $this->extractOrderLines(/** @scrutinizer ignore-type */ $order);
Loading history...
69
        self::assertSame($expectedOrderLines, $actualOrderLines);
70
    }
71
72
    public function providerUpdateOrderLineAndTransactionLine(): array
73
    {
74
        return [
75
            'more quantity of same product' => [
76
                'normal',
77
                null,
78
                [
79
                    [
80
                        'My product 1',
81
                        '100',
82
                        '27500',
83
                        '0',
84
                        true,
85
                        ProductTypeType::DIGITAL,
86
                    ],
87
                    [
88
                        'My product 2',
89
                        '1',
90
                        '20000',
91
                        '0',
92
                        true,
93
                        ProductTypeType::DIGITAL,
94
                    ],
95
                ],
96
            ],
97
            'more quantity of different, negative product' => [
98
                'normal',
99
                [
100
                    'name' => 'My negative product',
101
                    'pricePerUnitCHF' => Money::CHF(-10000),
102
                    'pricePerUnitEUR' => Money::EUR(-15000),
103
                ],
104
                [
105
                    [
106
                        'My negative product',
107
                        '100',
108
                        '-1000000',
109
                        '0',
110
                        true,
111
                        ProductTypeType::DIGITAL,
112
                    ],
113
                    [
114
                        'My product 2',
115
                        '1',
116
                        '20000',
117
                        '0',
118
                        true,
119
                        ProductTypeType::DIGITAL,
120
                    ],
121
                ],
122
            ],
123
            'from negative goes back to positive' => [
124
                'negative balance should swap accounts',
125
                [
126
                    'name' => 'My positive product',
127
                    'pricePerUnitCHF' => Money::CHF(10000),
128
                    'pricePerUnitEUR' => Money::EUR(15000),
129
                ],
130
                [
131
                    [
132
                        'My positive product',
133
                        '100',
134
                        '1000000',
135
                        '0',
136
                        true,
137
                        ProductTypeType::DIGITAL,
138
                    ],
139
                ],
140
            ],
141
        ];
142
    }
143
144
    public function providerCreateOrder(): array
145
    {
146
        return [
147
            'free product should create order, even with transactions for zero dollars' => [
148
                [
149
                    'paymentMethod' => PaymentMethodType::BVR,
150
                    'orderLines' => [
151
                        [
152
                            'quantity' => '1',
153
                            'isCHF' => true,
154
                            'type' => ProductTypeType::DIGITAL,
155
                            'product' => [
156
                                'name' => 'My product',
157
                                'pricePerUnitCHF' => Money::CHF(0),
158
                                'pricePerUnitEUR' => Money::EUR(0),
159
                            ],
160
                            'additionalEmails' => [],
161
                        ],
162
                    ],
163
                ],
164
                [
165
                    [
166
                        'My product',
167
                        '1',
168
                        '0',
169
                        '0',
170
                        true,
171
                        ProductTypeType::DIGITAL,
172
                    ],
173
                ],
174
            ],
175
            'normal' => [
176
                [
177
                    'paymentMethod' => PaymentMethodType::BVR,
178
                    'orderLines' => [
179
                        [
180
                            'quantity' => '3.100',
181
                            'isCHF' => true,
182
                            'type' => ProductTypeType::DIGITAL,
183
                            'product' => [
184
                                'name' => 'My product 1',
185
                                'pricePerUnitCHF' => Money::CHF(275),
186
                                'pricePerUnitEUR' => Money::EUR(280),
187
                            ],
188
                            'additionalEmails' => [],
189
                        ],
190
                        [
191
                            'quantity' => '1',
192
                            'isCHF' => true,
193
                            'type' => ProductTypeType::DIGITAL,
194
                            'product' => [
195
                                'name' => 'My product 2',
196
                                'pricePerUnitCHF' => Money::CHF(20000),
197
                                'pricePerUnitEUR' => Money::EUR(25000),
198
                            ],
199
                            'additionalEmails' => [],
200
                        ],
201
                    ],
202
                ],
203
                [
204
                    [
205
                        'My product 1',
206
                        '3.100',
207
                        '853',
208
                        '0',
209
                        true,
210
                        ProductTypeType::DIGITAL,
211
                    ],
212
                    [
213
                        'My product 2',
214
                        '1',
215
                        '20000',
216
                        '0',
217
                        true,
218
                        ProductTypeType::DIGITAL,
219
                    ],
220
                ],
221
            ],
222
            'with mixed CHF/EURO prices' => [
223
                [
224
                    'paymentMethod' => PaymentMethodType::BVR,
225
                    'orderLines' => [
226
                        [
227
                            'quantity' => '3.100',
228
                            'isCHF' => false,
229
                            'type' => ProductTypeType::DIGITAL,
230
                            'product' => [
231
                                'name' => 'My product 1',
232
                                'pricePerUnitCHF' => Money::CHF(275),
233
                                'pricePerUnitEUR' => Money::EUR(280),
234
                            ],
235
                            'additionalEmails' => [],
236
                        ],
237
                        [
238
                            'quantity' => '1',
239
                            'isCHF' => true,
240
                            'type' => ProductTypeType::PAPER,
241
                            'product' => [
242
                                'name' => 'My product 2',
243
                                'pricePerUnitCHF' => Money::CHF(20000),
244
                                'pricePerUnitEUR' => Money::EUR(25000),
245
                            ],
246
                            'additionalEmails' => [],
247
                        ],
248
                    ],
249
                ],
250
                [
251
                    [
252
                        'My product 1',
253
                        '3.100',
254
                        '0',
255
                        '868',
256
                        false,
257
                        ProductTypeType::DIGITAL,
258
                    ],
259
                    [
260
                        'My product 2',
261
                        '1',
262
                        '20000',
263
                        '0',
264
                        true,
265
                        ProductTypeType::PAPER,
266
                    ],
267
                ],
268
            ],
269
            'negative balance should swap accounts' => [
270
                [
271
                    'paymentMethod' => PaymentMethodType::BVR,
272
                    'orderLines' => [
273
                        [
274
                            'quantity' => '1',
275
                            'isCHF' => true,
276
                            'type' => ProductTypeType::DIGITAL,
277
                            'product' => [
278
                                'name' => 'My product',
279
                                'pricePerUnitCHF' => Money::CHF(-10000),
280
                                'pricePerUnitEUR' => Money::EUR(-15000),
281
                            ],
282
                            'additionalEmails' => [],
283
                        ],
284
                    ],
285
                ],
286
                [
287
                    [
288
                        'My product',
289
                        '1',
290
                        '-10000',
291
                        '0',
292
                        true,
293
                        ProductTypeType::DIGITAL,
294
                    ],
295
                ],
296
            ],
297
            'can create order for subscription' => [
298
                [
299
                    'paymentMethod' => PaymentMethodType::BVR,
300
                    'orderLines' => [
301
                        [
302
                            'quantity' => '1',
303
                            'isCHF' => true,
304
                            'type' => ProductTypeType::DIGITAL,
305
                            'subscription' => [
306
                                'name' => 'My subscription',
307
                                'pricePerUnitCHF' => Money::CHF(10000),
308
                                'pricePerUnitEUR' => Money::EUR(15000),
309
                                'type' => ProductTypeType::BOTH,
310
                            ],
311
                            'additionalEmails' => [],
312
                        ],
313
                    ],
314
                ],
315
                [
316
                    [
317
                        'My subscription',
318
                        '1',
319
                        '10000',
320
                        '0',
321
                        true,
322
                        ProductTypeType::BOTH,
323
                    ],
324
                ],
325
            ],
326
            'can create order for donation' => [
327
                [
328
                    'paymentMethod' => PaymentMethodType::BVR,
329
                    'orderLines' => [
330
                        [
331
                            'quantity' => '1',
332
                            'isCHF' => true,
333
                            'type' => ProductTypeType::DIGITAL,
334
                            'pricePerUnit' => 100,
335
                            'additionalEmails' => [],
336
                        ],
337
                    ],
338
                ],
339
                [
340
                    [
341
                        'Don',
342
                        '1',
343
                        '10000',
344
                        '0',
345
                        true,
346
                        ProductTypeType::DIGITAL,
347
                    ],
348
                ],
349
            ],
350
        ];
351
    }
352
353
    private function hydrateTestData(array $input): array
354
    {
355
        foreach ($input as &$i) {
356
            if (array_key_exists('product', $i)) {
357
                $i['product'] = $this->hydrateProduct($i['product']);
358
            }
359
            if (array_key_exists('subscription', $i)) {
360
                $i['subscription'] = $this->hydrateSubscription($i['subscription']);
361
            }
362
        }
363
364
        return $input;
365
    }
366
367
    private function extractOrderLines(Order $order): array
368
    {
369
        $actualOrderLines = [];
370
        /** @var OrderLine $orderLine */
371
        foreach ($order->getOrderLines() as $orderLine) {
372
            $abstractProduct = $orderLine->getProduct() ?: $orderLine->getSubscription();
373
            $expectedName = $abstractProduct ? $abstractProduct->getName() : 'Don';
374
            self::assertSame($expectedName, $orderLine->getName());
375
376
            $actualOrderLines[] = [
377
                $orderLine->getName(),
378
                $orderLine->getQuantity(),
379
                $orderLine->getBalanceCHF()->getAmount(),
380
                $orderLine->getBalanceEUR()->getAmount(),
381
                $orderLine->isCHF(),
382
                $orderLine->getType(),
383
            ];
384
        }
385
386
        return $actualOrderLines;
387
    }
388
389
    private function hydrateProduct(array $p): Product
390
    {
391
        $product = new Product();
392
        $this->hydrateAbstractProduct($product, $p);
393
394
        return $product;
395
    }
396
397
    private function hydrateSubscription(array $s): Subscription
398
    {
399
        $subscription = new Subscription();
400
        $this->hydrateAbstractProduct($subscription, $s);
401
402
        return $subscription;
403
    }
404
405
    private function hydrateAbstractProduct(AbstractProduct $product, array $p): void
406
    {
407
        $product->setName($p['name']);
408
        $product->setPricePerUnitCHF($p['pricePerUnitCHF']);
409
        $product->setPricePerUnitEUR($p['pricePerUnitEUR']);
410
        $product->setType($p['type'] ?? ProductTypeType::DIGITAL);
411
    }
412
}
413