Completed
Push — reproduce-taxon-autocompletion ( 8c649e )
by Kamil
22:05
created

OrderItemSpec::it_adds_adjustments_properly()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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