Completed
Push — 1.0-phpstan ( ddfe6c )
by Kamil
23:36
created

OrderSpec::it_has_total_quantity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
nc 1
cc 1
eloc 11
nop 2
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 Prophecy\Argument;
20
use Sylius\Component\Order\Model\AdjustableInterface;
21
use Sylius\Component\Order\Model\AdjustmentInterface;
22
use Sylius\Component\Order\Model\OrderInterface;
23
use Sylius\Component\Order\Model\OrderItemInterface;
24
use Sylius\Component\Resource\Model\TimestampableInterface;
25
26
final class OrderSpec extends ObjectBehavior
27
{
28
    function it_implements_an_order_interface(): void
29
    {
30
        $this->shouldImplement(OrderInterface::class);
31
    }
32
33
    function it_implements_an_adjustable_interface(): void
34
    {
35
        $this->shouldImplement(AdjustableInterface::class);
36
    }
37
38
    function it_implements_a_timestampable_interface(): void
39
    {
40
        $this->shouldImplement(TimestampableInterface::class);
41
    }
42
43
    function it_has_no_id_by_default(): void
44
    {
45
        $this->getId()->shouldReturn(null);
46
    }
47
48
    function it_does_not_have_completed_checkout_by_default(): void
49
    {
50
        $this->shouldNotBeCheckoutCompleted();
51
    }
52
53
    function its_checkout_can_be_completed(): void
54
    {
55
        $this->completeCheckout();
56
        $this->shouldBeCheckoutCompleted();
57
    }
58
59
    function it_has_checkout_completed_when_completion_date_is_set(): void
60
    {
61
        $this->shouldNotBeCheckoutCompleted();
62
        $this->setCheckoutCompletedAt(new \DateTime('2 days ago'));
63
        $this->shouldBeCheckoutCompleted();
64
    }
65
66
    function it_has_no_checkout_completion_date_by_default(): void
67
    {
68
        $this->getCheckoutCompletedAt()->shouldReturn(null);
69
    }
70
71
    function its_checkout_completion_date_is_mutable(): void
72
    {
73
        $date = new \DateTime('1 hour ago');
74
75
        $this->setCheckoutCompletedAt($date);
76
        $this->getCheckoutCompletedAt()->shouldReturn($date);
77
    }
78
79
    function it_has_no_number_by_default(): void
80
    {
81
        $this->getNumber()->shouldReturn(null);
82
    }
83
84
    function its_number_is_mutable(): void
85
    {
86
        $this->setNumber('001351');
87
        $this->getNumber()->shouldReturn('001351');
88
    }
89
90
    function it_creates_items_collection_by_default(): void
91
    {
92
        $this->getItems()->shouldHaveType(Collection::class);
93
    }
94
95
    function it_adds_items_properly(OrderItemInterface $item): void
96
    {
97
        $item->getTotal()->willReturn(420);
98
        $item->setOrder($this)->shouldBeCalled();
99
100
        $this->hasItem($item)->shouldReturn(false);
101
102
        $this->addItem($item);
103
        $this->hasItem($item)->shouldReturn(true);
104
    }
105
106
    function it_removes_items_properly(OrderItemInterface $item): void
107
    {
108
        $item->getTotal()->willReturn(420);
109
110
        $item->setOrder($this)->shouldBeCalled();
111
        $this->addItem($item);
112
113
        $item->setOrder(null)->shouldBeCalled();
114
        $this->removeItem($item);
115
116
        $this->hasItem($item)->shouldReturn(false);
117
    }
118
119
    function it_has_items_total_equal_to_0_by_default(): void
120
    {
121
        $this->getItemsTotal()->shouldReturn(0);
122
    }
123
124
    function it_calculates_correct_items_total(
125
        OrderItemInterface $item1,
126
        OrderItemInterface $item2,
127
        OrderItemInterface $item3
128
    ): void {
129
        $item1->getTotal()->willReturn(29999);
130
        $item2->getTotal()->willReturn(45000);
131
        $item3->getTotal()->willReturn(250);
132
133
        $item1->setOrder($this)->shouldBeCalled();
134
        $item2->setOrder($this)->shouldBeCalled();
135
        $item3->setOrder($this)->shouldBeCalled();
136
137
        $item1->equals(Argument::any())->willReturn(false);
138
        $item2->equals(Argument::any())->willReturn(false);
139
        $item3->equals(Argument::any())->willReturn(false);
140
141
        $this->addItem($item1);
142
        $this->addItem($item2);
143
        $this->addItem($item3);
144
145
        $this->getItemsTotal()->shouldReturn(75249);
146
    }
147
148
    function it_creates_adjustments_collection_by_default(): void
149
    {
150
        $this->getAdjustments()->shouldHaveType(Collection::class);
151
    }
152
153
    function it_adds_adjustments_properly(AdjustmentInterface $adjustment): void
154
    {
155
        $adjustment->setAdjustable($this)->shouldBeCalled();
156
        $adjustment->isNeutral()->willReturn(true);
157
158
        $this->hasAdjustment($adjustment)->shouldReturn(false);
159
        $this->addAdjustment($adjustment);
160
        $this->hasAdjustment($adjustment)->shouldReturn(true);
161
    }
162
163
    function it_removes_adjustments_properly(AdjustmentInterface $adjustment): void
164
    {
165
        $this->hasAdjustment($adjustment)->shouldReturn(false);
166
167
        $adjustment->setAdjustable($this)->shouldBeCalled();
168
        $adjustment->isNeutral()->willReturn(true);
169
170
        $this->addAdjustment($adjustment);
171
        $this->hasAdjustment($adjustment)->shouldReturn(true);
172
173
        $adjustment->isLocked()->willReturn(false);
174
        $adjustment->setAdjustable(null)->shouldBeCalled();
175
        $this->removeAdjustment($adjustment);
176
177
        $this->hasAdjustment($adjustment)->shouldReturn(false);
178
    }
179
180
    function it_removes_adjustments_recursively_properly(
181
        AdjustmentInterface $orderAdjustment,
182
        OrderItemInterface $item
183
    ): void {
184
        $orderAdjustment->getAmount()->willReturn(420);
185
        $orderAdjustment->isNeutral()->willReturn(true);
186
        $orderAdjustment->isLocked()->willReturn(false);
187
        $orderAdjustment->setAdjustable(Argument::any())->will(function () {});
188
189
        $item->getTotal()->willReturn(666);
190
        $item->setOrder($this)->will(function () {});
191
192
        $this->addAdjustment($orderAdjustment);
193
        $this->addItem($item);
194
195
        $item->removeAdjustmentsRecursively(null)->shouldBeCalled();
196
197
        $this->removeAdjustmentsRecursively();
198
199
        $this->hasAdjustment($orderAdjustment)->shouldReturn(false);
200
    }
201
202
    function it_removes_adjustments_recursively_by_type_properly(
203
        AdjustmentInterface $orderPromotionAdjustment,
204
        AdjustmentInterface $orderTaxAdjustment,
205
        OrderItemInterface $item
206
    ): void {
207
        $orderPromotionAdjustment->getType()->willReturn('promotion');
208
        $orderPromotionAdjustment->isNeutral()->willReturn(true);
209
        $orderPromotionAdjustment->isLocked()->willReturn(false);
210
        $orderPromotionAdjustment->setAdjustable($this)->shouldBeCalled();
211
        $orderPromotionAdjustment->getAmount()->willReturn(420);
212
        $orderPromotionAdjustment->setAdjustable(Argument::any())->will(function () {});
213
214
        $orderTaxAdjustment->getType()->willReturn('tax');
215
        $orderTaxAdjustment->isNeutral()->willReturn(true);
216
        $orderTaxAdjustment->isLocked()->willReturn(false);
217
        $orderTaxAdjustment->setAdjustable($this)->shouldBeCalled();
218
        $orderTaxAdjustment->getAmount()->willReturn(420);
219
        $orderTaxAdjustment->setAdjustable(Argument::any())->will(function () {});
220
221
        $item->getTotal()->willReturn(666);
222
        $item->setOrder($this)->will(function () {});
223
224
        $this->addAdjustment($orderPromotionAdjustment);
225
        $this->addAdjustment($orderTaxAdjustment);
226
        $this->addItem($item);
227
228
        $item->removeAdjustmentsRecursively('tax')->shouldBeCalled();
229
        $orderTaxAdjustment->setAdjustable(null)->shouldBeCalled();
230
231
        $this->removeAdjustmentsRecursively('tax');
232
233
        $this->hasAdjustment($orderPromotionAdjustment)->shouldReturn(true);
234
        $this->hasAdjustment($orderTaxAdjustment)->shouldReturn(false);
235
    }
236
237
    function it_returns_adjustments_recursively(
238
        AdjustmentInterface $orderAdjustment,
239
        AdjustmentInterface $itemAdjustment1,
240
        AdjustmentInterface $itemAdjustment2,
241
        OrderItemInterface $item1,
242
        OrderItemInterface $item2
243
    ): void {
244
        $item1->setOrder($this)->shouldBeCalled();
245
        $item1->getTotal()->willReturn(100);
246
        $item1->getAdjustmentsRecursively(null)->willReturn(new ArrayCollection([$itemAdjustment1->getWrappedObject()]));
0 ignored issues
show
Bug introduced by
The method getWrappedObject() does not seem to exist on object<Sylius\Component\...el\AdjustmentInterface>.

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
        $item2->setOrder($this)->shouldBeCalled();
249
        $item2->getTotal()->willReturn(100);
250
        $item2->getAdjustmentsRecursively(null)->willReturn(new ArrayCollection([$itemAdjustment2->getWrappedObject()]));
0 ignored issues
show
Bug introduced by
The method getWrappedObject() does not seem to exist on object<Sylius\Component\...el\AdjustmentInterface>.

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...
251
252
        $this->addItem($item1);
253
        $this->addItem($item2);
254
255
        $orderAdjustment->setAdjustable($this)->shouldBeCalled();
256
        $orderAdjustment->isNeutral()->willReturn(true);
257
258
        $this->addAdjustment($orderAdjustment);
259
260
        $this->getAdjustmentsRecursively()->shouldIterateAs([$orderAdjustment, $itemAdjustment1, $itemAdjustment2]);
261
    }
262
263
    function it_has_adjustments_total_equal_to_0_by_default(): void
264
    {
265
        $this->getAdjustmentsTotal()->shouldReturn(0);
266
    }
267
268
    function it_calculates_correct_adjustments_total(
269
        AdjustmentInterface $adjustment1,
270
        AdjustmentInterface $adjustment2,
271
        AdjustmentInterface $adjustment3
272
    ): void {
273
        $adjustment1->getAmount()->willReturn(10000);
274
        $adjustment2->getAmount()->willReturn(-4999);
275
        $adjustment3->getAmount()->willReturn(1929);
276
277
        $adjustment1->isNeutral()->willReturn(false);
278
        $adjustment2->isNeutral()->willReturn(false);
279
        $adjustment3->isNeutral()->willReturn(false);
280
281
        $adjustment1->setAdjustable($this)->shouldBeCalled();
282
        $adjustment2->setAdjustable($this)->shouldBeCalled();
283
        $adjustment3->setAdjustable($this)->shouldBeCalled();
284
285
        $this->addAdjustment($adjustment1);
286
        $this->addAdjustment($adjustment2);
287
        $this->addAdjustment($adjustment3);
288
289
        $this->getAdjustmentsTotal()->shouldReturn(6930);
290
    }
291
292
    function it_returns_adjustments_total_recursively(
293
        AdjustmentInterface $itemAdjustment,
294
        AdjustmentInterface $orderAdjustment,
295
        OrderItemInterface $orderItem
296
    ): void {
297
        $itemAdjustment->getAmount()->willReturn(10000);
298
        $orderAdjustment->getAmount()->willReturn(5000);
299
300
        $itemAdjustment->isNeutral()->willReturn(false);
301
        $orderAdjustment->isNeutral()->willReturn(false);
302
303
        $orderAdjustment->setAdjustable($this)->shouldBeCalled();
304
305
        $orderItem->getAdjustmentsRecursively(null)->willReturn(new ArrayCollection([$itemAdjustment->getWrappedObject()]));
0 ignored issues
show
Bug introduced by
The method getWrappedObject() does not seem to exist on object<Sylius\Component\...el\AdjustmentInterface>.

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...
306
        $orderItem->setOrder($this)->shouldBeCalled();
307
        $orderItem->getTotal()->willReturn(15000);
308
309
        $this->addItem($orderItem);
310
        $this->addAdjustment($orderAdjustment);
311
312
        $this->getAdjustmentsTotalRecursively()->shouldReturn(15000);
313
    }
314
315
    function it_has_total_equal_to_0_by_default(): void
316
    {
317
        $this->getTotal()->shouldReturn(0);
318
    }
319
320
    function it_has_total_quantity(OrderItemInterface $orderItem1, OrderItemInterface $orderItem2): void
321
    {
322
        $orderItem1->getQuantity()->willReturn(10);
323
        $orderItem1->setOrder($this)->shouldBeCalled();
324
        $orderItem1->getTotal()->willReturn(500);
325
326
        $orderItem2->getQuantity()->willReturn(30);
327
        $orderItem2->setOrder($this)->shouldBeCalled();
328
        $orderItem2->equals($orderItem1)->willReturn(false);
329
        $orderItem2->getTotal()->willReturn(1000);
330
331
        $this->addItem($orderItem1);
332
        $this->addItem($orderItem2);
333
334
        $this->getTotalQuantity()->shouldReturn(40);
335
    }
336
337
    function it_calculates_correct_total(
338
        OrderItemInterface $item1,
339
        OrderItemInterface $item2,
340
        AdjustmentInterface $adjustment1,
341
        AdjustmentInterface $adjustment2
342
    ): void {
343
        $item1->getTotal()->willReturn(29999);
344
        $item2->getTotal()->willReturn(45000);
345
346
        $item1->equals(Argument::any())->willReturn(false);
347
        $item2->equals(Argument::any())->willReturn(false);
348
349
        $item1->setOrder($this)->shouldBeCalled();
350
        $item2->setOrder($this)->shouldBeCalled();
351
352
        $adjustment1->isNeutral()->willReturn(false);
353
        $adjustment1->getAmount()->willReturn(10000);
354
        $adjustment2->isNeutral()->willReturn(false);
355
        $adjustment2->getAmount()->willReturn(-4999);
356
357
        $adjustment1->setAdjustable($this)->shouldBeCalled();
358
        $adjustment2->setAdjustable($this)->shouldBeCalled();
359
360
        $this->addItem($item1);
361
        $this->addItem($item2);
362
        $this->addAdjustment($adjustment1);
363
        $this->addAdjustment($adjustment2);
364
365
        $this->getTotal()->shouldReturn(80000);
366
    }
367
368
    function it_calculates_correct_total_after_items_and_adjustments_changes(
369
        AdjustmentInterface $adjustment1,
370
        AdjustmentInterface $adjustment2,
371
        OrderItemInterface $item1,
372
        OrderItemInterface $item2,
373
        OrderItemInterface $item3
374
    ): void {
375
        $item1->getTotal()->willReturn(29999);
376
        $item2->getTotal()->willReturn(45000);
377
378
        $item1->equals(Argument::any())->willReturn(false);
379
        $item2->equals(Argument::any())->willReturn(false);
380
381
        $item1->setOrder($this)->shouldBeCalled();
382
        $item2->setOrder($this)->shouldBeCalled();
383
384
        $adjustment1->isNeutral()->willReturn(false);
385
        $adjustment1->getAmount()->willReturn(10000);
386
        $adjustment1->setAdjustable($this)->shouldBeCalled();
387
388
        $this->addItem($item1);
389
        $this->addItem($item2);
390
        $this->addAdjustment($adjustment1);
391
392
        $this->getTotal()->shouldReturn(84999);
393
394
        $item2->setOrder(null)->shouldBeCalled();
395
396
        $this->removeItem($item2);
397
398
        $adjustment1->setAdjustable(null)->shouldBeCalled();
399
        $adjustment1->isLocked()->willReturn(false);
400
401
        $adjustment2->isNeutral()->willReturn(false);
402
        $adjustment2->getAmount()->willReturn(-4999);
403
        $adjustment2->setAdjustable($this)->shouldBeCalled();
404
405
        $this->removeAdjustment($adjustment1);
406
        $this->addAdjustment($adjustment2);
407
408
        $item3->getTotal()->willReturn(55000);
409
        $item3->equals(Argument::any())->willReturn(false);
410
        $item3->setOrder($this)->shouldBeCalled();
411
412
        $this->addItem($item3);
413
414
        $this->getTotal()->shouldReturn(80000);
415
    }
416
417
    function it_ignores_neutral_adjustments_when_calculating_total(
418
        OrderItemInterface $item1,
419
        OrderItemInterface $item2,
420
        AdjustmentInterface $adjustment1,
421
        AdjustmentInterface $adjustment2
422
    ): void {
423
        $item1->getTotal()->willReturn(29999);
424
        $item2->getTotal()->willReturn(45000);
425
426
        $item1->equals(Argument::any())->willReturn(false);
427
        $item2->equals(Argument::any())->willReturn(false);
428
429
        $item1->setOrder($this)->shouldBeCalled();
430
        $item2->setOrder($this)->shouldBeCalled();
431
432
        $adjustment1->isNeutral()->willReturn(true);
433
        $adjustment1->getAmount()->willReturn(10000);
434
        $adjustment2->isNeutral()->willReturn(false);
435
        $adjustment2->getAmount()->willReturn(-4999);
436
437
        $adjustment1->setAdjustable($this)->shouldBeCalled();
438
        $adjustment2->setAdjustable($this)->shouldBeCalled();
439
440
        $this->addItem($item1);
441
        $this->addItem($item2);
442
        $this->addAdjustment($adjustment1);
443
        $this->addAdjustment($adjustment2);
444
445
        $this->getTotal()->shouldReturn(70000);
446
    }
447
448
    function it_calculates_correct_total_when_adjustment_is_bigger_than_cost(
449
        OrderItemInterface $item,
450
        AdjustmentInterface $adjustment
451
    ): void {
452
        $item->getTotal()->willReturn(45000);
453
454
        $item->equals(Argument::any())->willReturn(false);
455
456
        $item->setOrder($this)->shouldBeCalled();
457
458
        $adjustment->isNeutral()->willReturn(false);
459
        $adjustment->getAmount()->willReturn(-100000);
460
461
        $adjustment->setAdjustable($this)->shouldBeCalled();
462
463
        $this->addItem($item);
464
        $this->addAdjustment($adjustment);
465
466
        $this->getTotal()->shouldReturn(0);
467
    }
468
469
    function it_initializes_creation_date_by_default(): void
470
    {
471
        $this->getCreatedAt()->shouldHaveType(\DateTimeInterface::class);
472
    }
473
474
    function it_has_no_last_update_date_by_default(): void
475
    {
476
        $this->getUpdatedAt()->shouldReturn(null);
477
    }
478
479
    function it_is_empty_by_default(): void
480
    {
481
        $this->countItems()->shouldReturn(0);
482
        $this->isEmpty()->shouldReturn(true);
483
    }
484
485
    function it_clears_items(OrderItemInterface $item): void
486
    {
487
        $item->getTotal()->willReturn(420);
488
        $item->setOrder($this)->will(function () {});
489
490
        $this->addItem($item);
491
        $this->clearItems();
492
493
        $this->isEmpty()->shouldReturn(true);
494
        $this->getTotal()->shouldReturn(0);
495
    }
496
497
    function it_has_notes(): void
498
    {
499
        $this->setNotes('something squishy');
500
        $this->getNotes()->shouldReturn('something squishy');
501
    }
502
}
503