Completed
Push — core-test-reorganisation ( 880d88 )
by Kamil
44:19 queued 07:25
created

PromotionContext   C

Complexity

Total Complexity 58

Size/Duplication

Total Lines 766
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
wmc 58
lcom 1
cbo 13
dl 0
loc 766
rs 5
c 0
b 0
f 0

54 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 1
A thereIsPromotion() 0 13 2
A thereIsAPromotionWithPriority() 0 11 1
A thereIsAnExclusivePromotionWithPriority() 0 12 1
A thereIsPromotionLimitedToUsages() 0 9 1
A thereIsPromotionWithCoupon() 0 18 1
A thisPromotionHasExpired() 0 6 1
A thisPromotionExpiresTomorrow() 0 6 1
A thisPromotionHasStartedYesterday() 0 6 1
A thisPromotionStartsTomorrow() 0 6 1
A thisCouponHasExpired() 0 6 1
A thisCouponExpiresTomorrow() 0 6 1
A thisCouponHasReachedItsUsageLimit() 0 7 1
A thisCouponCanBeUsedNTimes() 0 6 1
A thisCouponCanBeUsedTwicePerCustomer() 0 6 1
A itGivesFixedDiscountToEveryOrder() 0 4 1
A thisPromotionGivesDiscountToEveryOrderInTheChannelAndDiscountToEveryOrderInTheChannel() 0 17 1
A itGivesPercentageDiscountToEveryOrder() 0 4 1
A itGivesFixedDiscountToEveryOrderWithQuantityAtLeast() 0 9 1
A itGivesFixedDiscountToEveryOrderWithItemsTotalAtLeast() 0 10 1
A itGivesOffOnEveryItemWhenItemTotalExceeds() 0 10 1
A itGivesPercentageDiscountOnShippingToEveryOrder() 0 7 1
A thePromotionGivesFreeShippingToEveryOrder() 0 4 1
A itGivesPercentageOffEveryProductClassifiedAs() 0 7 1
A itGivesFixedOffEveryProductClassifiedAs() 0 7 1
A thisPromotionGivesOffOnEveryProductWithMinimumPriceAt() 0 7 1
A thisPromotionGivesOffOnEveryProductPricedBetween() 0 12 1
A thisPromotionPercentageGivesOffOnEveryProductWithMinimumPriceAt() 0 7 1
A thisPromotionPercentageGivesOffOnEveryProductPricedBetween() 0 12 1
A thePromotionGivesOffIfOrderContainsProductsClassifiedAs() 0 9 1
A thePromotionGivesOffIfOrderContainsProductsClassifiedAsOr() 0 9 1
A thePromotionGivesOffIfOrderContainsProductsClassifiedAsAndPricedAt() 0 11 1
A itGivesFixedOffCustomersNthOrder() 0 6 1
A itGivesPercentageOffCustomersNthOrder() 0 6 1
A itGivesPercentageOffOnEveryProductClassifiedAsAndAmountDiscountOnOrder() 0 9 1
A itGivesOffOnEveryProductClassifiedAsAndAFreeShippingToEveryOrderWithItemsTotalEqualAtLeast() 0 14 1
A itGivesOffOnEveryProductClassifiedAsAndAFixedDiscountToEveryOrderWithItemsTotalEqualAtLeast() 0 20 1
A itGivesOffOnEveryProductClassifiedAsOrIfOrderContainsAnyProductClassifiedAsOr() 0 18 1
A itGivesOffOnEveryProductClassifiedAsIfOrderContainsAnyProductClassifiedAs() 0 15 1
A itIsCouponBasedPromotion() 0 6 1
A thePromotionWasDisabledForTheChannel() 0 6 1
A theCouponWasUsed() 0 6 1
A thePromotionGivesOffIfOrderContainsProducts() 0 6 1
A itGivesFixedDiscountOffOnAProduct() 0 4 1
A itGivesPercentageDiscountOffOnAProduct() 0 4 1
A thePromotionGivesOffTheOrderForCustomersFromGroup() 0 11 1
A getTaxonFilterConfiguration() 0 4 1
A getProductsFilterConfiguration() 0 4 1
A getPriceRangeFilterConfiguration() 0 9 2
A createUnitFixedPromotion() 0 11 1
A createUnitPercentagePromotion() 0 11 1
A createFixedPromotion() 0 11 2
A createPercentagePromotion() 0 8 1
A persistPromotion() 0 12 2

How to fix   Complexity   

Complex Class

Complex classes like PromotionContext often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PromotionContext, and based on these observations, apply Extract Interface, too.

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\Behat\Service\SharedStorageInterface;
17
use Sylius\Component\Core\Factory\PromotionActionFactoryInterface;
18
use Sylius\Component\Core\Factory\PromotionRuleFactoryInterface;
19
use Sylius\Component\Core\Model\ChannelInterface;
20
use Sylius\Component\Core\Model\ProductInterface;
21
use Sylius\Component\Core\Model\PromotionCouponInterface;
22
use Sylius\Component\Core\Model\PromotionInterface;
23
use Sylius\Component\Core\Model\TaxonInterface;
24
use Sylius\Component\Core\Promotion\Checker\Rule\CustomerGroupRuleChecker;
25
use Sylius\Component\Core\Test\Factory\TestPromotionFactoryInterface;
26
use Sylius\Component\Customer\Model\CustomerGroupInterface;
27
use Sylius\Component\Promotion\Factory\PromotionCouponFactoryInterface;
28
use Sylius\Component\Promotion\Model\PromotionActionInterface;
29
use Sylius\Component\Promotion\Model\PromotionRuleInterface;
30
use Sylius\Component\Promotion\Repository\PromotionRepositoryInterface;
31
32
/**
33
 * @author Mateusz Zalewski <[email protected]>
34
 */
35
final class PromotionContext implements Context
36
{
37
    /**
38
     * @var SharedStorageInterface
39
     */
40
    private $sharedStorage;
41
42
    /**
43
     * @var PromotionActionFactoryInterface
44
     */
45
    private $actionFactory;
46
47
    /**
48
     * @var PromotionCouponFactoryInterface
49
     */
50
    private $couponFactory;
51
52
    /**
53
     * @var PromotionRuleFactoryInterface
54
     */
55
    private $ruleFactory;
56
57
    /**
58
     * @var TestPromotionFactoryInterface
59
     */
60
    private $testPromotionFactory;
61
62
    /**
63
     * @var PromotionRepositoryInterface
64
     */
65
    private $promotionRepository;
66
67
    /**
68
     * @var ObjectManager
69
     */
70
    private $objectManager;
71
72
    /**
73
     * @param SharedStorageInterface $sharedStorage
74
     * @param PromotionActionFactoryInterface $actionFactory
75
     * @param PromotionCouponFactoryInterface $couponFactory
76
     * @param PromotionRuleFactoryInterface $ruleFactory
77
     * @param TestPromotionFactoryInterface $testPromotionFactory
78
     * @param PromotionRepositoryInterface $promotionRepository
79
     * @param ObjectManager $objectManager
80
     */
81
    public function __construct(
82
        SharedStorageInterface $sharedStorage,
83
        PromotionActionFactoryInterface $actionFactory,
84
        PromotionCouponFactoryInterface $couponFactory,
85
        PromotionRuleFactoryInterface $ruleFactory,
86
        TestPromotionFactoryInterface $testPromotionFactory,
87
        PromotionRepositoryInterface $promotionRepository,
88
        ObjectManager $objectManager
89
    ) {
90
        $this->sharedStorage = $sharedStorage;
91
        $this->actionFactory = $actionFactory;
92
        $this->couponFactory = $couponFactory;
93
        $this->ruleFactory = $ruleFactory;
94
        $this->testPromotionFactory = $testPromotionFactory;
95
        $this->promotionRepository = $promotionRepository;
96
        $this->objectManager = $objectManager;
97
    }
98
99
    /**
100
     * @Given there is a promotion :promotionName
101
     * @Given there is a promotion :promotionName identified by :promotionCode code
102
     */
103
    public function thereIsPromotion($promotionName, $promotionCode = null)
104
    {
105
        $promotion = $this->testPromotionFactory
106
            ->createForChannel($promotionName, $this->sharedStorage->get('channel'))
107
        ;
108
109
        if (null !== $promotionCode) {
110
            $promotion->setCode($promotionCode);
111
        }
112
113
        $this->promotionRepository->add($promotion);
114
        $this->sharedStorage->set('promotion', $promotion);
115
    }
116
117
    /**
118
     * @Given /^there is a promotion "([^"]+)" with priority ([^"]+)$/
119
     */
120
    public function thereIsAPromotionWithPriority($promotionName, $priority)
121
    {
122
        $promotion = $this->testPromotionFactory
123
            ->createForChannel($promotionName, $this->sharedStorage->get('channel'))
124
        ;
125
126
        $promotion->setPriority($priority);
127
128
        $this->promotionRepository->add($promotion);
129
        $this->sharedStorage->set('promotion', $promotion);
130
    }
131
132
    /**
133
     * @Given /^there is an exclusive promotion "([^"]+)"(?:| with priority ([^"]+))$/
134
     */
135
    public function thereIsAnExclusivePromotionWithPriority($promotionName, $priority = 0)
136
    {
137
        $promotion = $this->testPromotionFactory
138
            ->createForChannel($promotionName, $this->sharedStorage->get('channel'))
139
        ;
140
141
        $promotion->setExclusive(true);
142
        $promotion->setPriority($priority);
143
144
        $this->promotionRepository->add($promotion);
145
        $this->sharedStorage->set('promotion', $promotion);
146
    }
147
148
    /**
149
     * @Given there is a promotion :promotionName limited to :usageLimit usages
150
     */
151
    public function thereIsPromotionLimitedToUsages($promotionName, $usageLimit)
152
    {
153
        $promotion = $this->testPromotionFactory->createForChannel($promotionName, $this->sharedStorage->get('channel'));
154
155
        $promotion->setUsageLimit($usageLimit);
156
157
        $this->promotionRepository->add($promotion);
158
        $this->sharedStorage->set('promotion', $promotion);
159
    }
160
161
    /**
162
     * @Given the store has promotion :promotionName with coupon :couponCode
163
     * @Given the store has a promotion :promotionName with a coupon :couponCode that is limited to :usageLimit usages
164
     */
165
    public function thereIsPromotionWithCoupon($promotionName, $couponCode, $usageLimit = null)
166
    {
167
        /** @var PromotionCouponInterface $coupon */
168
        $coupon = $this->couponFactory->createNew();
169
        $coupon->setCode($couponCode);
170
        $coupon->setUsageLimit($usageLimit);
171
172
        $promotion = $this->testPromotionFactory
173
            ->createForChannel($promotionName, $this->sharedStorage->get('channel'))
174
        ;
175
        $promotion->addCoupon($coupon);
176
        $promotion->setCouponBased(true);
177
178
        $this->promotionRepository->add($promotion);
179
180
        $this->sharedStorage->set('promotion', $promotion);
181
        $this->sharedStorage->set('coupon', $coupon);
182
    }
183
184
    /**
185
     * @Given /^(this promotion) has already expired$/
186
     */
187
    public function thisPromotionHasExpired(PromotionInterface $promotion)
188
    {
189
        $promotion->setEndsAt(new \DateTime('1 day ago'));
190
191
        $this->objectManager->flush();
192
    }
193
194
    /**
195
     * @Given /^(this promotion) expires tomorrow$/
196
     */
197
    public function thisPromotionExpiresTomorrow(PromotionInterface $promotion)
198
    {
199
        $promotion->setEndsAt(new \DateTime('tomorrow'));
200
201
        $this->objectManager->flush();
202
    }
203
204
    /**
205
     * @Given /^(this promotion) has started yesterday$/
206
     */
207
    public function thisPromotionHasStartedYesterday(PromotionInterface $promotion)
208
    {
209
        $promotion->setStartsAt(new \DateTime('1 day ago'));
210
211
        $this->objectManager->flush();
212
    }
213
214
    /**
215
     * @Given /^(this promotion) starts tomorrow$/
216
     */
217
    public function thisPromotionStartsTomorrow(PromotionInterface $promotion)
218
    {
219
        $promotion->setStartsAt(new \DateTime('tomorrow'));
220
221
        $this->objectManager->flush();
222
    }
223
224
    /**
225
     * @Given /^(this coupon) has already expired$/
226
     */
227
    public function thisCouponHasExpired(PromotionCouponInterface $coupon)
228
    {
229
        $coupon->setExpiresAt(new \DateTime('1 day ago'));
230
231
        $this->objectManager->flush();
232
    }
233
234
    /**
235
     * @Given /^(this coupon) expires tomorrow$/
236
     */
237
    public function thisCouponExpiresTomorrow(PromotionCouponInterface $coupon)
238
    {
239
        $coupon->setExpiresAt(new \DateTime('tomorrow'));
240
241
        $this->objectManager->flush();
242
    }
243
244
    /**
245
     * @Given /^(this coupon) has already reached its usage limit$/
246
     */
247
    public function thisCouponHasReachedItsUsageLimit(PromotionCouponInterface $coupon)
248
    {
249
        $coupon->setUsed(42);
250
        $coupon->setUsageLimit(42);
251
252
        $this->objectManager->flush();
253
    }
254
255
    /**
256
     * @Given /^(this coupon) can be used (\d+) times?$/
257
     */
258
    public function thisCouponCanBeUsedNTimes(PromotionCouponInterface $coupon, $usageLimit)
259
    {
260
        $coupon->setUsageLimit($usageLimit);
261
262
        $this->objectManager->flush();
263
    }
264
265
    /**
266
     * @Given /^(this coupon) can be used twice per customer$/
267
     */
268
    public function thisCouponCanBeUsedTwicePerCustomer(PromotionCouponInterface $coupon)
269
    {
270
        $coupon->setPerCustomerUsageLimit(2);
271
272
        $this->objectManager->flush();
273
    }
274
275
    /**
276
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") discount to every order$/
277
     */
278
    public function itGivesFixedDiscountToEveryOrder(PromotionInterface $promotion, $discount)
279
    {
280
        $this->createFixedPromotion($promotion, $discount);
281
    }
282
283
    /**
284
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") discount to every order in the ("[^"]+" channel) and ("(?:€|£|\$)[^"]+") discount to every order in the ("[^"]+" channel)$/
285
     */
286
    public function thisPromotionGivesDiscountToEveryOrderInTheChannelAndDiscountToEveryOrderInTheChannel(
287
        PromotionInterface $promotion,
288
        $firstChannelDiscount,
289
        ChannelInterface $firstChannel,
290
        $secondChannelDiscount,
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $secondChannelDiscount exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
291
        ChannelInterface $secondChannel
292
    ) {
293
        /** @var PromotionActionInterface $action */
294
        $action = $this->actionFactory->createFixedDiscount($firstChannelDiscount, $firstChannel->getCode());
295
        $action->setConfiguration(array_merge($action->getConfiguration(), [$secondChannel->getCode() => ['amount' => $secondChannelDiscount]]));
296
297
        $promotion->addChannel($firstChannel);
298
        $promotion->addChannel($secondChannel);
299
        $promotion->addAction($action);
300
301
        $this->objectManager->flush();
302
    }
303
304
    /**
305
     * @Given /^([^"]+) gives ("[^"]+%") discount to every order$/
306
     */
307
    public function itGivesPercentageDiscountToEveryOrder(PromotionInterface $promotion, $discount)
308
    {
309
        $this->createPercentagePromotion($promotion, $discount);
310
    }
311
312
    /**
313
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") discount to every order with quantity at least ([^"]+)$/
314
     */
315
    public function itGivesFixedDiscountToEveryOrderWithQuantityAtLeast(
316
        PromotionInterface $promotion,
317
        $discount,
318
        $quantity
319
    ) {
320
        $rule = $this->ruleFactory->createCartQuantity((int) $quantity);
321
322
        $this->createFixedPromotion($promotion, $discount, [], $rule);
323
    }
324
325
    /**
326
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") discount to every order with items total at least ("[^"]+")$/
327
     */
328
    public function itGivesFixedDiscountToEveryOrderWithItemsTotalAtLeast(
329
        PromotionInterface $promotion,
330
        $discount,
331
        $targetAmount
332
    ) {
333
        $channelCode = $this->sharedStorage->get('channel')->getCode();
334
        $rule = $this->ruleFactory->createItemTotal($channelCode, $targetAmount);
335
336
        $this->createFixedPromotion($promotion, $discount, [], $rule);
337
    }
338
339
    /**
340
     * @Given /^([^"]+) gives ("[^"]+%") off on every product when the item total is at least ("(?:€|£|\$)[^"]+")$/
341
     */
342
    public function itGivesOffOnEveryItemWhenItemTotalExceeds(
343
        PromotionInterface $promotion,
344
        $discount,
345
        $targetAmount
346
    ) {
347
        $channelCode = $this->sharedStorage->get('channel')->getCode();
348
        $rule = $this->ruleFactory->createItemTotal($channelCode, $targetAmount);
349
350
        $this->createUnitPercentagePromotion($promotion, $discount, [], $rule);
351
    }
352
353
    /**
354
     * @Given /^([^"]+) gives ("[^"]+%") discount on shipping to every order$/
355
     */
356
    public function itGivesPercentageDiscountOnShippingToEveryOrder(PromotionInterface $promotion, $discount)
357
    {
358
        $action = $this->actionFactory->createShippingPercentageDiscount($discount);
359
        $promotion->addAction($action);
360
361
        $this->objectManager->flush();
362
    }
363
364
    /**
365
     * @Given /^([^"]+) gives free shipping to every order$/
366
     */
367
    public function thePromotionGivesFreeShippingToEveryOrder(PromotionInterface $promotion)
368
    {
369
        $this->itGivesPercentageDiscountOnShippingToEveryOrder($promotion, 1);
370
    }
371
372
    /**
373
     * @Given /^([^"]+) gives(?:| another) ("[^"]+%") off every product (classified as "[^"]+")$/
374
     */
375
    public function itGivesPercentageOffEveryProductClassifiedAs(
376
        PromotionInterface $promotion,
377
        $discount,
378
        TaxonInterface $taxon
379
    ) {
380
        $this->createUnitPercentagePromotion($promotion, $discount, $this->getTaxonFilterConfiguration([$taxon->getCode()]));
381
    }
382
383
    /**
384
     * @Given /^([^"]+) gives(?:| another) ("(?:€|£|\$)[^"]+") off on every product (classified as "[^"]+")$/
385
     */
386
    public function itGivesFixedOffEveryProductClassifiedAs(
387
        PromotionInterface $promotion,
388
        $discount,
389
        TaxonInterface $taxon
390
    ) {
391
        $this->createUnitFixedPromotion($promotion, $discount, $this->getTaxonFilterConfiguration([$taxon->getCode()]));
392
    }
393
394
    /**
395
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") off on every product with minimum price at ("(?:€|£|\$)[^"]+")$/
396
     */
397
    public function thisPromotionGivesOffOnEveryProductWithMinimumPriceAt(
398
        PromotionInterface $promotion,
399
        $discount,
400
        $amount
401
    ) {
402
        $this->createUnitFixedPromotion($promotion, $discount, $this->getPriceRangeFilterConfiguration($amount));
403
    }
404
405
    /**
406
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") off on every product priced between ("(?:€|£|\$)[^"]+") and ("(?:€|£|\$)[^"]+")$/
407
     */
408
    public function thisPromotionGivesOffOnEveryProductPricedBetween(
409
        PromotionInterface $promotion,
410
        $discount,
411
        $minAmount,
412
        $maxAmount
413
    ) {
414
        $this->createUnitFixedPromotion(
415
            $promotion,
416
            $discount,
417
            $this->getPriceRangeFilterConfiguration($minAmount, $maxAmount)
418
        );
419
    }
420
421
    /**
422
     * @Given /^([^"]+) gives ("[^"]+%") off on every product with minimum price at ("(?:€|£|\$)[^"]+")$/
423
     */
424
    public function thisPromotionPercentageGivesOffOnEveryProductWithMinimumPriceAt(
425
        PromotionInterface $promotion,
426
        $discount,
427
        $amount
428
    ) {
429
        $this->createUnitPercentagePromotion($promotion, $discount, $this->getPriceRangeFilterConfiguration($amount));
430
    }
431
432
    /**
433
     * @Given /^([^"]+) gives ("[^"]+%") off on every product priced between ("(?:€|£|\$)[^"]+") and ("(?:€|£|\$)[^"]+")$/
434
     */
435
    public function thisPromotionPercentageGivesOffOnEveryProductPricedBetween(
436
        PromotionInterface $promotion,
437
        $discount,
438
        $minAmount,
439
        $maxAmount
440
    ) {
441
        $this->createUnitPercentagePromotion(
442
            $promotion,
443
            $discount,
444
            $this->getPriceRangeFilterConfiguration($minAmount, $maxAmount)
445
        );
446
    }
447
448
    /**
449
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") off if order contains products (classified as "[^"]+")$/
450
     */
451
    public function thePromotionGivesOffIfOrderContainsProductsClassifiedAs(
452
        PromotionInterface $promotion,
453
        $discount,
454
        TaxonInterface $taxon
455
    ) {
456
        $rule = $this->ruleFactory->createHasTaxon([$taxon->getCode()]);
457
458
        $this->createFixedPromotion($promotion, $discount, [], $rule);
459
    }
460
461
    /**
462
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") off if order contains products (classified as "[^"]+" or "[^"]+")$/
463
     */
464
    public function thePromotionGivesOffIfOrderContainsProductsClassifiedAsOr(
465
        PromotionInterface $promotion,
466
        $discount,
467
        array $taxons
468
    ) {
469
        $rule = $this->ruleFactory->createHasTaxon([$taxons[0]->getCode(), $taxons[1]->getCode()]);
470
471
        $this->createFixedPromotion($promotion, $discount, [], $rule);
472
    }
473
474
    /**
475
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") off if order contains products (classified as "[^"]+") with a minimum value of ("(?:€|£|\$)[^"]+")$/
476
     */
477
    public function thePromotionGivesOffIfOrderContainsProductsClassifiedAsAndPricedAt(
478
        PromotionInterface $promotion,
479
        $discount,
480
        TaxonInterface $taxon,
481
        $amount
482
    ) {
483
        $channelCode = $this->sharedStorage->get('channel')->getCode();
484
        $rule = $this->ruleFactory->createItemsFromTaxonTotal($channelCode, $taxon->getCode(), $amount);
485
486
        $this->createFixedPromotion($promotion, $discount, [], $rule);
487
    }
488
489
    /**
490
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") off customer's (\d)(?:st|nd|rd|th) order$/
491
     */
492
    public function itGivesFixedOffCustomersNthOrder(PromotionInterface $promotion, $discount, $nth)
493
    {
494
        $rule = $this->ruleFactory->createNthOrder((int) $nth);
495
496
        $this->createFixedPromotion($promotion, $discount, [], $rule);
497
    }
498
499
    /**
500
     * @Given /^([^"]+) gives ("[^"]+%") off on the customer's (\d)(?:st|nd|rd|th) order$/
501
     */
502
    public function itGivesPercentageOffCustomersNthOrder(PromotionInterface $promotion, $discount, $nth)
503
    {
504
        $rule = $this->ruleFactory->createNthOrder((int) $nth);
505
506
        $this->createPercentagePromotion($promotion, $discount, [], $rule);
507
    }
508
509
    /**
510
     * @Given /^([^"]+) gives ("[^"]+%") off on every product (classified as "[^"]+") and ("(?:€|£|\$)[^"]+") discount on every order$/
511
     */
512
    public function itGivesPercentageOffOnEveryProductClassifiedAsAndAmountDiscountOnOrder(
513
        PromotionInterface $promotion,
514
        $productDiscount,
515
        TaxonInterface $discountTaxon,
516
        $orderDiscount
517
    ) {
518
        $this->createUnitPercentagePromotion($promotion, $productDiscount, $this->getTaxonFilterConfiguration([$discountTaxon->getCode()]));
519
        $this->createFixedPromotion($promotion, $orderDiscount);
520
    }
521
522
    /**
523
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") off on every product (classified as "[^"]+") and a free shipping to every order with items total equal at least ("[^"]+")$/
524
     */
525
    public function itGivesOffOnEveryProductClassifiedAsAndAFreeShippingToEveryOrderWithItemsTotalEqualAtLeast(
526
        PromotionInterface $promotion,
527
        $discount,
528
        TaxonInterface $taxon,
0 ignored issues
show
Unused Code introduced by
The parameter $taxon is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
529
        $targetAmount
530
    ) {
531
        $freeShippingAction = $this->actionFactory->createShippingPercentageDiscount(1);
532
        $promotion->addAction($freeShippingAction);
533
534
        $channelCode = $this->sharedStorage->get('channel')->getCode();
535
        $rule = $this->ruleFactory->createItemTotal($channelCode, $targetAmount);
536
537
        $this->createUnitFixedPromotion($promotion, $discount, [], $rule);
538
    }
539
540
    /**
541
     * @Given /^([^"]+) gives ("[^"]+%") off on every product (classified as "[^"]+") and a ("(?:€|£|\$)[^"]+") discount to every order with items total equal at least ("(?:€|£|\$)[^"]+")$/
542
     */
543
    public function itGivesOffOnEveryProductClassifiedAsAndAFixedDiscountToEveryOrderWithItemsTotalEqualAtLeast(
544
        PromotionInterface $promotion,
545
        $taxonDiscount,
546
        TaxonInterface $taxon,
547
        $orderDiscount,
548
        $targetAmount
549
    ) {
550
        $orderDiscountAction = $this->actionFactory->createFixedDiscount($orderDiscount, $this->sharedStorage->get('channel')->getCode());
551
        $promotion->addAction($orderDiscountAction);
552
553
        $channelCode = $this->sharedStorage->get('channel')->getCode();
554
        $rule = $this->ruleFactory->createItemTotal($channelCode, $targetAmount);
555
556
        $this->createUnitPercentagePromotion(
557
            $promotion,
558
            $taxonDiscount,
559
            $this->getTaxonFilterConfiguration([$taxon->getCode()]),
560
            $rule
561
        );
562
    }
563
564
    /**
565
     * @Given /^([^"]+) gives ("[^"]+%") off on every product (classified as "[^"]+" or "[^"]+") if order contains any product (classified as "[^"]+" or "[^"]+")$/
566
     */
567
    public function itGivesOffOnEveryProductClassifiedAsOrIfOrderContainsAnyProductClassifiedAsOr(
568
        PromotionInterface $promotion,
569
        $discount,
570
        array $discountTaxons,
571
        array $targetTaxons
572
    ) {
573
        $discountTaxonsCodes = [$discountTaxons[0]->getCode(), $discountTaxons[1]->getCode()];
574
        $targetTaxonsCodes = [$targetTaxons[0]->getCode(), $targetTaxons[1]->getCode()];
575
576
        $rule = $this->ruleFactory->createHasTaxon($targetTaxonsCodes);
577
578
        $this->createUnitPercentagePromotion(
579
            $promotion,
580
            $discount,
581
            $this->getTaxonFilterConfiguration($discountTaxonsCodes),
582
            $rule
583
        );
584
    }
585
586
    /**
587
     * @Given /^([^"]+) gives ("[^"]+%") off on every product (classified as "[^"]+") if order contains any product (classified as "[^"]+")$/
588
     */
589
    public function itGivesOffOnEveryProductClassifiedAsIfOrderContainsAnyProductClassifiedAs(
590
        PromotionInterface $promotion,
591
        $discount,
592
        $discountTaxon,
593
        $targetTaxon
594
    ) {
595
        $rule = $this->ruleFactory->createHasTaxon([$targetTaxon->getCode()]);
596
597
        $this->createUnitPercentagePromotion(
598
            $promotion,
599
            $discount,
600
            $this->getTaxonFilterConfiguration([$discountTaxon->getCode()]),
601
            $rule
602
        );
603
    }
604
605
    /**
606
     * @Given /^(it) is coupon based promotion$/
607
     */
608
    public function itIsCouponBasedPromotion(PromotionInterface $promotion)
609
    {
610
        $promotion->setCouponBased(true);
611
612
        $this->objectManager->flush();
613
    }
614
615
    /**
616
     * @Given /^(the promotion) was disabled for the (channel "[^"]+")$/
617
     */
618
    public function thePromotionWasDisabledForTheChannel(PromotionInterface $promotion, ChannelInterface $channel)
619
    {
620
        $promotion->removeChannel($channel);
621
622
        $this->objectManager->flush();
623
    }
624
625
    /**
626
     * @Given /^the (coupon "[^"]+") was used up to its usage limit$/
627
     */
628
    public function theCouponWasUsed(PromotionCouponInterface $coupon)
629
    {
630
        $coupon->setUsed($coupon->getUsageLimit());
631
632
        $this->objectManager->flush();
633
    }
634
635
    /**
636
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") off if order contains (?:a|an) ("[^"]+" product)$/
637
     */
638
    public function thePromotionGivesOffIfOrderContainsProducts(PromotionInterface $promotion, $discount, ProductInterface $product)
639
    {
640
        $rule = $this->ruleFactory->createContainsProduct($product->getCode());
641
642
        $this->createFixedPromotion($promotion, $discount, [], $rule);
643
    }
644
645
    /**
646
     * @Given /^([^"]+) gives ("(?:€|£|\$)[^"]+") off on a ("[^"]*" product)$/
647
     */
648
    public function itGivesFixedDiscountOffOnAProduct(PromotionInterface $promotion, $discount, ProductInterface $product)
649
    {
650
        $this->createUnitFixedPromotion($promotion, $discount, $this->getProductsFilterConfiguration([$product->getCode()]));
651
    }
652
653
    /**
654
     * @Given /^([^"]+) gives ("[^"]+%") off on a ("[^"]*" product)$/
655
     */
656
    public function itGivesPercentageDiscountOffOnAProduct(PromotionInterface $promotion, $discount, ProductInterface $product)
657
    {
658
        $this->createUnitPercentagePromotion($promotion, $discount, $this->getProductsFilterConfiguration([$product->getCode()]));
659
    }
660
661
    /**
662
     * @Given /^([^"]+) gives ("[^"]+%") off the order for customers from ("[^"]*" group)$/
663
     */
664
    public function thePromotionGivesOffTheOrderForCustomersFromGroup(
665
        PromotionInterface $promotion,
666
        $discount,
667
        CustomerGroupInterface $customerGroup
668
    ) {
669
        $rule = $this->ruleFactory->createNew();
670
        $rule->setType(CustomerGroupRuleChecker::TYPE);
671
        $rule->setConfiguration(['group_code' => $customerGroup->getCode()]);
672
673
        $this->createPercentagePromotion($promotion, $discount, [], $rule);
674
    }
675
676
    /**
677
     * @param array $taxonCodes
678
     *
679
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array<string,array<string,array>>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
680
     */
681
    private function getTaxonFilterConfiguration(array $taxonCodes)
682
    {
683
        return ['filters' => ['taxons_filter' => ['taxons' => $taxonCodes]]];
684
    }
685
686
    /**
687
     * @param array $productCodes
688
     *
689
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array<string,array<string,array>>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
690
     */
691
    private function getProductsFilterConfiguration(array $productCodes)
692
    {
693
        return ['filters' => ['products_filter' => ['products' => $productCodes]]];
694
    }
695
696
    /**
697
     * @param int $minAmount
698
     * @param int $maxAmount
0 ignored issues
show
Documentation introduced by
Should the type for parameter $maxAmount not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
699
     *
700
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array<string,array<string,integer>>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
701
     */
702
    private function getPriceRangeFilterConfiguration($minAmount, $maxAmount = null)
703
    {
704
        $configuration = ['filters' => ['price_range_filter' => ['min' => $minAmount]]];
705
        if (null !== $maxAmount) {
706
            $configuration['filters']['price_range_filter']['max'] = $maxAmount;
707
        }
708
709
        return $configuration;
710
    }
711
712
    /**
713
     * @param PromotionInterface $promotion
714
     * @param int $discount
715
     * @param array $configuration
716
     * @param PromotionRuleInterface|null $rule
717
     */
718
    private function createUnitFixedPromotion(PromotionInterface $promotion, $discount, array $configuration = [], PromotionRuleInterface $rule = null)
719
    {
720
        $channelCode = $this->sharedStorage->get('channel')->getCode();
721
722
        $this->persistPromotion(
723
            $promotion,
724
            $this->actionFactory->createUnitFixedDiscount($discount, $channelCode),
725
            [$channelCode => $configuration],
726
            $rule
727
        );
728
    }
729
730
    /**
731
     * @param PromotionInterface $promotion
732
     * @param int $discount
733
     * @param array $configuration
734
     * @param PromotionRuleInterface|null $rule
735
     */
736
    private function createUnitPercentagePromotion(PromotionInterface $promotion, $discount, array $configuration = [], PromotionRuleInterface $rule = null)
737
    {
738
        $channelCode = $this->sharedStorage->get('channel')->getCode();
739
740
        $this->persistPromotion(
741
            $promotion,
742
            $this->actionFactory->createUnitPercentageDiscount($discount, $channelCode),
743
            [$channelCode => $configuration],
744
            $rule
745
        );
746
    }
747
748
    /**
749
     * @param PromotionInterface $promotion
750
     * @param int $discount
751
     * @param array $configuration
752
     * @param PromotionRuleInterface|null $rule
753
     * @param ChannelInterface|null $channel
754
     */
755
    private function createFixedPromotion(
756
        PromotionInterface $promotion,
757
        $discount,
758
        array $configuration = [],
759
        PromotionRuleInterface $rule = null,
760
        ChannelInterface $channel = null
761
    ) {
762
        $channelCode = (null !== $channel) ? $channel->getCode() : $this->sharedStorage->get('channel')->getCode();
763
764
        $this->persistPromotion($promotion, $this->actionFactory->createFixedDiscount($discount, $channelCode), $configuration, $rule);
765
    }
766
767
    /**
768
     * @param PromotionInterface $promotion
769
     * @param float $discount
770
     * @param array $configuration
771
     * @param PromotionRuleInterface $rule
0 ignored issues
show
Documentation introduced by
Should the type for parameter $rule not be null|PromotionRuleInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
772
     */
773
    private function createPercentagePromotion(
774
        PromotionInterface $promotion,
775
        $discount,
776
        array $configuration = [],
777
        PromotionRuleInterface $rule = null
778
    ) {
779
        $this->persistPromotion($promotion, $this->actionFactory->createPercentageDiscount($discount), $configuration, $rule);
780
    }
781
782
    /**
783
     * @param PromotionInterface $promotion
784
     * @param PromotionActionInterface $action
785
     * @param array $configuration
786
     * @param PromotionRuleInterface|null $rule
787
     */
788
    private function persistPromotion(PromotionInterface $promotion, PromotionActionInterface $action, array $configuration, PromotionRuleInterface $rule = null)
789
    {
790
        $configuration = array_merge_recursive($action->getConfiguration(), $configuration);
791
        $action->setConfiguration($configuration);
792
793
        $promotion->addAction($action);
794
        if (null !== $rule) {
795
            $promotion->addRule($rule);
796
        }
797
798
        $this->objectManager->flush();
799
    }
800
}
801