Skip to content

Commit

Permalink
[CartPromotion][CatalogPromotion] Receiving discount only on non disc…
Browse files Browse the repository at this point in the history
…ounted products for unit cart promotions
  • Loading branch information
GSadee authored and SirDomin committed Dec 8, 2021
1 parent 3556f47 commit 1f1e798
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Feature: Receiving fixed discount from cart promotions only on non discounted pr
And the store has a product "Cap" priced at "$10.00"
And there is a catalog promotion "Winter sale" that reduces price by "25%" and applies on "T-Shirt" product

@todo @ui @api
@ui @api
Scenario: Receiving product discount from cart promotions also on discounted products
Given there is a promotion "Christmas sale" that applies to discounted products
And this promotion gives "$10.00" off on every product priced between "$10.00" and "$50.00"
Expand All @@ -21,7 +21,7 @@ Feature: Receiving fixed discount from cart promotions only on non discounted pr
And the product "Mug" should have discounted unit price "$30.00" in the cart
And my cart total should be "$35.00"

@todo @ui @api
@ui @api
Scenario: Receiving product discount from cart promotions only on non discounted products
Given there is a promotion "Christmas sale" that does not apply to discounted products
And this promotion gives "$10.00" off on every product priced between "$10.00" and "$50.00"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Feature: Receiving percentage discount from cart promotions only on non discount
And the store has a product "Cap" priced at "$10.00"
And there is a catalog promotion "Winter sale" that reduces price by "25%" and applies on "T-Shirt" product

@todo @ui @api
@ui @api
Scenario: Receiving product discount from cart promotions also on discounted products
Given there is a promotion "Christmas sale" that applies to discounted products
And this promotion gives "50%" off on every product priced between "$10.00" and "$50.00"
Expand All @@ -21,7 +21,7 @@ Feature: Receiving percentage discount from cart promotions only on non discount
And the product "Mug" should have discounted unit price "$20.00" in the cart
And my cart total should be "$27.50"

@todo @ui @api
@ui @api
Scenario: Receiving product discount from cart promotions only on non discounted products
Given there is a promotion "Christmas sale" that does not apply to discounted products
And this promotion gives "50%" off on every product priced between "$10.00" and "$50.00"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ protected function removeUnitOrderItemAdjustments(OrderItemUnitInterface $unit,

protected function addAdjustmentToUnit(OrderItemUnitInterface $unit, int $amount, PromotionInterface $promotion): void
{
if (!$this->canPromotionBeApplied($unit, $promotion)) {
return;
}

$adjustment = $this->createAdjustment($promotion, AdjustmentInterface::ORDER_UNIT_PROMOTION_ADJUSTMENT);

/** @var OrderItemInterface $orderItem */
Expand Down Expand Up @@ -107,4 +111,23 @@ private function calculate(int $unitTotal, ?int $minimumPrice, int $promotionAmo

return $promotionAmount;
}

private function canPromotionBeApplied(OrderItemUnitInterface $unit, PromotionInterface $promotion): bool
{
if ($promotion->getAppliesToDiscounted()) {
return true;
}

/** @var OrderItemInterface $item */
$item = $unit->getOrderItem();
$variant = $item->getVariant();
if ($variant === null) {
return false;
}

/** @var OrderInterface $order */
$order = $item->getOrder();

return empty($variant->getAppliedPromotionsForChannel($order->getChannel()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ function it_is_a_discount_action(): void
}

function it_applies_a_fixed_discount_on_every_unit_in_order(
ChannelInterface $channel,
FactoryInterface $adjustmentFactory,
FilterInterface $priceRangeFilter,
FilterInterface $taxonFilter,
FilterInterface $productFilter,
ChannelInterface $channel,
AdjustmentInterface $promotionAdjustment1,
AdjustmentInterface $promotionAdjustment2,
OrderInterface $order,
Expand Down Expand Up @@ -89,7 +89,6 @@ function it_applies_a_fixed_discount_on_every_unit_in_order(
$channelPricing2->getMinimumPrice()->willReturn(0);

$order->getItems()->willReturn(new ArrayCollection([$orderItem]));
$order->getChannel()->willReturn($channel);

$priceRangeFilter->filter([$orderItem], ['amount' => 500, 'channel' => $channel])->willReturn([$orderItem]);
$taxonFilter->filter([$orderItem], ['amount' => 500])->willReturn([$orderItem]);
Expand All @@ -100,6 +99,7 @@ function it_applies_a_fixed_discount_on_every_unit_in_order(

$promotion->getName()->willReturn('Test promotion');
$promotion->getCode()->willReturn('TEST_PROMOTION');
$promotion->getAppliesToDiscounted()->willReturn(true);

$adjustmentFactory->createNew()->willReturn($promotionAdjustment1, $promotionAdjustment2);

Expand All @@ -123,11 +123,68 @@ function it_applies_a_fixed_discount_on_every_unit_in_order(
$this->execute($order, ['WEB_US' => ['amount' => 500]], $promotion)->shouldReturn(true);
}

function it_does_not_apply_a_discount_if_all_items_have_been_filtered_out(
function it_applies_a_fixed_discount_only_to_non_discounted_units_if_promotion_does_not_apply_to_discounted_ones(
FactoryInterface $adjustmentFactory,
FilterInterface $priceRangeFilter,
FilterInterface $taxonFilter,
FilterInterface $productFilter,
ChannelInterface $channel,
OrderInterface $order,
OrderItemInterface $orderItem1,
OrderItemInterface $orderItem2,
OrderItemUnitInterface $unit1,
OrderItemUnitInterface $unit2,
PromotionInterface $promotion,
ProductVariantInterface $variant1,
ProductVariantInterface $variant2,
AdjustmentInterface $promotionAdjustment
): void {
$order->getChannel()->willReturn($channel);
$channel->getCode()->willReturn('WEB_US');

$order->getItems()->willReturn(new ArrayCollection([$orderItem1->getWrappedObject(), $orderItem2->getWrappedObject()]));

$priceRangeFilter->filter([$orderItem1, $orderItem2], ['amount' => 500, 'channel' => $channel])->willReturn([$orderItem1, $orderItem2]);
$taxonFilter->filter([$orderItem1, $orderItem2], ['amount' => 500])->willReturn([$orderItem1, $orderItem2]);
$productFilter->filter([$orderItem1, $orderItem2], ['amount' => 500])->willReturn([$orderItem1, $orderItem2]);

$orderItem1->getQuantity()->willReturn(1);
$orderItem1->getUnits()->willReturn(new ArrayCollection([$unit1->getWrappedObject()]));
$orderItem1->getVariant()->willReturn($variant1);
$orderItem1->getOrder()->willReturn($order);
$variant1->getAppliedPromotionsForChannel($channel)->willReturn([]);
$unit1->getTotal()->willReturn(1000);
$unit1->getOrderItem()->willReturn($orderItem1);

$orderItem2->getQuantity()->willReturn(1);
$orderItem2->getUnits()->willReturn(new ArrayCollection([$unit2->getWrappedObject()]));
$orderItem2->getVariant()->willReturn($variant2);
$orderItem2->getOrder()->willReturn($order);
$variant2->getAppliedPromotionsForChannel($channel)->willReturn(['winter_sale' => ['name' => 'Winter sale']]);
$unit2->getTotal()->willReturn(1000);
$unit2->getOrderItem()->willReturn($orderItem2);

$promotion->getName()->willReturn('Test promotion');
$promotion->getCode()->willReturn('TEST_PROMOTION');
$promotion->getAppliesToDiscounted()->willReturn(false);

$adjustmentFactory->createNew()->willReturn($promotionAdjustment);
$promotionAdjustment->setType(AdjustmentInterface::ORDER_UNIT_PROMOTION_ADJUSTMENT)->shouldBeCalled();
$promotionAdjustment->setLabel('Test promotion')->shouldBeCalled();
$promotionAdjustment->setAmount(-500)->shouldBeCalled();
$promotionAdjustment->setOriginCode('TEST_PROMOTION')->shouldBeCalled();

$unit1->addAdjustment($promotionAdjustment)->shouldBeCalled();
$unit2->addAdjustment(Argument::any())->shouldNotBeCalled();

$this->execute($order, ['WEB_US' => ['amount' => 500]], $promotion)->shouldReturn(true);
}

function it_does_not_apply_a_discount_if_all_items_have_been_filtered_out(
FilterInterface $priceRangeFilter,
FilterInterface $taxonFilter,
FilterInterface $productFilter,
ChannelInterface $channel,
OrderInterface $order,
OrderItemInterface $orderItem,
PromotionInterface $promotion
Expand All @@ -136,7 +193,6 @@ function it_does_not_apply_a_discount_if_all_items_have_been_filtered_out(
$channel->getCode()->willReturn('WEB_US');

$order->getItems()->willReturn(new ArrayCollection([$orderItem]));
$order->getChannel()->willReturn($channel);

$priceRangeFilter->filter([$orderItem], ['amount' => 500, 'channel' => $channel])->willReturn([$orderItem]);
$taxonFilter->filter([$orderItem], ['amount' => 500])->willReturn([$orderItem]);
Expand All @@ -146,8 +202,8 @@ function it_does_not_apply_a_discount_if_all_items_have_been_filtered_out(
}

function it_does_not_apply_discount_with_amount_0(
ChannelInterface $channel,
FactoryInterface $adjustmentFactory,
ChannelInterface $channel,
OrderInterface $order,
OrderItemUnitInterface $unit1,
OrderItemUnitInterface $unit2,
Expand All @@ -165,11 +221,11 @@ function it_does_not_apply_discount_with_amount_0(
}

function it_does_not_apply_bigger_discount_than_unit_total(
ChannelInterface $channel,
FactoryInterface $adjustmentFactory,
FilterInterface $priceRangeFilter,
FilterInterface $taxonFilter,
FilterInterface $productFilter,
ChannelInterface $channel,
AdjustmentInterface $promotionAdjustment1,
AdjustmentInterface $promotionAdjustment2,
OrderInterface $order,
Expand Down Expand Up @@ -202,7 +258,6 @@ function it_does_not_apply_bigger_discount_than_unit_total(
$channelPricing2->getMinimumPrice()->willReturn(0);

$order->getItems()->willReturn(new ArrayCollection([$orderItem]));
$order->getChannel()->willReturn($channel);

$priceRangeFilter->filter([$orderItem], ['amount' => 1000, 'channel' => $channel])->willReturn([$orderItem]);
$taxonFilter->filter([$orderItem], ['amount' => 1000])->willReturn([$orderItem]);
Expand All @@ -213,6 +268,7 @@ function it_does_not_apply_bigger_discount_than_unit_total(

$promotion->getName()->willReturn('Test promotion');
$promotion->getCode()->willReturn('TEST_PROMOTION');
$promotion->getAppliesToDiscounted()->willReturn(true);

$adjustmentFactory->createNew()->willReturn($promotionAdjustment1, $promotionAdjustment2);

Expand Down Expand Up @@ -310,8 +366,8 @@ function it_does_not_apply_bigger_discount_than_variant_minimum_price(
}

function it_does_not_apply_discount_if_no_amount_is_defined_for_order_channel(
ChannelInterface $channel,
FactoryInterface $adjustmentFactory,
ChannelInterface $channel,
OrderInterface $order,
PromotionInterface $promotion
): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Component\Core\Model\AdjustmentInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\ChannelPricingInterface;
Expand Down Expand Up @@ -52,11 +53,11 @@ function it_is_an_item_discount_action(): void
}

function it_applies_percentage_discount_on_every_unit_in_order(
ChannelInterface $channel,
FactoryInterface $adjustmentFactory,
FilterInterface $priceRangeFilter,
FilterInterface $taxonFilter,
FilterInterface $productFilter,
ChannelInterface $channel,
AdjustmentInterface $promotionAdjustment1,
AdjustmentInterface $promotionAdjustment2,
Collection $originalItems,
Expand Down Expand Up @@ -107,6 +108,7 @@ function it_applies_percentage_discount_on_every_unit_in_order(

$promotion->getName()->willReturn('Test promotion');
$promotion->getCode()->willReturn('TEST_PROMOTION');
$promotion->getAppliesToDiscounted()->willReturn(true);

$adjustmentFactory->createNew()->willReturn($promotionAdjustment1, $promotionAdjustment2);

Expand All @@ -128,11 +130,69 @@ function it_applies_percentage_discount_on_every_unit_in_order(
$this->execute($order, ['WEB_US' => ['percentage' => 0.2]], $promotion)->shouldReturn(true);
}

function it_does_not_apply_a_discount_if_all_items_have_been_filtered_out(
function it_applies_discount_only_to_non_discounted_units_if_promotion_does_not_apply_to_discounted_ones(
FactoryInterface $adjustmentFactory,
FilterInterface $priceRangeFilter,
FilterInterface $taxonFilter,
FilterInterface $productFilter,
ChannelInterface $channel,
AdjustmentInterface $promotionAdjustment,
OrderInterface $order,
OrderItemInterface $orderItem1,
OrderItemInterface $orderItem2,
OrderItemUnitInterface $unit1,
OrderItemUnitInterface $unit2,
PromotionInterface $promotion,
ProductVariantInterface $variant1,
ProductVariantInterface $variant2
): void {
$order->getChannel()->willReturn($channel);
$channel->getCode()->willReturn('WEB_US');

$order->getItems()->willReturn(new ArrayCollection([$orderItem1->getWrappedObject(), $orderItem2->getWrappedObject()]));

$priceRangeFilter->filter([$orderItem1, $orderItem2], ['percentage' => 0.2, 'channel' => $channel])->willReturn([$orderItem1, $orderItem2]);
$taxonFilter->filter([$orderItem1, $orderItem2], ['percentage' => 0.2])->willReturn([$orderItem1, $orderItem2]);
$productFilter->filter([$orderItem1, $orderItem2], ['percentage' => 0.2])->willReturn([$orderItem1, $orderItem2]);

$orderItem1->getQuantity()->willReturn(1);
$orderItem1->getUnitPrice()->willReturn(500);
$orderItem1->getUnits()->willReturn(new ArrayCollection([$unit1->getWrappedObject()]));
$orderItem1->getVariant()->willReturn($variant1);
$orderItem1->getOrder()->willReturn($order);
$variant1->getAppliedPromotionsForChannel($channel)->willReturn([]);
$unit1->getOrderItem()->willReturn($orderItem1);

$orderItem2->getQuantity()->willReturn(1);
$orderItem2->getUnitPrice()->willReturn(500);
$orderItem2->getUnits()->willReturn(new ArrayCollection([$unit2->getWrappedObject()]));
$orderItem2->getVariant()->willReturn($variant2);
$orderItem2->getOrder()->willReturn($order);
$variant2->getAppliedPromotionsForChannel($channel)->willReturn(['winter_sale' => ['name' => 'Winter sale']]);
$unit2->getOrderItem()->willReturn($orderItem2);

$promotion->getName()->willReturn('Test promotion');
$promotion->getCode()->willReturn('TEST_PROMOTION');
$promotion->getAppliesToDiscounted()->willReturn(false);

$adjustmentFactory->createNew()->willReturn($promotionAdjustment);

$promotionAdjustment->setType(AdjustmentInterface::ORDER_UNIT_PROMOTION_ADJUSTMENT)->shouldBeCalled();
$promotionAdjustment->setLabel('Test promotion')->shouldBeCalled();
$promotionAdjustment->setAmount(-100)->shouldBeCalled();
$promotionAdjustment->setOriginCode('TEST_PROMOTION')->shouldBeCalled();

$unit1->addAdjustment($promotionAdjustment)->shouldBeCalled();
$unit2->addAdjustment(Argument::any())->shouldNotBeCalled();

$this->execute($order, ['WEB_US' => ['percentage' => 0.2]], $promotion)->shouldReturn(true);
}

function it_does_not_apply_a_discount_if_all_items_have_been_filtered_out(
FilterInterface $priceRangeFilter,
FilterInterface $taxonFilter,
FilterInterface $productFilter,
ChannelInterface $channel,
OrderInterface $order,
OrderItemInterface $orderItem,
PromotionInterface $promotion
Expand Down

0 comments on commit 1f1e798

Please sign in to comment.