From 4227f910669fbfb843802791ed1819f9dd6a47e1 Mon Sep 17 00:00:00 2001 From: SirDomin Date: Thu, 9 Dec 2021 09:26:49 +0100 Subject: [PATCH] [MinimumPrice][ApplyOnDiscounted] merge solutions for apply on discount and minimum prices --- ...th_product_minimum_price_specified.feature | 15 +++++++ .../Behat/Context/Setup/PromotionContext.php | 10 +++++ .../Distributor/MinimumPriceDistributor.php | 23 +++++++--- .../MinimumPriceDistributorInterface.php | 2 +- .../ProportionalIntegerDistributor.php | 10 ++++- .../FixedDiscountPromotionActionCommand.php | 2 +- ...rcentageDiscountPromotionActionCommand.php | 2 +- .../MinimumPriceDistributorSpec.php | 43 +++++++++++++++++-- .../ProportionalIntegerDistributorSpec.php | 5 +++ ...ixedDiscountPromotionActionCommandSpec.php | 13 +++--- ...tageDiscountPromotionActionCommandSpec.php | 21 +++++---- 11 files changed, 119 insertions(+), 27 deletions(-) diff --git a/features/promotion/receiving_discount/receiving_discounts_with_product_minimum_price_specified.feature b/features/promotion/receiving_discount/receiving_discounts_with_product_minimum_price_specified.feature index 14c6beacf899..a04d3080d505 100644 --- a/features/promotion/receiving_discount/receiving_discounts_with_product_minimum_price_specified.feature +++ b/features/promotion/receiving_discount/receiving_discounts_with_product_minimum_price_specified.feature @@ -211,3 +211,18 @@ Feature: Receiving discounts with product minimum price specified And the "Keyboard" product should have unit price discounted by "$1.00" And the "Mouse" product should have unit price discounted by "$0.00" And the "Headphones" product should have unit price discounted by "$4.00" + + @api + Scenario: Distributing discount proportionally between different products when one has minimum price specified and promotion does not apply on discounted products + Given this promotion does not apply on discounted products + And it gives "$27" discount to every order + And there is a catalog promotion "Fixed T-Shirt sale" that reduces price by fixed "$2.50" in the "United States" channel and applies on "PHP Mug" product + And I add 2 products "T-Shirt" to the cart + And I add 2 products "PHP Mug" to the cart + And I add product "Symfony Mug" to the cart + And I specified the billing address as "Ankh Morpork", "Frost Alley", "90210", "United States" for "Jon Snow" + When I proceed with "Free" shipping method and "Offline" payment + Then I should be on the checkout summary step + And the "T-Shirt" product should have unit prices discounted by "$5.00" and "$5.00" + And the "PHP Mug" product should have unit prices discounted by "$2.50" and "$2.50" + And the "Symfony Mug" product should have unit price discounted by "$17.00" diff --git a/src/Sylius/Behat/Context/Setup/PromotionContext.php b/src/Sylius/Behat/Context/Setup/PromotionContext.php index b12eeea07a45..ae63b2cd9f41 100644 --- a/src/Sylius/Behat/Context/Setup/PromotionContext.php +++ b/src/Sylius/Behat/Context/Setup/PromotionContext.php @@ -203,6 +203,16 @@ public function thisPromotionHasCoupons(PromotionInterface $promotion, string .. $this->objectManager->flush(); } + /** + * @Given /^(this promotion) does not apply on discounted products$/ + */ + public function thisPromotionDoesNotApplyOnDiscountedProducts(PromotionInterface $promotion): void + { + $promotion->setAppliesToDiscounted(false); + + $this->objectManager->flush(); + } + /** * @Given /^(this promotion) has already expired$/ */ diff --git a/src/Sylius/Component/Core/Distributor/MinimumPriceDistributor.php b/src/Sylius/Component/Core/Distributor/MinimumPriceDistributor.php index 4c153f1a0d7b..32d25ab47272 100644 --- a/src/Sylius/Component/Core/Distributor/MinimumPriceDistributor.php +++ b/src/Sylius/Component/Core/Distributor/MinimumPriceDistributor.php @@ -27,7 +27,7 @@ public function __construct(ProportionalIntegerDistributorInterface $proportiona $this->proportionalIntegerDistributor = $proportionalIntegerDistributor; } - public function distribute(array $orderItems, int $amount, ChannelInterface $channel): array + public function distribute(array $orderItems, int $amount, ChannelInterface $channel, bool $appliesOnDiscounted): array { Assert::allIsInstanceOf($orderItems, OrderItemInterface::class); @@ -37,7 +37,6 @@ public function distribute(array $orderItems, int $amount, ChannelInterface $cha $variant = $orderItem->getVariant(); $minimumPrice = $variant->getChannelPricingForChannel($channel)->getMinimumPrice(); - $minimumPrice *= $orderItem->getQuantity(); $orderItemsToProcess['order-item-' . $index] = [ @@ -48,14 +47,14 @@ public function distribute(array $orderItems, int $amount, ChannelInterface $cha return array_values(array_map( function (array $processedOrderItem): int { return $processedOrderItem['promotion']; }, - $this->processDistributionWithMinimumPrice($orderItemsToProcess, $amount, $channel) + $this->processDistributionWithMinimumPrice($orderItemsToProcess, $amount, $channel, $appliesOnDiscounted) )); } - private function processDistributionWithMinimumPrice(array $orderItems, int $amount, $channel): array + private function processDistributionWithMinimumPrice(array $orderItems, int $amount, $channel, bool $appliesOnDiscounted): array { - $totals = array_values(array_map(function (array $orderItemData): int { - return $orderItemData['orderItem']->getTotal(); + $totals = array_values(array_map(function (array $orderItemData) use ($appliesOnDiscounted, $channel): int { + return $this->getTotalPrice($orderItemData['orderItem'], $appliesOnDiscounted, $channel); }, $orderItems)); $promotionsToDistribute = array_combine( @@ -92,7 +91,7 @@ private function processDistributionWithMinimumPrice(array $orderItems, int $amo return $orderItems; } - $nestedDistributions = $this->processDistributionWithMinimumPrice($distributableItems, $leftAmount, $channel); + $nestedDistributions = $this->processDistributionWithMinimumPrice($distributableItems, $leftAmount, $channel, $appliesOnDiscounted); foreach ($nestedDistributions as $index => $distribution) { $orderItems[$index]['promotion'] += $distribution['promotion']; @@ -108,4 +107,14 @@ private function exceedsOrderItemMinimumPrice( ): bool { return $minimumPriceAdjustedByCurrentDiscount >= ($orderItemTotal + $proposedPromotion); } + + private function getTotalPrice(OrderItemInterface $orderItem, bool $appliesOnDiscounted, ChannelInterface $channel): int + { + $variant = $orderItem->getVariant(); + if ($appliesOnDiscounted === false && !empty($variant->getAppliedPromotionsForChannel($channel))) { + return 0; + } + + return $orderItem->getTotal(); + } } diff --git a/src/Sylius/Component/Core/Distributor/MinimumPriceDistributorInterface.php b/src/Sylius/Component/Core/Distributor/MinimumPriceDistributorInterface.php index 90d995342bed..4f31dfe94ccf 100644 --- a/src/Sylius/Component/Core/Distributor/MinimumPriceDistributorInterface.php +++ b/src/Sylius/Component/Core/Distributor/MinimumPriceDistributorInterface.php @@ -17,5 +17,5 @@ interface MinimumPriceDistributorInterface { - public function distribute(array $orderItems, int $amount, ChannelInterface $channel): array; + public function distribute(array $orderItems, int $amount, ChannelInterface $channel, bool $appliesOnDiscounted): array; } diff --git a/src/Sylius/Component/Core/Distributor/ProportionalIntegerDistributor.php b/src/Sylius/Component/Core/Distributor/ProportionalIntegerDistributor.php index a07d025f1584..a6f43e1c3b8f 100644 --- a/src/Sylius/Component/Core/Distributor/ProportionalIntegerDistributor.php +++ b/src/Sylius/Component/Core/Distributor/ProportionalIntegerDistributor.php @@ -25,7 +25,15 @@ public function distribute(array $integers, int $amount): array $distributedAmounts = []; foreach ($integers as $element) { - $distributedAmounts[] = (int) round(($element * $amount) / $total, 0, \PHP_ROUND_HALF_DOWN); + if ($element === 0) { + $distributedAmounts[] = 0; + } else { + $distributedAmounts[] = (int) round(($element * $amount) / $total, 0, \PHP_ROUND_HALF_DOWN); + } + } + + if(array_sum($distributedAmounts) === 0) { + return $distributedAmounts; } $missingAmount = $amount - array_sum($distributedAmounts); diff --git a/src/Sylius/Component/Core/Promotion/Action/FixedDiscountPromotionActionCommand.php b/src/Sylius/Component/Core/Promotion/Action/FixedDiscountPromotionActionCommand.php index 8a0903e26a92..3eeeb270ee63 100644 --- a/src/Sylius/Component/Core/Promotion/Action/FixedDiscountPromotionActionCommand.php +++ b/src/Sylius/Component/Core/Promotion/Action/FixedDiscountPromotionActionCommand.php @@ -69,7 +69,7 @@ public function execute(PromotionSubjectInterface $subject, array $configuration } if ($this->minimumPriceDistributor !== null) { - $splitPromotion = $this->minimumPriceDistributor->distribute($subject->getItems()->toArray(), $promotionAmount, $subject->getChannel()); + $splitPromotion = $this->minimumPriceDistributor->distribute($subject->getItems()->toArray(), $promotionAmount, $subject->getChannel(), $promotion->getAppliesToDiscounted()); } else { $itemsTotal = []; foreach ($subject->getItems() as $orderItem) { diff --git a/src/Sylius/Component/Core/Promotion/Action/PercentageDiscountPromotionActionCommand.php b/src/Sylius/Component/Core/Promotion/Action/PercentageDiscountPromotionActionCommand.php index 0d96b6462742..51a4d32c2d6f 100644 --- a/src/Sylius/Component/Core/Promotion/Action/PercentageDiscountPromotionActionCommand.php +++ b/src/Sylius/Component/Core/Promotion/Action/PercentageDiscountPromotionActionCommand.php @@ -65,7 +65,7 @@ public function execute(PromotionSubjectInterface $subject, array $configuration } if ($this->minimumPriceDistributor !== null) { - $splitPromotion = $this->minimumPriceDistributor->distribute($subject->getItems()->toArray(), $promotionAmount, $subject->getChannel()); + $splitPromotion = $this->minimumPriceDistributor->distribute($subject->getItems()->toArray(), $promotionAmount, $subject->getChannel(), $promotion->getAppliesToDiscounted()); } else { $itemsTotal = []; foreach ($subject->getItems() as $orderItem) { diff --git a/src/Sylius/Component/Core/spec/Distributor/MinimumPriceDistributorSpec.php b/src/Sylius/Component/Core/spec/Distributor/MinimumPriceDistributorSpec.php index e20978fc4a03..85adacae2e87 100644 --- a/src/Sylius/Component/Core/spec/Distributor/MinimumPriceDistributorSpec.php +++ b/src/Sylius/Component/Core/spec/Distributor/MinimumPriceDistributorSpec.php @@ -48,30 +48,34 @@ function it_distributes_promotion_taking_into_account_minimum_price( $tshirt->getVariant()->willReturn($tshirtVariant); $tshirtVariant->getChannelPricingForChannel($channel)->willReturn($tshirtVariantChannelPricing); $tshirtVariantChannelPricing->getMinimumPrice()->willReturn(0); + $tshirtVariant->getAppliedPromotionsForChannel($channel)->willReturn([]); $book->getTotal()->willReturn(2000); $book->getQuantity()->willReturn(1); $book->getVariant()->willReturn($bookVariant); $bookVariant->getChannelPricingForChannel($channel)->willReturn($bookVariantChannelPricing); $bookVariantChannelPricing->getMinimumPrice()->willReturn(1900); + $bookVariant->getAppliedPromotionsForChannel($channel)->willReturn([]); $shoes->getTotal()->willReturn(5000); $shoes->getQuantity()->willReturn(1); $shoes->getVariant()->willReturn($shoesVariant); $shoesVariant->getChannelPricingForChannel($channel)->willReturn($shoesVariantChannelPricing); $shoesVariantChannelPricing->getMinimumPrice()->willReturn(5000); + $shoesVariant->getAppliedPromotionsForChannel($channel)->willReturn([]); $boardGame->getTotal()->willReturn(3000); $boardGame->getQuantity()->willReturn(1); $boardGame->getVariant()->willReturn($boardGameVariant); $boardGameVariant->getChannelPricingForChannel($channel)->willReturn($boardGameVariantChannelPricing); $boardGameVariantChannelPricing->getMinimumPrice()->willReturn(2600); + $boardGameVariant->getAppliedPromotionsForChannel($channel)->willReturn([]); $proportionalIntegerDistributor->distribute([1000, 2000, 5000, 3000], -1200)->willReturn([-110, -218, -545, -327]); $proportionalIntegerDistributor->distribute([1000, 3000], -663)->willReturn([-166, -497]); $proportionalIntegerDistributor->distribute([1000], -424)->willReturn([-424]); - $this->distribute([$tshirt, $book, $shoes, $boardGame], -1200, $channel)->shouldReturn([-700, -100, 0, -400]); + $this->distribute([$tshirt, $book, $shoes, $boardGame], -1200, $channel, true)->shouldReturn([-700, -100, 0, -400]); } function it_distributes_promotion_taking_into_account_minimum_price_with_quantity( @@ -89,17 +93,19 @@ function it_distributes_promotion_taking_into_account_minimum_price_with_quantit $tshirt->getVariant()->willReturn($tshirtVariant); $tshirtVariant->getChannelPricingForChannel($channel)->willReturn($tshirtVariantChannelPricing); $tshirtVariantChannelPricing->getMinimumPrice()->willReturn(4500); + $tshirtVariant->getAppliedPromotionsForChannel($channel)->willReturn([]); $mug->getTotal()->willReturn(6000); $mug->getQuantity()->willReturn(3); $mug->getVariant()->willReturn($mugVariant); $mugVariant->getChannelPricingForChannel($channel)->willReturn($mugVariantChannelPricing); $mugVariantChannelPricing->getMinimumPrice()->willReturn(0); + $mugVariant->getAppliedPromotionsForChannel($channel)->willReturn([]); $proportionalIntegerDistributor->distribute([5000, 6000], -2500)->willReturn([-1136, -1364]); $proportionalIntegerDistributor->distribute([6000], -636)->willReturn([-636]); - $this->distribute([$tshirt, $mug], -2500, $channel)->shouldReturn([-500, -2000]); + $this->distribute([$tshirt, $mug], -2500, $channel, true)->shouldReturn([-500, -2000]); } function it_distributes_promotion_that_exceeds_possible_distribution_taking_into_account_minimum_price( @@ -117,16 +123,47 @@ function it_distributes_promotion_that_exceeds_possible_distribution_taking_into $tshirt->getVariant()->willReturn($tshirtVariant); $tshirtVariant->getChannelPricingForChannel($channel)->willReturn($tshirtVariantChannelPricing); $tshirtVariantChannelPricing->getMinimumPrice()->willReturn(4500); + $tshirtVariant->getAppliedPromotionsForChannel($channel)->willReturn([]); $mug->getTotal()->willReturn(6000); $mug->getQuantity()->willReturn(3); $mug->getVariant()->willReturn($mugVariant); $mugVariant->getChannelPricingForChannel($channel)->willReturn($mugVariantChannelPricing); $mugVariantChannelPricing->getMinimumPrice()->willReturn(1500); + $mugVariant->getAppliedPromotionsForChannel($channel)->willReturn([]); $proportionalIntegerDistributor->distribute([5000, 6000], -2500)->willReturn([-1136, -1364]); $proportionalIntegerDistributor->distribute([6000], -636)->willReturn([-636]); - $this->distribute([$tshirt, $mug], -2500, $channel)->shouldReturn([-500, -1500]); + $this->distribute([$tshirt, $mug], -2500, $channel, true)->shouldReturn([-500, -1500]); + } + + function it_distributes_promotion_for_products_without_promotions_if_promotion_does_not_apply_on_catalog_promotions( + ProportionalIntegerDistributorInterface $proportionalIntegerDistributor, + OrderItemInterface $tshirt, + OrderItemInterface $mug, + ProductVariantInterface $tshirtVariant, + ProductVariantInterface $mugVariant, + ChannelPricingInterface $tshirtVariantChannelPricing, + ChannelPricingInterface $mugVariantChannelPricing, + ChannelInterface $channel + ) { + $tshirt->getTotal()->willReturn(5000); + $tshirt->getQuantity()->willReturn(1); + $tshirt->getVariant()->willReturn($tshirtVariant); + $tshirtVariant->getChannelPricingForChannel($channel)->willReturn($tshirtVariantChannelPricing); + $tshirtVariantChannelPricing->getMinimumPrice()->willReturn(4500); + $tshirtVariant->getAppliedPromotionsForChannel($channel)->willReturn([['promotion_applied']]); + + $mug->getTotal()->willReturn(6000); + $mug->getQuantity()->willReturn(3); + $mug->getVariant()->willReturn($mugVariant); + $mugVariant->getChannelPricingForChannel($channel)->willReturn($mugVariantChannelPricing); + $mugVariantChannelPricing->getMinimumPrice()->willReturn(1500); + $mugVariant->getAppliedPromotionsForChannel($channel)->willReturn([]); + + $proportionalIntegerDistributor->distribute([5000, 6000], -2500)->willReturn([0, -1500]); + + $this->distribute([$tshirt, $mug], -2500, $channel, true)->shouldReturn([0, -1500]); } } diff --git a/src/Sylius/Component/Core/spec/Distributor/ProportionalIntegerDistributorSpec.php b/src/Sylius/Component/Core/spec/Distributor/ProportionalIntegerDistributorSpec.php index d17d2eff96f8..4848abae1107 100644 --- a/src/Sylius/Component/Core/spec/Distributor/ProportionalIntegerDistributorSpec.php +++ b/src/Sylius/Component/Core/spec/Distributor/ProportionalIntegerDistributorSpec.php @@ -48,6 +48,11 @@ function it_distributes_an_integer_even_if_its_indivisible_by_number_of_items(): $this->distribute([4300, 1400, 2300], -299)->shouldReturn([-161, -52, -86]); } + function it_distributes_an_integer_even_for_non_distributable_items(): void + { + $this->distribute([0], -299)->shouldReturn([0]); + } + function it_throws_an_exception_if_any_of_integers_array_element_is_not_integer(): void { $this diff --git a/src/Sylius/Component/Core/spec/Promotion/Action/FixedDiscountPromotionActionCommandSpec.php b/src/Sylius/Component/Core/spec/Promotion/Action/FixedDiscountPromotionActionCommandSpec.php index 0dac7cee86e7..aa9375c3f810 100644 --- a/src/Sylius/Component/Core/spec/Promotion/Action/FixedDiscountPromotionActionCommandSpec.php +++ b/src/Sylius/Component/Core/spec/Promotion/Action/FixedDiscountPromotionActionCommandSpec.php @@ -89,7 +89,7 @@ function it_uses_a_distributor_and_applicator_to_execute_promotion_action( $secondItem->getTotal()->willReturn(4000); $secondItem->getQuantity()->willReturn(1); - $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel)->willReturn([-600, -400]); + $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel, true)->willReturn([-600, -400]); $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-600, -400])->shouldBeCalled(); $this->execute($order, ['WEB_US' => ['amount' => 1000]], $promotion)->shouldReturn(true); @@ -125,6 +125,8 @@ function it_distributes_promotion_using_regular_distributor_if_minimum_price_dis ->willReturn(new ArrayCollection([$firstItem->getWrappedObject(), $secondItem->getWrappedObject()])) ; + $promotion->getAppliesToDiscounted()->willReturn(true); + $firstItem->getVariant()->willReturn($productVariantOne); $secondItem->getVariant()->willReturn($productVariantTwo); $productVariantOne->getChannelPricingForChannel($channel)->willReturn($channelPricingOne); @@ -139,7 +141,7 @@ function it_distributes_promotion_using_regular_distributor_if_minimum_price_dis $secondItem->getTotal()->willReturn(4000); $secondItem->getQuantity()->willReturn(1); - $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel)->shouldNotBeCalled(); + $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel, true)->shouldNotBeCalled(); $distributor->distribute([6000, 4000], -1000)->willReturn([-200, -800]); $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-200, -800])->shouldBeCalled(); @@ -184,8 +186,9 @@ function it_distributes_promotion_up_to_minimum_price_of_variant( $firstItem->getQuantity()->willReturn(1); $secondItem->getTotal()->willReturn(4000); $secondItem->getQuantity()->willReturn(1); + $promotion->getAppliesToDiscounted()->willReturn(true); - $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel)->willReturn([-200, -800]); + $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel, true)->willReturn([-200, -800]); $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-200, -800])->shouldBeCalled(); @@ -226,7 +229,7 @@ function it_uses_a_distributor_and_applicator_to_execute_promotion_action_only_f $secondVariant->getAppliedPromotionsForChannel($channel)->willReturn(['winter_sale' => ['name' => 'Winter sale']]); $proportionalIntegerDistributor->distribute([6000, 0], -1000)->shouldNotBeCalled(); - $minimumPriceDistributor->distribute([$firstItem, $secondItem], -10000, $channel)->willReturn([-6000, 0]); + $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel, false)->willReturn([-1000, 0]); $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-1000, 0])->shouldBeCalled(); @@ -274,7 +277,7 @@ function it_does_not_apply_bigger_discount_than_promotion_subject_total( $secondItem->getTotal()->willReturn(4000); $secondItem->getQuantity()->willReturn(1); - $minimumPriceDistributor->distribute([$firstItem, $secondItem], -10000, $channel)->willReturn([-6000, -4000]); + $minimumPriceDistributor->distribute([$firstItem, $secondItem], -10000, $channel, true)->willReturn([-6000, -4000]); $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-6000, -4000])->shouldBeCalled(); diff --git a/src/Sylius/Component/Core/spec/Promotion/Action/PercentageDiscountPromotionActionCommandSpec.php b/src/Sylius/Component/Core/spec/Promotion/Action/PercentageDiscountPromotionActionCommandSpec.php index ab971a16241e..f092623505f2 100644 --- a/src/Sylius/Component/Core/spec/Promotion/Action/PercentageDiscountPromotionActionCommandSpec.php +++ b/src/Sylius/Component/Core/spec/Promotion/Action/PercentageDiscountPromotionActionCommandSpec.php @@ -68,6 +68,7 @@ function it_uses_distributor_and_applicator_to_execute_promotion_action( $secondItem->getTotal()->willReturn(800); $secondItem->getQuantity()->willReturn(1); + $promotion->getAppliesToDiscounted()->willReturn(true); $firstItem->getVariant()->willReturn($productVariantOne); $secondItem->getVariant()->willReturn($productVariantTwo); $productVariantOne->getChannelPricingForChannel($channel)->willReturn($channelPricingOne); @@ -78,7 +79,7 @@ function it_uses_distributor_and_applicator_to_execute_promotion_action( $order->getPromotionSubjectTotal()->willReturn(10000); - $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel)->willReturn([-200, -800]); + $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel, true)->willReturn([-200, -800]); $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-200, -800])->shouldBeCalled(); $this->execute($order, ['percentage' => 0.1], $promotion)->shouldReturn(true); @@ -122,7 +123,7 @@ function it_distributes_promotion_using_regular_distributor_if_minimum_price_dis $order->getPromotionSubjectTotal()->willReturn(10000); - $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel)->shouldNotBeCalled(); + $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel, true)->shouldNotBeCalled(); $distributor->distribute([200, 800], -1000)->willReturn([-200, -800]); $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-200, -800])->shouldBeCalled(); @@ -142,8 +143,7 @@ function it_distributes_promotion_amount_taking_minimum_price_into_account( ChannelPricingInterface $channelPricingOne, ChannelPricingInterface $channelPricingTwo, ChannelInterface $channel - ): void - { + ): void { $order->countItems()->willReturn(2); $order->getChannel()->willReturn($channel); @@ -162,11 +162,14 @@ function it_distributes_promotion_amount_taking_minimum_price_into_account( $channelPricingOne->getMinimumPrice()->willReturn(100); $channelPricingTwo->getMinimumPrice()->willReturn(0); - $order->getPromotionSubjectTotal()->willReturn(10000); + $order->getPromotionSubjectTotal()->willReturn(1000); + $promotion->getAppliesToDiscounted()->willReturn(true); + + $minimumPriceDistributor->distribute([$firstItem, $secondItem], -500, $channel, true)->willReturn([-100, -400]); - $minimumPriceDistributor->distribute([$firstItem, $secondItem], -1000, $channel)->willReturn([-100, -800]); + $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-100, -400])->shouldBeCalled(); - $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-100, -800])->shouldBeCalled(); + $this->execute($order, ['percentage' => 0.5], $promotion)->shouldReturn(true); } function it_uses_a_distributor_and_applicator_to_execute_promotion_action_only_for_non_discounted_items( @@ -178,6 +181,7 @@ function it_uses_a_distributor_and_applicator_to_execute_promotion_action_only_f ProductVariantInterface $secondVariant, PromotionInterface $promotion, ProportionalIntegerDistributorInterface $distributor, + MinimumPriceDistributorInterface $minimumPriceDistributor, UnitsPromotionAdjustmentsApplicatorInterface $unitsPromotionAdjustmentsApplicator ): void { $order->countItems()->willReturn(2); @@ -197,7 +201,8 @@ function it_uses_a_distributor_and_applicator_to_execute_promotion_action_only_f $order->getPromotionSubjectTotal()->willReturn(10000); - $distributor->distribute([200, 0], -20)->willReturn([-20, 0]); + $distributor->distribute([200, 0], -20)->shouldNotBeCalled(); + $minimumPriceDistributor->distribute([$firstItem, $secondItem], -20, $channel, false)->willReturn([-20, 0]); $unitsPromotionAdjustmentsApplicator->apply($order, $promotion, [-20, 0])->shouldBeCalled(); $this->execute($order, ['percentage' => 0.1], $promotion)->shouldReturn(true);