Completed
Push — master ( d54afb...01173a )
by Kamil
26:45
created

OrderContext::getPriceFromString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
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 Sylius\Behat\Context\Setup;
13
14
use Behat\Behat\Context\Context;
15
use Doctrine\Common\Persistence\ObjectManager;
16
use Sylius\Component\Core\Model\ChannelInterface;
17
use Sylius\Component\Core\Model\CouponInterface;
18
use Sylius\Component\Core\OrderProcessing\OrderRecalculatorInterface;
19
use Sylius\Component\Currency\Model\CurrencyInterface;
20
use Sylius\Component\Order\Modifier\OrderItemQuantityModifierInterface;
21
use Sylius\Component\Core\Model\AddressInterface;
22
use Sylius\Component\Core\Model\OrderInterface;
23
use Sylius\Component\Core\Model\OrderItemInterface;
24
use Sylius\Component\Core\Model\ProductInterface;
25
use Sylius\Component\Core\Model\ProductVariantInterface;
26
use Sylius\Component\Core\Model\ShippingMethodInterface;
27
use Sylius\Component\Core\OrderProcessing\OrderShipmentProcessorInterface;
28
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
29
use Sylius\Component\Core\Test\Services\SharedStorageInterface;
30
use Sylius\Component\Payment\Factory\PaymentFactoryInterface;
31
use Sylius\Component\Payment\Model\PaymentInterface;
32
use Sylius\Component\Payment\Model\PaymentMethodInterface;
33
use Sylius\Component\Resource\Factory\FactoryInterface;
34
use Sylius\Component\Resource\Repository\RepositoryInterface;
35
use Sylius\Component\User\Model\CustomerInterface;
36
use Sylius\Component\User\Model\UserInterface;
37
38
/**
39
 * @author Łukasz Chruściel <[email protected]>
40
 */
41
final class OrderContext implements Context
42
{
43
    /**
44
     * @var SharedStorageInterface
45
     */
46
    private $sharedStorage;
47
48
    /**
49
     * @var OrderRepositoryInterface
50
     */
51
    private $orderRepository;
52
53
    /**
54
     * @var FactoryInterface
55
     */
56
    private $orderFactory;
57
58
    /**
59
     * @var OrderShipmentProcessorInterface
60
     */
61
    private $orderShipmentFactory;
62
63
    /**
64
     * @var PaymentFactoryInterface
65
     */
66
    private $paymentFactory;
67
68
    /**
69
     * @var FactoryInterface
70
     */
71
    private $orderItemFactory;
72
73
    /**
74
     * @var OrderItemQuantityModifierInterface
75
     */
76
    private $itemQuantityModifier;
77
78
    /**
79
     * @var FactoryInterface
80
     */
81
    private $customerFactory;
82
83
    /**
84
     * @var RepositoryInterface
85
     */
86
    private $customerRepository;
87
88
    /**
89
     * @var OrderRecalculatorInterface
90
     */
91
    private $orderRecalculator;
92
93
    /**
94
     * @var ObjectManager
95
     */
96
    private $objectManager;
97
98
    /**
99
     * @param SharedStorageInterface $sharedStorage
100
     * @param OrderRepositoryInterface $orderRepository
101
     * @param FactoryInterface $orderFactory
102
     * @param OrderShipmentProcessorInterface $orderShipmentFactory
103
     * @param PaymentFactoryInterface $paymentFactory
104
     * @param FactoryInterface $orderItemFactory
105
     * @param OrderItemQuantityModifierInterface $itemQuantityModifier
106
     * @param FactoryInterface $customerFactory
107
     * @param RepositoryInterface $customerRepository
108
     * @param OrderRecalculatorInterface $orderRecalculator
109
     * @param ObjectManager $objectManager
110
     */
111
    public function __construct(
112
        SharedStorageInterface $sharedStorage,
113
        OrderRepositoryInterface $orderRepository,
114
        FactoryInterface $orderFactory,
115
        OrderShipmentProcessorInterface $orderShipmentFactory,
116
        PaymentFactoryInterface $paymentFactory,
117
        FactoryInterface $orderItemFactory,
118
        OrderItemQuantityModifierInterface $itemQuantityModifier,
119
        FactoryInterface $customerFactory,
120
        RepositoryInterface $customerRepository,
121
        OrderRecalculatorInterface $orderRecalculator,
122
        ObjectManager $objectManager
123
    ) {
124
        $this->sharedStorage = $sharedStorage;
125
        $this->orderRepository = $orderRepository;
126
        $this->orderFactory = $orderFactory;
127
        $this->orderShipmentFactory = $orderShipmentFactory;
128
        $this->paymentFactory = $paymentFactory;
129
        $this->orderItemFactory = $orderItemFactory;
130
        $this->itemQuantityModifier = $itemQuantityModifier;
131
        $this->customerFactory = $customerFactory;
132
        $this->customerRepository = $customerRepository;
133
        $this->orderRecalculator = $orderRecalculator;
134
        $this->objectManager = $objectManager;
135
    }
136
137
    /**
138
     * @Given there is a customer :customer that placed an order :orderNumber
139
     */
140
    public function thereIsCustomerThatPlacedOrder(CustomerInterface $customer, $orderNumber)
141
    {
142
        $order = $this->createOrder($customer, $orderNumber);
143
144
        $this->sharedStorage->set('order', $order);
145
146
        $this->orderRepository->add($order);
147
    }
148
149
    /**
150
     * @Given /^the customer ("[^"]+" addressed it to "[^"]+", "[^"]+" "[^"]+" in the "[^"]+")$/
151
     */
152
    public function theCustomerAddressedItTo(AddressInterface $address)
153
    {
154
        /** @var OrderInterface $order */
155
        $order = $this->sharedStorage->get('order');
156
        $order->setShippingAddress($address);
157
158
        $this->objectManager->flush();
159
    }
160
161
    /**
162
     * @Given /^for the billing address (of "[^"]+" in the "[^"]+", "[^"]+" "[^"]+", "[^"]+")$/
163
     */
164
    public function forTheBillingAddressOf(AddressInterface $address)
165
    {
166
        /** @var OrderInterface $order */
167
        $order = $this->sharedStorage->get('order');
168
169
        $order->setBillingAddress($address);
170
171
        $this->objectManager->flush();
172
    }
173
174
    /**
175
     * @Given /^the customer chose ("[^"]+" shipping method) (to "[^"]+") with ("[^"]+" payment)$/
176
     */
177
    public function theCustomerChoseShippingToWithPayment(
178
        ShippingMethodInterface $shippingMethod,
179
        AddressInterface $address,
180
        PaymentMethodInterface $paymentMethod
181
    ) {
182
        /** @var OrderInterface $order */
183
        $order = $this->sharedStorage->get('order');
184
185
        $this->orderShipmentFactory->processOrderShipment($order);
186
        $order->getShipments()->first()->setMethod($shippingMethod);
187
188
        $payment = $this->paymentFactory->createWithAmountAndCurrency($order->getTotal(), $order->getCurrency());
189
        $payment->setMethod($paymentMethod);
190
191
        $order->addPayment($payment);
192
193
        $order->setShippingAddress($address);
194
        $order->setBillingAddress($address);
195
196
        $this->orderRecalculator->recalculate($order);
197
198
        $this->objectManager->flush();
199
    }
200
201
    /**
202
     * @Given /^the customer chose ("[^"]+" shipping method) with ("[^"]+" payment)$/
203
     */
204
    public function theCustomerChoseShippingWithPayment(
205
        ShippingMethodInterface $shippingMethod,
206
        PaymentMethodInterface $paymentMethod
207
    ) {
208
        /** @var OrderInterface $order */
209
        $order = $this->sharedStorage->get('order');
210
211
        $this->orderShipmentFactory->processOrderShipment($order);
212
        $order->getShipments()->first()->setMethod($shippingMethod);
213
214
        $this->orderRecalculator->recalculate($order);
215
216
        $payment = $this->paymentFactory->createWithAmountAndCurrency($order->getTotal(), $order->getCurrency());
217
        $payment->setMethod($paymentMethod);
218
219
        $order->addPayment($payment);
220
221
        $this->objectManager->flush();
222
    }
223
224
    /**
225
     * @Given the customer bought a single :product
226
     */
227
    public function theCustomerBoughtSingleProduct(ProductInterface $product)
228
    {
229
        $this->addProductVariantToOrder($product->getMasterVariant(), $product->getPrice(), 1);
230
231
        $this->objectManager->flush();
232
    }
233
234
    /**
235
     * @Given /^the customer bought ((?:a|an) "[^"]+") and ((?:a|an) "[^"]+")$/
236
     */
237
    public function theCustomerBoughtProductAndProduct(ProductInterface $product, ProductInterface $secondProduct)
238
    {
239
        $this->theCustomerBoughtSingleProduct($product);
240
        $this->theCustomerBoughtSingleProduct($secondProduct);
241
    }
242
243
244
    /**
245
     * @Given /^the customer bought (\d+) ("[^"]+" products)/
246
     */
247
    public function theCustomerBoughtSeveralProducts($quantity, ProductInterface $product)
248
    {
249
        $this->addProductVariantToOrder($product->getMasterVariant(), $product->getPrice(), $quantity);
250
251
        $this->objectManager->flush();
252
    }
253
254
    /**
255
     * @Given /^the customer bought a single ("[^"]+" variant of product "[^"]+")$/
256
     */
257
    public function theCustomerBoughtSingleProductVariant(ProductVariantInterface $productVariant)
258
    {
259
        $this->addProductVariantToOrder($productVariant, $productVariant->getPrice());
260
261
        $this->objectManager->flush();
262
    }
263
264
    /**
265
     * @Given the customer bought a single :product using :coupon coupon
266
     */
267
    public function theCustomerBoughtSingleUsing(ProductInterface $product, CouponInterface $coupon)
268
    {
269
        $order = $this->addProductVariantToOrder($product->getMasterVariant(), $product->getPrice());
270
        $order->setPromotionCoupon($coupon);
271
272
        $this->orderRecalculator->recalculate($order);
273
274
        $this->objectManager->flush();
275
    }
276
277
    /**
278
     * @Given /^(I) have already placed an order (\d+) times$/
279
     */
280
    public function iHaveAlreadyPlacedOrderNthTimes(UserInterface $user, $numberOfOrders)
281
    {
282
        $customer = $user->getCustomer();
283
        for ($i = 0; $i < $numberOfOrders; $i++) {
284
            $order = $this->createOrder($customer, '#00000'.$i);
285
            $order->setPaymentState(PaymentInterface::STATE_COMPLETED);
286
            $order->setCompletedAt(new \DateTime());
287
288
            $this->orderRepository->add($order);
289
        }
290
    }
291
292
    /**
293
     * @Given :numberOfCustomers customers have added products to the cart for total of :total
294
     */
295
    public function customersHaveAddedProductsToTheCartForTotalOf($numberOfCustomers, $total)
296
    {
297
        $customers = $this->generateCustomers($numberOfCustomers);
298
299
        $sampleProductVariant = $this->sharedStorage->get('variant');
300
        $total = $this->getPriceFromString($total);
301
302
        for ($i = 0; $i < $numberOfCustomers; $i++) {
303
            $order = $this->createOrder($customers[rand(0, $numberOfCustomers - 1)]);
304
            $order->setCompletedAt(null);
305
306
            $price = $i === ($numberOfCustomers - 1) ? $total : rand(1, $total);
307
            $total -= $price;
308
309
            $item = $this->orderItemFactory->createNew();
310
            $item->setVariant($sampleProductVariant);
311
            $item->setUnitPrice($price);
312
313
            $this->itemQuantityModifier->modify($item, 1);
314
315
            $order->addItem($item);
316
317
            $this->orderRepository->add($order);
318
        }
319
    }
320
321
    /**
322
     * @Given :numberOfCustomers customers have placed :numberOfOrders orders for total of :total
323
     * @Given then :numberOfCustomers more customers have placed :numberOfOrders orders for total of :total
324
     */
325
    public function customersHavePlacedOrdersForTotalOf($numberOfCustomers, $numberOfOrders, $total)
326
    {
327
        $customers = $this->generateCustomers($numberOfCustomers);
328
        $sampleProductVariant = $this->sharedStorage->get('variant');
329
        $total = $this->getPriceFromString($total);
330
331
        for ($i = 0; $i < $numberOfOrders; $i++) {
332
            $order = $this->createOrder($customers[rand(0, $numberOfCustomers - 1)], '#'.uniqid());
333
            $order->setPaymentState(PaymentInterface::STATE_COMPLETED);
334
            $order->setCompletedAt(new \DateTime());
335
336
            $price = $i === ($numberOfOrders - 1) ? $total : rand(1, $total);
337
            $total -= $price;
338
339
            $item = $this->orderItemFactory->createNew();
340
            $item->setVariant($sampleProductVariant);
341
            $item->setUnitPrice($price);
342
343
            $this->itemQuantityModifier->modify($item, 1);
344
345
            $order->addItem($item);
346
347
            $this->orderRepository->add($order);
348
        }
349
    }
350
351
    /**
352
     * @param ProductVariantInterface $productVariant
353
     * @param int $price
354
     * @param int $quantity
355
     *
356
     * @return OrderInterface
357
     */
358
    private function addProductVariantToOrder(ProductVariantInterface $productVariant, $price, $quantity = 1)
359
    {
360
        $order = $this->sharedStorage->get('order');
361
362
        /** @var OrderItemInterface $item */
363
        $item = $this->orderItemFactory->createNew();
364
        $item->setVariant($productVariant);
365
        $item->setUnitPrice($price);
366
367
        $this->itemQuantityModifier->modify($item, $quantity);
368
369
        $order->addItem($item);
370
371
        $this->orderRecalculator->recalculate($order);
372
373
        return $order;
374
    }
375
376
    /**
377
     * @param CustomerInterface $customer
378
     * @param string $number
379
     * @param ChannelInterface|null $channel
380
     * @param CurrencyInterface|null $currency
381
     *
382
     * @return OrderInterface
383
     */
384
    private function createOrder(
385
        CustomerInterface $customer,
386
        $number = null,
387
        ChannelInterface $channel = null,
388
        CurrencyInterface $currency = null
389
    ) {
390
        $order = $this->orderFactory->createNew();
391
392
        $order->setCustomer($customer);
393
        $order->setNumber($number);
394
        $order->setChannel((null !== $channel) ? $channel : $this->sharedStorage->get('channel'));
395
        $order->setCurrency((null !== $currency) ? $currency : $this->sharedStorage->get('currency'));
396
        $order->complete();
397
398
        return $order;
399
    }
400
401
    /**
402
     * @param $count
403
     *
404
     * @return CustomerInterface[]
405
     */
406
    private function generateCustomers($count)
407
    {
408
        $customers = [];
409
410
        for ($i = 0; $i < $count; $i++) {
411
            $customer = $this->customerFactory->createNew();
412
            $customer->setEmail(sprintf('john%[email protected]', uniqid()));
413
            $customer->setFirstname('John');
414
            $customer->setLastname('Doe'.$i);
415
416
            $customers[] = $customer;
417
418
            $this->customerRepository->add($customer);
419
        }
420
421
        return $customers;
422
    }
423
424
    /**
425
     * @param string $price
426
     *
427
     * @return int
428
     */
429
    private function getPriceFromString($price)
430
    {
431
        return (int) round((str_replace(['€', '£', '$'], '', $price) * 100), 2);
432
    }
433
}
434