Completed
Push — 1.0-phpstan ( 5ae83f )
by Kamil
27:50
created

OrderItemSpec   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 447
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 5
dl 0
loc 447
rs 9.6
c 0
b 0
f 0

32 Methods

Rating   Name   Duplication   Size   Complexity  
A it_adds_and_removes_units() 0 17 1
A it_implements_an_order_item_interface() 0 4 1
A it_implements_an_adjustable_interface() 0 4 1
A it_has_no_id_by_default() 0 4 1
A it_does_not_belong_to_an_order_by_default() 0 4 1
A it_allows_assigning_itself_to_an_order() 0 8 1
A it_allows_detaching_itself_from_an_order() 0 14 1
A it_does_not_set_order_if_it_is_already_set() 0 11 1
A it_has_quantity_equal_to_0_by_default() 0 4 1
A it_has_unit_price_equal_to_0_by_default() 0 4 1
A its_unit_price_should_accept_only_integer() 0 5 1
A it_has_total_equal_to_0_by_default() 0 4 1
A it_initializes_adjustments_collection_by_default() 0 4 1
B it_returns_adjustments_recursively() 0 25 1
A it_adds_only_unit_that_is_assigned_to_it() 0 8 1
A it_recalculates_units_total_on_unit_price_change() 0 14 1
A it_adds_adjustments_properly() 0 9 1
A it_removes_adjustments_properly() 0 15 1
A it_has_correct_total_based_on_unit_items() 0 13 1
A it_has_correct_total_after_unit_item_remove() 0 16 1
A it_has_correct_total_after_negative_adjustment_add() 0 19 1
A it_has_correct_total_after_adjustment_add_and_remove() 0 15 1
A it_has_correct_total_after_neutral_adjustment_add_and_remove() 0 15 1
A it_has_0_total_when_adjustment_decreases_total_under_0() 0 15 1
A it_has_correct_total_after_unit_price_change() 0 15 1
A it_has_correct_total_after_order_item_unit_total_change() 0 16 1
A it_has_correct_total_after_adjustment_amount_change() 0 18 1
A it_returns_correct_adjustments_total() 0 16 1
B it_returns_correct_adjustments_total_by_type() 0 27 1
B it_returns_correct_adjustments_total_recursively() 0 29 1
B it_returns_correct_adjustments_total_by_type_recursively() 0 36 1
A it_can_be_immutable() 0 5 1
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace spec\Sylius\Component\Order\Model;
15
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Common\Collections\Collection;
18
use PhpSpec\ObjectBehavior;
19
use Sylius\Component\Order\Model\AdjustableInterface;
20
use Sylius\Component\Order\Model\AdjustmentInterface;
21
use Sylius\Component\Order\Model\OrderInterface;
22
use Sylius\Component\Order\Model\OrderItemInterface;
23
use Sylius\Component\Order\Model\OrderItemUnitInterface;
24
25
/**
26
 * @author Paweł Jędrzejewski <[email protected]>
27
 * @author Michał Marcinkowski <[email protected]>
28
 */
29
final class OrderItemSpec extends ObjectBehavior
30
{
31
    function it_implements_an_order_item_interface(): void
32
    {
33
        $this->shouldImplement(OrderItemInterface::class);
34
    }
35
36
    function it_implements_an_adjustable_interface(): void
37
    {
38
        $this->shouldImplement(AdjustableInterface::class);
39
    }
40
41
    function it_has_no_id_by_default(): void
42
    {
43
        $this->getId()->shouldReturn(null);
44
    }
45
46
    function it_does_not_belong_to_an_order_by_default(): void
47
    {
48
        $this->getOrder()->shouldReturn(null);
49
    }
50
51
    function it_allows_assigning_itself_to_an_order(OrderInterface $order): void
52
    {
53
        $order->hasItem($this)->willReturn(false);
54
        $order->addItem($this)->shouldBeCalled();
55
56
        $this->setOrder($order);
57
        $this->getOrder()->shouldReturn($order);
58
    }
59
60
    function it_allows_detaching_itself_from_an_order(OrderInterface $order): void
61
    {
62
        $order->hasItem($this)->willReturn(false);
63
        $order->addItem($this)->shouldBeCalled();
64
65
        $this->setOrder($order);
66
        $this->getOrder()->shouldReturn($order);
67
68
        $order->hasItem($this)->willReturn(true);
69
        $order->removeItem($this)->shouldBeCalled();
70
71
        $this->setOrder(null);
72
        $this->getOrder()->shouldReturn(null);
73
    }
74
75
    function it_does_not_set_order_if_it_is_already_set(OrderInterface $order): void
76
    {
77
        $order->hasItem($this)->willReturn(false);
78
        $order->addItem($this)->shouldBeCalled();
79
        $this->setOrder($order);
80
        $this->getOrder()->shouldReturn($order);
81
82
        $order->hasItem($this)->willReturn(true);
83
        $this->setOrder($order);
84
        $this->getOrder()->shouldReturn($order);
85
    }
86
87
    function it_has_quantity_equal_to_0_by_default(): void
88
    {
89
        $this->getQuantity()->shouldReturn(0);
90
    }
91
92
    function it_has_unit_price_equal_to_0_by_default(): void
93
    {
94
        $this->getUnitPrice()->shouldReturn(0);
95
    }
96
97
    function its_unit_price_should_accept_only_integer(): void
98
    {
99
        $this->setUnitPrice(4498);
100
        $this->getUnitPrice()->shouldReturn(4498);
101
    }
102
103
    function it_has_total_equal_to_0_by_default(): void
104
    {
105
        $this->getTotal()->shouldReturn(0);
106
    }
107
108
    function it_initializes_adjustments_collection_by_default(): void
109
    {
110
        $this->getAdjustments()->shouldHaveType(Collection::class);
111
    }
112
113
    function it_returns_adjustments_recursively(
114
        AdjustmentInterface $itemAdjustment,
115
        AdjustmentInterface $unitAdjustment1,
116
        AdjustmentInterface $unitAdjustment2,
117
        OrderItemUnitInterface $unit1,
118
        OrderItemUnitInterface $unit2
119
    ): void {
120
        $unit1->getOrderItem()->willReturn($this);
121
        $unit1->getTotal()->willReturn(100);
122
        $unit1->getAdjustments(null)->willReturn(new ArrayCollection([$unitAdjustment1->getWrappedObject()]));
123
124
        $unit2->getOrderItem()->willReturn($this);
125
        $unit2->getTotal()->willReturn(100);
126
        $unit2->getAdjustments(null)->willReturn(new ArrayCollection([$unitAdjustment2->getWrappedObject()]));
127
128
        $this->addUnit($unit1);
129
        $this->addUnit($unit2);
130
131
        $itemAdjustment->setAdjustable($this)->shouldBeCalled();
132
        $itemAdjustment->isNeutral()->willReturn(true);
133
134
        $this->addAdjustment($itemAdjustment);
135
136
        $this->getAdjustmentsRecursively()->shouldIterateAs([$itemAdjustment, $unitAdjustment1, $unitAdjustment2]);
137
    }
138
139
    function it_adds_and_removes_units(OrderItemUnitInterface $orderItemUnit1, OrderItemUnitInterface $orderItemUnit2): void
140
    {
141
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
142
        $orderItemUnit1->getTotal()->willReturn(0);
143
        $orderItemUnit2->getOrderItem()->willReturn($this->getWrappedObject());
144
        $orderItemUnit2->getTotal()->willReturn(0);
145
        $this->getUnits()->shouldHaveType(Collection::class);
146
147
        $this->addUnit($orderItemUnit1);
148
        $this->addUnit($orderItemUnit2);
149
        $this->hasUnit($orderItemUnit1)->shouldReturn(true);
150
        $this->hasUnit($orderItemUnit2)->shouldReturn(true);
151
152
        $this->removeUnit($orderItemUnit1);
153
        $this->hasUnit($orderItemUnit1)->shouldReturn(false);
154
        $this->hasUnit($orderItemUnit2)->shouldReturn(true);
155
    }
156
157
    function it_adds_only_unit_that_is_assigned_to_it(OrderItemUnitInterface $orderItemUnit1, OrderItemInterface $orderItem): void
158
    {
159
        $orderItemUnit1->getOrderItem()->willReturn($orderItem);
160
        $this
161
            ->shouldThrow(new \LogicException('This order item unit is assigned to a different order item.'))
162
            ->duringAddUnit($orderItemUnit1)
163
        ;
164
    }
165
166
    function it_recalculates_units_total_on_unit_price_change(
167
        OrderItemUnitInterface $orderItemUnit1,
168
        OrderItemUnitInterface $orderItemUnit2
169
    ): void {
170
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
171
        $orderItemUnit1->getTotal()->willReturn(0, 100);
172
        $orderItemUnit2->getOrderItem()->willReturn($this->getWrappedObject());
173
        $orderItemUnit2->getTotal()->willReturn(0, 100);
174
175
        $this->addUnit($orderItemUnit1);
176
        $this->addUnit($orderItemUnit2);
177
178
        $this->setUnitPrice(100);
179
    }
180
181
    function it_adds_adjustments_properly(AdjustmentInterface $adjustment): void
182
    {
183
        $adjustment->isNeutral()->willReturn(true);
184
        $adjustment->setAdjustable($this)->shouldBeCalled();
185
186
        $this->hasAdjustment($adjustment)->shouldReturn(false);
187
        $this->addAdjustment($adjustment);
188
        $this->hasAdjustment($adjustment)->shouldReturn(true);
189
    }
190
191
    function it_removes_adjustments_properly(AdjustmentInterface $adjustment): void
192
    {
193
        $adjustment->isNeutral()->willReturn(true);
194
        $adjustment->setAdjustable($this)->shouldBeCalled();
195
196
        $this->hasAdjustment($adjustment)->shouldReturn(false);
197
        $this->addAdjustment($adjustment);
198
        $this->hasAdjustment($adjustment)->shouldReturn(true);
199
200
        $adjustment->setAdjustable(null)->shouldBeCalled();
201
        $adjustment->isLocked()->willReturn(false);
202
203
        $this->removeAdjustment($adjustment);
204
        $this->hasAdjustment($adjustment)->shouldReturn(false);
205
    }
206
207
    function it_has_correct_total_based_on_unit_items(
208
        OrderItemUnitInterface $orderItemUnit1,
209
        OrderItemUnitInterface $orderItemUnit2
210
    ): void {
211
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
212
        $orderItemUnit1->getTotal()->willReturn(1499);
213
        $orderItemUnit2->getOrderItem()->willReturn($this->getWrappedObject());
214
        $orderItemUnit2->getTotal()->willReturn(1499);
215
216
        $this->addUnit($orderItemUnit1);
217
        $this->addUnit($orderItemUnit2);
218
        $this->getTotal()->shouldReturn(2998);
219
    }
220
221
    function it_has_correct_total_after_unit_item_remove(
222
        OrderItemUnitInterface $orderItemUnit1,
223
        OrderItemUnitInterface $orderItemUnit2
224
    ): void {
225
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
226
        $orderItemUnit1->getTotal()->willReturn(2000);
227
        $orderItemUnit2->getOrderItem()->willReturn($this->getWrappedObject());
228
        $orderItemUnit2->getTotal()->willReturn(1000);
229
230
        $this->addUnit($orderItemUnit1);
231
        $this->addUnit($orderItemUnit2);
232
        $this->getTotal()->shouldReturn(3000);
233
234
        $this->removeUnit($orderItemUnit2);
235
        $this->getTotal()->shouldReturn(2000);
236
    }
237
238
    function it_has_correct_total_after_negative_adjustment_add(
239
        AdjustmentInterface $adjustment,
240
        OrderItemUnitInterface $orderItemUnit1,
241
        OrderItemUnitInterface $orderItemUnit2
242
    ): void {
243
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
244
        $orderItemUnit1->getTotal()->willReturn(1499);
245
        $orderItemUnit2->getOrderItem()->willReturn($this->getWrappedObject());
246
        $orderItemUnit2->getTotal()->willReturn(1499);
247
248
        $adjustment->isNeutral()->willReturn(false);
249
        $adjustment->getAmount()->willReturn(-1000);
250
        $adjustment->setAdjustable($this)->shouldBeCalled();
251
252
        $this->addUnit($orderItemUnit1);
253
        $this->addUnit($orderItemUnit2);
254
        $this->addAdjustment($adjustment);
255
        $this->getTotal()->shouldReturn(1998);
256
    }
257
258
    function it_has_correct_total_after_adjustment_add_and_remove(AdjustmentInterface $adjustment): void
259
    {
260
        $adjustment->isNeutral()->willReturn(false);
261
        $adjustment->getAmount()->willReturn(200);
262
        $adjustment->setAdjustable($this)->shouldBeCalled();
263
264
        $this->addAdjustment($adjustment);
265
        $this->getTotal()->shouldReturn(200);
266
267
        $adjustment->setAdjustable(null)->shouldBeCalled();
268
        $adjustment->isLocked()->willReturn(false);
269
270
        $this->removeAdjustment($adjustment);
271
        $this->getTotal()->shouldReturn(0);
272
    }
273
274
    function it_has_correct_total_after_neutral_adjustment_add_and_remove(AdjustmentInterface $adjustment): void
275
    {
276
        $adjustment->isNeutral()->willReturn(true);
277
        $adjustment->getAmount()->willReturn(200);
278
        $adjustment->setAdjustable($this)->shouldBeCalled();
279
280
        $this->addAdjustment($adjustment);
281
        $this->getTotal()->shouldReturn(0);
282
283
        $adjustment->setAdjustable(null)->shouldBeCalled();
284
        $adjustment->isLocked()->willReturn(false);
285
286
        $this->removeAdjustment($adjustment);
287
        $this->getTotal()->shouldReturn(0);
288
    }
289
290
    function it_has_0_total_when_adjustment_decreases_total_under_0(
291
        AdjustmentInterface $adjustment,
292
        OrderItemUnitInterface $orderItemUnit1
293
    ): void {
294
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
295
        $orderItemUnit1->getTotal()->willReturn(1499);
296
297
        $adjustment->isNeutral()->willReturn(false);
298
        $adjustment->getAmount()->willReturn(-2000);
299
        $adjustment->setAdjustable($this)->shouldBeCalled();
300
301
        $this->addUnit($orderItemUnit1);
302
        $this->addAdjustment($adjustment);
303
        $this->getTotal()->shouldReturn(0);
304
    }
305
306
    function it_has_correct_total_after_unit_price_change(
307
        OrderItemUnitInterface $orderItemUnit1,
308
        OrderItemUnitInterface $orderItemUnit2
309
    ): void {
310
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
311
        $orderItemUnit1->getTotal()->willReturn(0, 100);
312
        $orderItemUnit2->getOrderItem()->willReturn($this->getWrappedObject());
313
        $orderItemUnit2->getTotal()->willReturn(0, 100);
314
315
        $this->addUnit($orderItemUnit1);
316
        $this->addUnit($orderItemUnit2);
317
318
        $this->setUnitPrice(100);
319
        $this->getTotal()->shouldReturn(200);
320
    }
321
322
    function it_has_correct_total_after_order_item_unit_total_change(
323
        OrderItemUnitInterface $orderItemUnit1,
324
        OrderItemUnitInterface $orderItemUnit2
325
    ): void {
326
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
327
        $orderItemUnit1->getTotal()->willReturn(0);
328
        $orderItemUnit2->getOrderItem()->willReturn($this->getWrappedObject());
329
        $orderItemUnit2->getTotal()->willReturn(0, 100);
330
331
        $this->addUnit($orderItemUnit1);
332
        $this->addUnit($orderItemUnit2);
333
334
        $this->getTotal()->shouldReturn(0);
335
        $this->recalculateUnitsTotal();
336
        $this->getTotal()->shouldReturn(100);
337
    }
338
339
    function it_has_correct_total_after_adjustment_amount_change(
340
        AdjustmentInterface $adjustment1,
341
        AdjustmentInterface $adjustment2
342
    ): void {
343
        $adjustment1->getAmount()->willReturn(100);
344
        $adjustment1->isNeutral()->willReturn(false);
345
        $adjustment1->setAdjustable($this)->shouldBeCalled();
346
        $adjustment2->getAmount()->willReturn(500, 300);
347
        $adjustment2->isNeutral()->willReturn(false);
348
        $adjustment2->setAdjustable($this)->shouldBeCalled();
349
350
        $this->addAdjustment($adjustment1);
351
        $this->addAdjustment($adjustment2);
352
353
        $this->getTotal()->shouldReturn(600);
354
        $this->recalculateAdjustmentsTotal();
355
        $this->getTotal()->shouldReturn(400);
356
    }
357
358
    function it_returns_correct_adjustments_total(
359
        AdjustmentInterface $adjustment1,
360
        AdjustmentInterface $adjustment2
361
    ): void {
362
        $adjustment1->getAmount()->willReturn(100);
363
        $adjustment1->isNeutral()->willReturn(false);
364
        $adjustment1->setAdjustable($this)->shouldBeCalled();
365
        $adjustment2->getAmount()->willReturn(500);
366
        $adjustment2->isNeutral()->willReturn(false);
367
        $adjustment2->setAdjustable($this)->shouldBeCalled();
368
369
        $this->addAdjustment($adjustment1);
370
        $this->addAdjustment($adjustment2);
371
372
        $this->getAdjustmentsTotal()->shouldReturn(600);
373
    }
374
375
    function it_returns_correct_adjustments_total_by_type(
376
        AdjustmentInterface $adjustment1,
377
        AdjustmentInterface $adjustment2,
378
        AdjustmentInterface $adjustment3
379
    ): void {
380
        $adjustment1->getType()->willReturn('tax');
381
        $adjustment1->getAmount()->willReturn(200);
382
        $adjustment1->isNeutral()->willReturn(false);
383
        $adjustment1->setAdjustable($this)->shouldBeCalled();
384
        $adjustment2->getType()->willReturn('tax');
385
        $adjustment2->getAmount()->willReturn(-50);
386
        $adjustment2->isNeutral()->willReturn(false);
387
        $adjustment2->setAdjustable($this)->shouldBeCalled();
388
389
        $adjustment3->getType()->willReturn('promotion');
390
        $adjustment3->getAmount()->willReturn(-1000);
391
        $adjustment3->isNeutral()->willReturn(false);
392
        $adjustment3->setAdjustable($this)->shouldBeCalled();
393
394
        $this->addAdjustment($adjustment1);
395
        $this->addAdjustment($adjustment2);
396
        $this->addAdjustment($adjustment3);
397
398
        $this->getAdjustmentsTotal('tax')->shouldReturn(150);
399
        $this->getAdjustmentsTotal('promotion')->shouldReturn(-1000);
400
        $this->getAdjustmentsTotal('any')->shouldReturn(0);
401
    }
402
403
    function it_returns_correct_adjustments_total_recursively(
404
        AdjustmentInterface $adjustment1,
405
        AdjustmentInterface $taxAdjustment1,
406
        AdjustmentInterface $taxAdjustment2,
407
        OrderItemUnitInterface $orderItemUnit1,
408
        OrderItemUnitInterface $orderItemUnit2
409
    ): void {
410
        $adjustment1->getAmount()->willReturn(200);
411
        $adjustment1->isNeutral()->willReturn(false);
412
        $adjustment1->setAdjustable($this)->shouldBeCalled();
413
414
        $taxAdjustment1->getAmount()->willReturn(150);
415
        $taxAdjustment1->isNeutral()->willReturn(false);
416
        $taxAdjustment2->getAmount()->willReturn(100);
417
        $taxAdjustment2->isNeutral()->willReturn(false);
418
419
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
420
        $orderItemUnit1->getTotal()->willReturn(500);
421
        $orderItemUnit1->getAdjustments(null)->willReturn(new ArrayCollection([$taxAdjustment1->getWrappedObject()]));
422
        $orderItemUnit2->getOrderItem()->willReturn($this->getWrappedObject());
423
        $orderItemUnit2->getTotal()->willReturn(300);
424
        $orderItemUnit2->getAdjustments(null)->willReturn(new ArrayCollection([$taxAdjustment2->getWrappedObject()]));
425
426
        $this->addAdjustment($adjustment1);
427
        $this->addUnit($orderItemUnit1);
428
        $this->addUnit($orderItemUnit2);
429
430
        $this->getAdjustmentsTotalRecursively()->shouldReturn(450);
431
    }
432
433
    function it_returns_correct_adjustments_total_by_type_recursively(
434
        AdjustmentInterface $adjustment1,
435
        AdjustmentInterface $promotionAdjustment,
436
        AdjustmentInterface $taxAdjustment1,
437
        AdjustmentInterface $taxAdjustment2,
438
        OrderItemUnitInterface $orderItemUnit1,
439
        OrderItemUnitInterface $orderItemUnit2
440
    ): void {
441
        $adjustment1->getType()->willReturn('tax');
442
        $adjustment1->getAmount()->willReturn(200);
443
        $adjustment1->isNeutral()->willReturn(false);
444
        $adjustment1->setAdjustable($this)->shouldBeCalled();
445
446
        $promotionAdjustment->getAmount()->willReturn(30);
447
        $promotionAdjustment->isNeutral()->willReturn(false);
448
        $taxAdjustment1->getAmount()->willReturn(150);
449
        $taxAdjustment1->isNeutral()->willReturn(false);
450
        $taxAdjustment2->getAmount()->willReturn(100);
451
        $taxAdjustment2->isNeutral()->willReturn(false);
452
453
        $orderItemUnit1->getOrderItem()->willReturn($this->getWrappedObject());
454
        $orderItemUnit1->getTotal()->willReturn(500);
455
        $orderItemUnit1->getAdjustments('tax')->willReturn(new ArrayCollection([$taxAdjustment1->getWrappedObject()]));
456
        $orderItemUnit1->getAdjustments('promotion')->willReturn(new ArrayCollection([$promotionAdjustment->getWrappedObject()]));
457
        $orderItemUnit2->getOrderItem()->willReturn($this->getWrappedObject());
458
        $orderItemUnit2->getTotal()->willReturn(300);
459
        $orderItemUnit2->getAdjustments('tax')->willReturn(new ArrayCollection([$taxAdjustment2->getWrappedObject()]));
460
        $orderItemUnit2->getAdjustments('promotion')->willReturn(new ArrayCollection());
461
462
        $this->addAdjustment($adjustment1);
463
        $this->addUnit($orderItemUnit1);
464
        $this->addUnit($orderItemUnit2);
465
466
        $this->getAdjustmentsTotalRecursively('tax')->shouldReturn(450);
467
        $this->getAdjustmentsTotalRecursively('promotion')->shouldReturn(30);
468
    }
469
470
    function it_can_be_immutable(): void
471
    {
472
        $this->setImmutable(true);
473
        $this->isImmutable()->shouldReturn(true);
474
    }
475
}
476