Completed
Push — master ( d81c19...f57266 )
by Kamil
20s
created

src/Sylius/Behat/Context/Setup/OrderContext.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 Sylius\Behat\Context\Setup;
15
16
use Behat\Behat\Context\Context;
17
use Doctrine\Common\Persistence\ObjectManager;
18
use SM\Factory\FactoryInterface as StateMachineFactoryInterface;
19
use Sylius\Behat\Service\SharedStorageInterface;
20
use Sylius\Component\Core\Model\AddressInterface;
21
use Sylius\Component\Core\Model\ChannelInterface;
22
use Sylius\Component\Core\Model\ChannelPricingInterface;
23
use Sylius\Component\Core\Model\OrderInterface;
24
use Sylius\Component\Core\Model\OrderItemInterface;
25
use Sylius\Component\Core\Model\ProductInterface;
26
use Sylius\Component\Core\Model\ProductVariantInterface;
27
use Sylius\Component\Core\Model\PromotionCouponInterface;
28
use Sylius\Component\Core\Model\ShippingMethodInterface;
29
use Sylius\Component\Core\Model\ShopUserInterface;
30
use Sylius\Component\Core\OrderCheckoutTransitions;
31
use Sylius\Component\Core\OrderPaymentTransitions;
32
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
33
use Sylius\Component\Customer\Model\CustomerInterface;
34
use Sylius\Component\Order\Modifier\OrderItemQuantityModifierInterface;
35
use Sylius\Component\Order\OrderTransitions;
36
use Sylius\Component\Payment\Model\PaymentInterface;
37
use Sylius\Component\Payment\Model\PaymentMethodInterface;
38
use Sylius\Component\Payment\PaymentTransitions;
39
use Sylius\Component\Product\Resolver\ProductVariantResolverInterface;
40
use Sylius\Component\Resource\Factory\FactoryInterface;
41
use Sylius\Component\Resource\Repository\RepositoryInterface;
42
use Sylius\Component\Shipping\ShipmentTransitions;
43
44
final class OrderContext implements Context
45
{
46
    /**
47
     * @var SharedStorageInterface
48
     */
49
    private $sharedStorage;
50
51
    /**
52
     * @var OrderRepositoryInterface
53
     */
54
    private $orderRepository;
55
56
    /**
57
     * @var FactoryInterface
58
     */
59
    private $orderFactory;
60
61
    /**
62
     * @var FactoryInterface
63
     */
64
    private $orderItemFactory;
65
66
    /**
67
     * @var OrderItemQuantityModifierInterface
68
     */
69
    private $itemQuantityModifier;
70
71
    /**
72
     * @var FactoryInterface
73
     */
74
    private $customerFactory;
75
76
    /**
77
     * @var RepositoryInterface
78
     */
79
    private $customerRepository;
80
81
    /**
82
     * @var ObjectManager
83
     */
84
    private $objectManager;
85
86
    /**
87
     * @var StateMachineFactoryInterface
88
     */
89
    private $stateMachineFactory;
90
91
    /**
92
     * @var ProductVariantResolverInterface
93
     */
94
    private $variantResolver;
95
96
    /**
97
     * @param SharedStorageInterface $sharedStorage
98
     * @param OrderRepositoryInterface $orderRepository
99
     * @param FactoryInterface $orderFactory
100
     * @param FactoryInterface $orderItemFactory
101
     * @param OrderItemQuantityModifierInterface $itemQuantityModifier
102
     * @param FactoryInterface $customerFactory
103
     * @param RepositoryInterface $customerRepository
104
     * @param ObjectManager $objectManager
105
     * @param StateMachineFactoryInterface $stateMachineFactory
106
     * @param ProductVariantResolverInterface $variantResolver
107
     */
108
    public function __construct(
109
        SharedStorageInterface $sharedStorage,
110
        OrderRepositoryInterface $orderRepository,
111
        FactoryInterface $orderFactory,
112
        FactoryInterface $orderItemFactory,
113
        OrderItemQuantityModifierInterface $itemQuantityModifier,
114
        FactoryInterface $customerFactory,
115
        RepositoryInterface $customerRepository,
116
        ObjectManager $objectManager,
117
        StateMachineFactoryInterface $stateMachineFactory,
118
        ProductVariantResolverInterface $variantResolver
119
    ) {
120
        $this->sharedStorage = $sharedStorage;
121
        $this->orderRepository = $orderRepository;
122
        $this->orderFactory = $orderFactory;
123
        $this->orderItemFactory = $orderItemFactory;
124
        $this->itemQuantityModifier = $itemQuantityModifier;
125
        $this->customerFactory = $customerFactory;
126
        $this->customerRepository = $customerRepository;
127
        $this->objectManager = $objectManager;
128
        $this->stateMachineFactory = $stateMachineFactory;
129
        $this->variantResolver = $variantResolver;
130
    }
131
132
    /**
133
     * @Given /^there is (?:a|another) (customer "[^"]+") that placed an order$/
134
     * @Given /^there is (?:a|another) (customer "[^"]+") that placed (an order "[^"]+")$/
135
     * @Given a customer :customer placed an order :orderNumber
136
     * @Given the customer :customer has already placed an order :orderNumber
137
     */
138
    public function thereIsCustomerThatPlacedOrder(CustomerInterface $customer, $orderNumber = null)
139
    {
140
        $order = $this->createOrder($customer, $orderNumber);
141
142
        $this->sharedStorage->set('order', $order);
143
144
        $this->orderRepository->add($order);
145
    }
146
147
    /**
148
     * @Given /^the guest customer placed order with ("[^"]+" product) for "([^"]+)" and ("[^"]+" based shipping address) with ("[^"]+" shipping method) and ("[^"]+" payment)$/
149
     */
150
    public function theGuestCustomerPlacedOrderWithForAndBasedShippingAddress(
151
        ProductInterface $product,
152
        string $email,
153
        AddressInterface $address,
154
        ShippingMethodInterface $shippingMethod,
155
        PaymentMethodInterface $paymentMethod
156
    ) {
157
        /** @var CustomerInterface $customer */
158
        $customer = $this->customerFactory->createNew();
159
        $customer->setEmail($email);
160
        $customer->setFirstName('John');
161
        $customer->setLastName('Doe');
162
163
        $this->customerRepository->add($customer);
164
165
        $this->placeOrder($product, $shippingMethod, $address, $paymentMethod, $customer, 1);
166
        $this->objectManager->flush();
167
    }
168
169
    /**
170
     * @Given a customer :customer added something to cart
171
     */
172
    public function customerStartedCheckout(CustomerInterface $customer)
173
    {
174
        $cart = $this->createCart($customer);
175
176
        $this->sharedStorage->set('cart', $cart);
177
178
        $this->orderRepository->add($cart);
179
    }
180
181
    /**
182
     * @Given /^(I) placed (an order "[^"]+")$/
183
     */
184
    public function iPlacedAnOrder(ShopUserInterface $user, $orderNumber)
185
    {
186
        $customer = $user->getCustomer();
187
        $order = $this->createOrder($customer, $orderNumber);
188
189
        $this->sharedStorage->set('order', $order);
190
191
        $this->orderRepository->add($order);
192
    }
193
194
    /**
195
     * @Given /^the customer ("[^"]+" addressed it to "[^"]+", "[^"]+" "[^"]+" in the "[^"]+"(?:|, "[^"]+"))$/
196
     * @Given /^I (addressed it to "[^"]+", "[^"]+", "[^"]+" "[^"]+" in the "[^"]+"(?:|, "[^"]+"))$/
197
     */
198
    public function theCustomerAddressedItTo(AddressInterface $address)
199
    {
200
        /** @var OrderInterface $order */
201
        $order = $this->sharedStorage->get('order');
202
        $order->setShippingAddress($address);
203
204
        $this->objectManager->flush();
205
    }
206
207
    /**
208
     * @Given the customer changed shipping address' street to :street
209
     */
210
    public function theCustomerChangedShippingAddressStreetTo($street)
211
    {
212
        /** @var OrderInterface $order */
213
        $order = $this->sharedStorage->get('order');
214
215
        $shippingAddress = $order->getShippingAddress();
216
        $shippingAddress->setStreet($street);
217
218
        $this->objectManager->flush();
219
220
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_ADDRESS);
221
    }
222
223
    /**
224
     * @Given /^the customer set the billing (address as "([^"]+)", "([^"]+)", "([^"]+)", "([^"]+)", "([^"]+)")$/
225
     * @Given /^for the billing address (of "[^"]+" in the "[^"]+", "[^"]+" "[^"]+", "[^"]+")$/
226
     * @Given /^for the billing address (of "[^"]+" in the "[^"]+", "[^"]+" "([^"]+)", "[^"]+", "[^"]+")$/
227
     */
228
    public function forTheBillingAddressOf(AddressInterface $address)
229
    {
230
        /** @var OrderInterface $order */
231
        $order = $this->sharedStorage->get('order');
232
233
        $order->setBillingAddress($address);
234
235
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_ADDRESS);
236
237
        $this->objectManager->flush();
238
    }
239
240
    /**
241
     * @Given /^the customer ("[^"]+" addressed it to "[^"]+", "[^"]+" "[^"]+" in the "[^"]+") with identical billing address$/
242
     * @Given /^I (addressed it to "[^"]+", "[^"]+", "[^"]+" "[^"]+" in the "[^"]+") with identical billing address$/
243
     */
244
    public function theCustomerAddressedItToWithIdenticalBillingAddress(AddressInterface $address)
245
    {
246
        $this->theCustomerAddressedItTo($address);
247
        $this->forTheBillingAddressOf(clone $address);
248
    }
249
250
    /**
251
     * @Given /^the customer chose ("[^"]+" shipping method) (to "[^"]+") with ("[^"]+" payment)$/
252
     * @Given /^I chose ("[^"]+" shipping method) (to "[^"]+") with ("[^"]+" payment)$/
253
     */
254
    public function theCustomerChoseShippingToWithPayment(
255
        ShippingMethodInterface $shippingMethod,
256
        AddressInterface $address,
257
        PaymentMethodInterface $paymentMethod
258
    ) {
259
        /** @var OrderInterface $order */
260
        $order = $this->sharedStorage->get('order');
261
262
        $this->checkoutUsing($order, $shippingMethod, $address, $paymentMethod);
263
264
        $this->objectManager->flush();
265
    }
266
267
    /**
268
     * @Given /^the customer chose ("[^"]+" shipping method) with ("[^"]+" payment)$/
269
     * @Given /^I chose ("[^"]+" shipping method) with ("[^"]+" payment)$/
270
     */
271
    public function theCustomerChoseShippingWithPayment(
272
        ShippingMethodInterface $shippingMethod,
273
        PaymentMethodInterface $paymentMethod
274
    ) {
275
        /** @var OrderInterface $order */
276
        $order = $this->sharedStorage->get('order');
277
278
        $this->proceedSelectingShippingAndPaymentMethod($order, $shippingMethod, $paymentMethod);
279
280
        $this->objectManager->flush();
281
    }
282
283
    /**
284
     * @Given /^the customer chose ("[^"]+" shipping method)$/
285
     */
286
    public function theCustomerChoseShippingMethod(ShippingMethodInterface $shippingMethod)
287
    {
288
        /** @var OrderInterface $order */
289
        $order = $this->sharedStorage->get('order');
290
291
        foreach ($order->getShipments() as $shipment) {
292
            $shipment->setMethod($shippingMethod);
293
        }
294
295
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_SELECT_SHIPPING);
296
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_COMPLETE);
297
        if (!$order->getPayments()->isEmpty()) {
298
            $this->stateMachineFactory->get($order, OrderPaymentTransitions::GRAPH)->apply(OrderPaymentTransitions::TRANSITION_PAY);
299
        }
300
301
        $this->objectManager->flush();
302
    }
303
304
    /**
305
     * @Given /^the customer chose ("[^"]+" payment)$/
306
     */
307
    public function theCustomerChosePayment(PaymentMethodInterface $paymentMethod)
308
    {
309
        /** @var OrderInterface $order */
310
        $order = $this->sharedStorage->get('order');
311
312
        foreach ($order->getPayments() as $payment) {
313
            $payment->setMethod($paymentMethod);
314
        }
315
316
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT);
317
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_COMPLETE);
318
319
        $this->objectManager->flush();
320
    }
321
322
    /**
323
     * @Given the customer bought a single :product
324
     * @Given I bought a single :product
325
     */
326
    public function theCustomerBoughtSingleProduct(ProductInterface $product)
327
    {
328
        $this->addProductVariantToOrder($this->variantResolver->getVariant($product), 1);
329
330
        $this->objectManager->flush();
331
    }
332
333
    /**
334
     * @Given /^the customer bought ((?:a|an) "[^"]+") and ((?:a|an) "[^"]+")$/
335
     * @Given /^I bought ((?:a|an) "[^"]+") and ((?:a|an) "[^"]+")$/
336
     */
337
    public function theCustomerBoughtProductAndProduct(ProductInterface $product, ProductInterface $secondProduct)
338
    {
339
        $this->theCustomerBoughtSingleProduct($product);
340
        $this->theCustomerBoughtSingleProduct($secondProduct);
341
    }
342
343
    /**
344
     * @Given /^the customer bought (\d+) ("[^"]+" products)$/
345
     */
346
    public function theCustomerBoughtSeveralProducts($quantity, ProductInterface $product)
347
    {
348
        $variant = $this->variantResolver->getVariant($product);
349
        $this->addProductVariantToOrder($variant, $quantity);
350
351
        $this->objectManager->flush();
352
    }
353
354
    /**
355
     * @Given /^the customer bought ([^"]+) units of ("[^"]+" variant of product "[^"]+")$/
356
     */
357
    public function theCustomerBoughtSeveralVariantsOfProduct($quantity, ProductVariantInterface $variant)
358
    {
359
        $this->addProductVariantToOrder($variant, $quantity);
360
361
        $this->objectManager->flush();
362
    }
363
364
    /**
365
     * @Given /^the customer bought a single ("[^"]+" variant of product "[^"]+")$/
366
     */
367
    public function theCustomerBoughtSingleProductVariant(ProductVariantInterface $productVariant)
368
    {
369
        $this->addProductVariantToOrder($productVariant);
370
371
        $this->objectManager->flush();
372
    }
373
374
    /**
375
     * @Given the customer bought a single :product using :coupon coupon
376
     * @Given I bought a single :product using :coupon coupon
377
     */
378
    public function theCustomerBoughtSingleUsing(ProductInterface $product, PromotionCouponInterface $coupon)
379
    {
380
        $order = $this->addProductVariantToOrder($this->variantResolver->getVariant($product));
381
        $order->setPromotionCoupon($coupon);
382
383
        $this->objectManager->flush();
384
    }
385
386
    /**
387
     * @Given I used :coupon coupon
388
     */
389
    public function iUsedCoupon(PromotionCouponInterface $coupon)
390
    {
391
        $order = $this->sharedStorage->get('order');
392
        $order->setPromotionCoupon($coupon);
393
394
        $this->objectManager->flush();
395
    }
396
397
    /**
398
     * @Given /^(I) have already placed (\d+) orders choosing ("[^"]+" product), ("[^"]+" shipping method) (to "[^"]+") with ("[^"]+" payment)$/
399
     */
400
    public function iHaveAlreadyPlacedOrderNthTimes(
401
        ShopUserInterface $user,
402
        $numberOfOrders,
403
        ProductInterface $product,
404
        ShippingMethodInterface $shippingMethod,
405
        AddressInterface $address,
406
        PaymentMethodInterface $paymentMethod
407
    ) {
408
        $customer = $user->getCustomer();
409
        for ($i = 0; $i < $numberOfOrders; ++$i) {
410
            $this->placeOrder($product, $shippingMethod, $address, $paymentMethod, $customer, $i);
411
        }
412
413
        $this->objectManager->flush();
414
    }
415
416
    /**
417
     * @Given /^(this customer) has(?:| also) placed (an order "[^"]+") at "([^"]+)"$/
418
     */
419
    public function thisCustomerHasPlacedAnOrderAtDate(CustomerInterface $customer, $number, $checkoutCompletedAt)
420
    {
421
        $order = $this->createOrder($customer, $number);
422
        $order->setCheckoutCompletedAt(new \DateTime($checkoutCompletedAt));
423
        $order->setState(OrderInterface::STATE_NEW);
424
425
        $this->orderRepository->add($order);
426
    }
427
428
    /**
429
     * @Given /^(this customer) has(?:| also) placed (an order "[^"]+") on a (channel "[^"]+")$/
430
     */
431
    public function thisCustomerHasPlacedAnOrderOnAChannel(CustomerInterface $customer, $number, $channel)
432
    {
433
        $order = $this->createOrder($customer, $number, $channel);
434
        $order->setState(OrderInterface::STATE_NEW);
435
436
        $this->orderRepository->add($order);
437
        $this->sharedStorage->set('order', $order);
438
    }
439
440
    /**
441
     * @Given /^(this customer) has(?:| also) started checkout on a (channel "[^"]+")$/
442
     */
443
    public function thisCustomerHasStartedCheckoutOnAChannel(CustomerInterface $customer, $channel)
444
    {
445
        $order = $this->createOrder($customer, null, $channel);
446
447
        $this->orderRepository->add($order);
448
        $this->sharedStorage->set('order', $order);
449
    }
450
451
    /**
452
     * @Given /^(customer "[^"]+"|this customer) has(?:| also) placed (\d+) orders on the ("[^"]+" channel) in each buying (\d+) ("[^"]+" products?)$/
453
     */
454
    public function thisCustomerPlacedOrdersOnChannelBuyingProducts(
455
        CustomerInterface $customer,
456
        int $orderCount,
457
        ChannelInterface $channel,
458
        int $productCount,
459
        ProductInterface $product
460
    ): void {
461
        $this->createOrdersForCustomer($customer, $orderCount, $channel, $productCount, $product);
462
    }
463
464
    /**
465
     * @Given /^(customer "[^"]+"|this customer) has(?:| also) fulfilled (\d+) orders placed on the ("[^"]+" channel) in each buying (\d+) ("[^"]+" products?)$/
466
     */
467
    public function thisCustomerFulfilledOrdersPlacedOnChannelBuyingProducts(
468
        CustomerInterface $customer,
469
        int $orderCount,
470
        ChannelInterface $channel,
471
        int $productCount,
472
        ProductInterface $product
473
    ): void {
474
        $this->createOrdersForCustomer($customer, $orderCount, $channel, $productCount, $product, true);
475
    }
476
477
    /**
478
     * @Given :numberOfCustomers customers have added products to the cart for total of :total
479
     */
480
    public function customersHaveAddedProductsToTheCartForTotalOf($numberOfCustomers, $total)
481
    {
482
        $customers = $this->generateCustomers($numberOfCustomers);
483
484
        $sampleProductVariant = $this->sharedStorage->get('variant');
485
        $total = $this->getPriceFromString($total);
486
487
        for ($i = 0; $i < $numberOfCustomers; ++$i) {
488
            $order = $this->createCart($customers[random_int(0, $numberOfCustomers - 1)]);
489
490
            $price = $i === ($numberOfCustomers - 1) ? $total : random_int(1, $total);
491
            $total -= $price;
492
493
            $this->addVariantWithPriceToOrder($order, $sampleProductVariant, $price);
494
495
            $this->objectManager->persist($order);
496
        }
497
498
        $this->objectManager->flush();
499
    }
500
501
    /**
502
     * @Given a single customer has placed an order for total of :total
503
     * @Given :numberOfCustomers customers have placed :numberOfOrders orders for total of :total
504
     * @Given then :numberOfCustomers more customers have placed :numberOfOrders orders for total of :total
505
     */
506
    public function customersHavePlacedOrdersForTotalOf(
507
        int $numberOfCustomers = 1,
508
        int $numberOfOrders = 1,
509
        string $total
510
    ): void {
511
        $this->createOrders($numberOfCustomers, $numberOfOrders, $total);
512
    }
513
514
    /**
515
     * @Given :numberOfCustomers customers have fulfilled :numberOfOrders orders placed for total of :total
516
     * @Given then :numberOfCustomers more customers have fulfilled :numberOfOrders orders placed for total of :total
517
     */
518
    public function customersHaveFulfilledOrdersPlacedForTotalOf(
519
        int $numberOfCustomers,
520
        int $numberOfOrders,
521
        string $total
522
    ): void {
523
        $this->createOrders($numberOfCustomers, $numberOfOrders, $total, true);
524
    }
525
526
    /**
527
     * @Given :numberOfCustomers customers have placed :numberOfOrders orders for total of :total mostly :product product
528
     * @Given then :numberOfCustomers more customers have placed :numberOfOrders orders for total of :total mostly :product product
529
     */
530
    public function customersHavePlacedOrdersForTotalOfMostlyProduct(
531
        int $numberOfCustomers,
532
        int $numberOfOrders,
533
        string $total,
534
        ProductInterface $product
535
    ): void {
536
        $this->createOrdersWithProduct($numberOfCustomers, $numberOfOrders, $total, $product);
537
    }
538
539
    /**
540
     * @Given :numberOfCustomers customers have fulfilled :numberOfOrders orders placed for total of :total mostly :product product
541
     * @Given then :numberOfCustomers more customers have fulfilled :numberOfOrders orders placed for total of :total mostly :product product
542
     */
543
    public function customersHaveFulfilledOrdersPlacedForTotalOfMostlyProduct(
544
        int $numberOfCustomers,
545
        int $numberOfOrders,
546
        string $total,
547
        ProductInterface $product
548
    ): void {
549
        $this->createOrdersWithProduct($numberOfCustomers, $numberOfOrders, $total, $product, true);
550
    }
551
552
    /**
553
     * @Given /^(this customer) has(?:| also) placed (an order "[^"]+") buying a single ("[^"]+" product) for ("[^"]+") on the ("[^"]+" channel)$/
554
     */
555
    public function customerHasPlacedAnOrderBuyingASingleProductForOnTheChannel(
556
        CustomerInterface $customer,
557
        $orderNumber,
558
        ProductInterface $product,
559
        $price,
560
        ChannelInterface $channel
561
    ) {
562
        $order = $this->createOrder($customer, $orderNumber, $channel);
563
        $order->setState(OrderInterface::STATE_NEW);
564
565
        $this->addVariantWithPriceToOrder($order, $product->getVariants()->first(), $price);
566
567
        $this->orderRepository->add($order);
568
        $this->sharedStorage->set('order', $order);
569
    }
570
571
    /**
572
     * @Given /^(this order) is already paid$/
573
     * @Given the order :order is already paid
574
     */
575
    public function thisOrderIsAlreadyPaid(OrderInterface $order)
576
    {
577
        $this->applyPaymentTransitionOnOrder($order, PaymentTransitions::TRANSITION_COMPLETE);
578
579
        $this->objectManager->flush();
580
    }
581
582
    /**
583
     * @Given /^(this order) has been refunded$/
584
     */
585
    public function thisOrderHasBeenRefunded(OrderInterface $order)
586
    {
587
        $this->applyPaymentTransitionOnOrder($order, PaymentTransitions::TRANSITION_REFUND);
588
589
        $this->objectManager->flush();
590
    }
591
592
    /**
593
     * @Given /^the customer cancelled (this order)$/
594
     * @Given /^(this order) was cancelled$/
595
     * @Given the order :order was cancelled
596
     * @Given /^I cancelled (this order)$/
597
     */
598
    public function theCustomerCancelledThisOrder(OrderInterface $order)
599
    {
600
        $this->stateMachineFactory->get($order, OrderTransitions::GRAPH)->apply(OrderTransitions::TRANSITION_CANCEL);
601
602
        $this->objectManager->flush();
603
    }
604
605
    /**
606
     * @Given /^I cancelled my last order$/
607
     */
608
    public function theCustomerCancelledMyLastOrder()
609
    {
610
        $order = $this->sharedStorage->get('order');
611
        $this->stateMachineFactory->get($order, OrderTransitions::GRAPH)->apply(OrderTransitions::TRANSITION_CANCEL);
612
613
        $this->objectManager->flush();
614
    }
615
616
    /**
617
     * @Given /^(this order) has already been shipped$/
618
     */
619
    public function thisOrderHasAlreadyBeenShipped(OrderInterface $order)
620
    {
621
        $this->applyShipmentTransitionOnOrder($order, ShipmentTransitions::TRANSITION_SHIP);
622
623
        $this->objectManager->flush();
624
    }
625
626
    /**
627
     * @When the customer used coupon :coupon
628
     */
629
    public function theCustomerUsedCoupon(PromotionCouponInterface $coupon)
630
    {
631
        /** @var OrderInterface $order */
632
        $order = $this->sharedStorage->get('order');
633
        $order->setPromotionCoupon($coupon);
634
635
        $this->objectManager->flush();
636
    }
637
638
    /**
639
     * @param OrderInterface $order
640
     * @param string $transition
641
     */
642
    private function applyShipmentTransitionOnOrder(OrderInterface $order, $transition)
643
    {
644
        foreach ($order->getShipments() as $shipment) {
645
            $this->stateMachineFactory->get($shipment, ShipmentTransitions::GRAPH)->apply($transition);
646
        }
647
    }
648
649
    /**
650
     * @param OrderInterface $order
651
     * @param string $transition
652
     */
653
    private function applyPaymentTransitionOnOrder(OrderInterface $order, $transition)
654
    {
655
        foreach ($order->getPayments() as $payment) {
656
            $this->stateMachineFactory->get($payment, PaymentTransitions::GRAPH)->apply($transition);
657
        }
658
    }
659
660
    /**
661
     * @param OrderInterface $order
662
     * @param string $transition
663
     */
664
    private function applyTransitionOnOrderCheckout(OrderInterface $order, $transition)
665
    {
666
        $this->stateMachineFactory->get($order, OrderCheckoutTransitions::GRAPH)->apply($transition);
667
    }
668
669
    /**
670
     * @param OrderInterface $order
671
     * @param string $transition
672
     */
673
    private function applyTransitionOnOrder(OrderInterface $order, string $transition): void
674
    {
675
        $this->stateMachineFactory->get($order, OrderTransitions::GRAPH)->apply($transition);
676
    }
677
678
    /**
679
     * @param ProductVariantInterface $productVariant
680
     * @param int $quantity
681
     *
682
     * @return OrderInterface
683
     */
684
    private function addProductVariantToOrder(ProductVariantInterface $productVariant, $quantity = 1)
685
    {
686
        $order = $this->sharedStorage->get('order');
687
688
        $this->addProductVariantsToOrderWithChannelPrice(
689
            $order,
690
            $this->sharedStorage->get('channel'),
691
            $productVariant,
692
            (int) $quantity
693
        );
694
695
        return $order;
696
    }
697
698
    /**
699
     * @param OrderInterface $order
700
     * @param ChannelInterface $channel
701
     * @param ProductVariantInterface $productVariant
702
     * @param int $quantity
703
     */
704
    private function addProductVariantsToOrderWithChannelPrice(
705
        OrderInterface $order,
706
        ChannelInterface $channel,
707
        ProductVariantInterface $productVariant,
708
        int $quantity = 1
709
    ) {
710
        /** @var OrderItemInterface $item */
711
        $item = $this->orderItemFactory->createNew();
712
        $item->setVariant($productVariant);
713
714
        /** @var ChannelPricingInterface $channelPricing */
715
        $channelPricing = $productVariant->getChannelPricingForChannel($channel);
716
        $item->setUnitPrice($channelPricing->getPrice());
717
718
        $this->itemQuantityModifier->modify($item, $quantity);
719
720
        $order->addItem($item);
721
    }
722
723
    /**
724
     * @param CustomerInterface $customer
725
     * @param string $number
726
     * @param ChannelInterface|null $channel
727
     * @param string|null $localeCode
728
     *
729
     * @return OrderInterface
730
     */
731
    private function createOrder(
732
        CustomerInterface $customer,
733
        $number = null,
734
        ChannelInterface $channel = null,
735
        $localeCode = null
736
    ) {
737
        $order = $this->createCart($customer, $channel, $localeCode);
738
739
        if (null !== $number) {
740
            $order->setNumber($number);
741
        }
742
743
        $order->completeCheckout();
744
745
        return $order;
746
    }
747
748
    /**
749
     * @param CustomerInterface $customer
750
     * @param ChannelInterface|null $channel
751
     * @param string|null $localeCode
752
     *
753
     * @return OrderInterface
754
     */
755
    private function createCart(
756
        CustomerInterface $customer,
757
        ChannelInterface $channel = null,
758
        $localeCode = null
759
    ) {
760
        /** @var OrderInterface $order */
761
        $order = $this->orderFactory->createNew();
762
763
        $order->setCustomer($customer);
764
        $order->setChannel($channel ?? $this->sharedStorage->get('channel'));
765
        $order->setLocaleCode($localeCode ?? $this->sharedStorage->get('locale')->getCode());
766
        $order->setCurrencyCode($order->getChannel()->getBaseCurrency()->getCode());
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Sylius\Component\Channel\Model\ChannelInterface as the method getBaseCurrency() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\Channel.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
767
768
        return $order;
769
    }
770
771
    /**
772
     * @param int $count
773
     *
774
     * @return CustomerInterface[]
775
     */
776
    private function generateCustomers($count)
777
    {
778
        $customers = [];
779
780
        for ($i = 0; $i < $count; ++$i) {
781
            $customer = $this->customerFactory->createNew();
782
            $customer->setEmail(sprintf('john%[email protected]', uniqid()));
783
            $customer->setFirstname('John');
784
            $customer->setLastname('Doe' . $i);
785
786
            $customers[] = $customer;
787
788
            $this->customerRepository->add($customer);
789
        }
790
791
        return $customers;
792
    }
793
794
    /**
795
     * @param string $price
796
     *
797
     * @return int
798
     */
799
    private function getPriceFromString($price)
800
    {
801
        return (int) round(str_replace(['€', '£', '$'], '', $price) * 100, 2);
802
    }
803
804
    /**
805
     * @param OrderInterface $order
806
     * @param ShippingMethodInterface $shippingMethod
807
     * @param AddressInterface $address
808
     * @param PaymentMethodInterface $paymentMethod
809
     */
810
    private function checkoutUsing(
811
        OrderInterface $order,
812
        ShippingMethodInterface $shippingMethod,
813
        AddressInterface $address,
814
        PaymentMethodInterface $paymentMethod
815
    ) {
816
        $order->setShippingAddress($address);
817
        $order->setBillingAddress(clone $address);
818
819
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_ADDRESS);
820
821
        $this->proceedSelectingShippingAndPaymentMethod($order, $shippingMethod, $paymentMethod);
822
    }
823
824
    /**
825
     * @param OrderInterface $order
826
     * @param ShippingMethodInterface $shippingMethod
827
     * @param PaymentMethodInterface $paymentMethod
828
     */
829
    private function proceedSelectingShippingAndPaymentMethod(OrderInterface $order, ShippingMethodInterface $shippingMethod, PaymentMethodInterface $paymentMethod)
830
    {
831
        foreach ($order->getShipments() as $shipment) {
832
            $shipment->setMethod($shippingMethod);
833
        }
834
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_SELECT_SHIPPING);
835
836
        $payment = $order->getLastPayment(PaymentInterface::STATE_CART);
837
        $payment->setMethod($paymentMethod);
838
839
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT);
840
        $this->applyTransitionOnOrderCheckout($order, OrderCheckoutTransitions::TRANSITION_COMPLETE);
841
    }
842
843
    /**
844
     * @param OrderInterface $order
845
     * @param ProductVariantInterface $variant
846
     * @param int $price
847
     */
848
    private function addVariantWithPriceToOrder(OrderInterface $order, ProductVariantInterface $variant, $price)
849
    {
850
        $item = $this->orderItemFactory->createNew();
851
        $item->setVariant($variant);
852
        $item->setUnitPrice($price);
853
854
        $this->itemQuantityModifier->modify($item, 1);
855
856
        $order->addItem($item);
857
    }
858
859
    /**
860
     * @param int $numberOfCustomers
861
     * @param int $numberOfOrders
862
     * @param string $total
863
     * @param bool $isFulfilled
864
     */
865
    private function createOrders(
866
        int $numberOfCustomers,
867
        int $numberOfOrders,
868
        string $total,
869
        bool $isFulfilled = false
870
    ): void {
871
        $customers = $this->generateCustomers($numberOfCustomers);
872
        $sampleProductVariant = $this->sharedStorage->get('variant');
873
        $total = $this->getPriceFromString($total);
874
875
        for ($i = 0; $i < $numberOfOrders; ++$i) {
876
            $order = $this->createOrder($customers[random_int(0, $numberOfCustomers - 1)], '#' . uniqid());
877
            $order->setState(OrderInterface::STATE_NEW); // Temporary, we should use checkout to place these orders.
878
            $this->applyPaymentTransitionOnOrder($order, PaymentTransitions::TRANSITION_COMPLETE);
879
880
            $price = $i === ($numberOfOrders - 1) ? $total : random_int(1, $total);
881
            $total -= $price;
882
883
            $this->addVariantWithPriceToOrder($order, $sampleProductVariant, $price);
884
885
            if ($isFulfilled) {
886
                $this->applyTransitionOnOrder($order, OrderTransitions::TRANSITION_FULFILL);
887
            }
888
889
            $this->objectManager->persist($order);
890
            $this->sharedStorage->set('order', $order);
891
        }
892
893
        $this->objectManager->flush();
894
    }
895
896
    /**
897
     * @param int $numberOfCustomers
898
     * @param int $numberOfOrders
899
     * @param string $total
900
     * @param ProductInterface $product
901
     * @param bool $isFulfilled
902
     */
903
    private function createOrdersWithProduct(
904
        int $numberOfCustomers,
905
        int $numberOfOrders,
906
        string $total,
907
        ProductInterface $product,
908
        bool $isFulfilled = false
909
    ): void {
910
        $customers = $this->generateCustomers($numberOfCustomers);
911
        $sampleProductVariant = $product->getVariants()->first();
912
        $total = $this->getPriceFromString($total);
913
914
        for ($i = 0; $i < $numberOfOrders; ++$i) {
915
            $order = $this->createOrder($customers[random_int(0, $numberOfCustomers - 1)], '#' . uniqid(), $product->getChannels()->first());
916
            $order->setState(OrderInterface::STATE_NEW);
917
            $this->applyPaymentTransitionOnOrder($order, PaymentTransitions::TRANSITION_COMPLETE);
918
919
            $price = $i === ($numberOfOrders - 1) ? $total : random_int(1, $total);
920
            $total -= $price;
921
922
            $this->addVariantWithPriceToOrder($order, $sampleProductVariant, $price);
923
924
            if ($isFulfilled) {
925
                $this->applyTransitionOnOrder($order, OrderTransitions::TRANSITION_FULFILL);
926
            }
927
928
            $this->objectManager->persist($order);
929
        }
930
931
        $this->objectManager->flush();
932
    }
933
934
    /**
935
     * @param CustomerInterface $customer
936
     * @param int $orderCount
937
     * @param ChannelInterface $channel
938
     * @param int $productCount
939
     * @param ProductInterface $product
940
     * @param bool $isFulfilled
941
     */
942
    private function createOrdersForCustomer(
943
        CustomerInterface $customer,
944
        int $orderCount,
945
        ChannelInterface $channel,
946
        int $productCount,
947
        ProductInterface $product,
948
        bool $isFulfilled = false
949
    ): void {
950
        for ($i = 0; $i < $orderCount; ++$i) {
951
            $order = $this->createOrder($customer, uniqid('#'), $channel);
952
953
            $this->addProductVariantsToOrderWithChannelPrice(
954
                $order,
955
                $channel,
956
                $this->variantResolver->getVariant($product),
957
                (int) $productCount
958
            );
959
960
            $order->setState($isFulfilled ? OrderInterface::STATE_FULFILLED : OrderInterface::STATE_NEW);
961
962
            $this->objectManager->persist($order);
963
        }
964
965
        $this->objectManager->flush();
966
    }
967
968
    /**
969
     * @param ProductInterface $product
970
     * @param ShippingMethodInterface $shippingMethod
971
     * @param AddressInterface $address
972
     * @param PaymentMethodInterface $paymentMethod
973
     * @param CustomerInterface $customer
974
     * @param int $number
975
     */
976
    private function placeOrder(
977
        ProductInterface $product,
978
        ShippingMethodInterface $shippingMethod,
979
        AddressInterface $address,
980
        PaymentMethodInterface $paymentMethod,
981
        CustomerInterface $customer,
982
        int $number
983
    ): void {
984
        /** @var ProductVariantInterface $variant */
985
        $variant = $this->variantResolver->getVariant($product);
986
987
        /** @var ChannelPricingInterface $channelPricing */
988
        $channelPricing = $variant->getChannelPricingForChannel($this->sharedStorage->get('channel'));
989
990
        /** @var OrderItemInterface $item */
991
        $item = $this->orderItemFactory->createNew();
992
        $item->setVariant($variant);
993
        $item->setUnitPrice($channelPricing->getPrice());
994
995
        $this->itemQuantityModifier->modify($item, 1);
996
997
        $order = $this->createOrder($customer, '#00000' . $number);
998
        $order->addItem($item);
999
1000
        $this->checkoutUsing($order, $shippingMethod, clone $address, $paymentMethod);
1001
        $this->applyPaymentTransitionOnOrder($order, PaymentTransitions::TRANSITION_COMPLETE);
1002
1003
        $this->objectManager->persist($order);
1004
        $this->sharedStorage->set('order', $order);
1005
    }
1006
}
1007