mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
Add include_child_taxons toggle to TotalOfItemsFromTaxon promotion rule
This commit is contained in:
parent
c4bc877222
commit
28accafe56
8 changed files with 93 additions and 13 deletions
|
|
@ -58,11 +58,11 @@ Feature: Receiving discount based on total of items from specific taxon
|
||||||
And my discount should be "-$15.00"
|
And my discount should be "-$15.00"
|
||||||
|
|
||||||
@api @ui
|
@api @ui
|
||||||
Scenario: Receiving discount on order while buying product from child taxon of promoted taxon
|
Scenario: Receiving discount on order while buying product from child taxon of promoted taxon when child taxons are included
|
||||||
Given the "T-Shirts" taxon has child taxon "Polo T-Shirts"
|
Given the "T-Shirts" taxon has child taxon "Polo T-Shirts"
|
||||||
And the store has a product "Polo T-Shirt" priced at "$100.00"
|
And the store has a product "Polo T-Shirt" priced at "$100.00"
|
||||||
And it belongs to "Polo T-Shirts"
|
And it belongs to "Polo T-Shirts"
|
||||||
And the promotion gives "$20.00" off if order contains products classified as "T-Shirts" with a minimum value of "$50.00"
|
And the promotion gives "$20.00" off if order contains products classified as "T-Shirts" with a minimum value of "$50.00", including child taxons
|
||||||
And I added product "Polo T-Shirt" to the cart
|
And I added product "Polo T-Shirt" to the cart
|
||||||
When I check the details of my cart
|
When I check the details of my cart
|
||||||
Then my cart total should be "$80.00"
|
Then my cart total should be "$80.00"
|
||||||
|
|
@ -73,7 +73,7 @@ Feature: Receiving discount based on total of items from specific taxon
|
||||||
Given the "T-Shirts" taxon has child taxon "Polo T-Shirts"
|
Given the "T-Shirts" taxon has child taxon "Polo T-Shirts"
|
||||||
And the store has a product "Polo T-Shirt" priced at "$30.00"
|
And the store has a product "Polo T-Shirt" priced at "$30.00"
|
||||||
And it belongs to "Polo T-Shirts"
|
And it belongs to "Polo T-Shirts"
|
||||||
And the promotion gives "$20.00" off if order contains products classified as "T-Shirts" with a minimum value of "$50.00"
|
And the promotion gives "$20.00" off if order contains products classified as "T-Shirts" with a minimum value of "$50.00", including child taxons
|
||||||
And I added product "Polo T-Shirt" to the cart
|
And I added product "Polo T-Shirt" to the cart
|
||||||
When I check the details of my cart
|
When I check the details of my cart
|
||||||
Then my cart total should be "$30.00"
|
Then my cart total should be "$30.00"
|
||||||
|
|
@ -84,9 +84,20 @@ Feature: Receiving discount based on total of items from specific taxon
|
||||||
Given the "T-Shirts" taxon has child taxon "Polo T-Shirts"
|
Given the "T-Shirts" taxon has child taxon "Polo T-Shirts"
|
||||||
And the store has a product "Polo T-Shirt" priced at "$60.00"
|
And the store has a product "Polo T-Shirt" priced at "$60.00"
|
||||||
And it belongs to "Polo T-Shirts"
|
And it belongs to "Polo T-Shirts"
|
||||||
And the promotion gives "$10.00" off if order contains products classified as "T-Shirts" with a minimum value of "$50.00"
|
And the promotion gives "$10.00" off if order contains products classified as "T-Shirts" with a minimum value of "$50.00", including child taxons
|
||||||
And I added product "PHP T-Shirt" to the cart
|
And I added product "PHP T-Shirt" to the cart
|
||||||
And I added product "Polo T-Shirt" to the cart
|
And I added product "Polo T-Shirt" to the cart
|
||||||
When I check the details of my cart
|
When I check the details of my cart
|
||||||
Then my cart total should be "$150.00"
|
Then my cart total should be "$150.00"
|
||||||
And my discount should be "-$10.00"
|
And my discount should be "-$10.00"
|
||||||
|
|
||||||
|
@api @ui
|
||||||
|
Scenario: Receiving no discount on order while buying product from child taxon when child taxons are excluded from the rule
|
||||||
|
Given the "T-Shirts" taxon has child taxon "Polo T-Shirts"
|
||||||
|
And the store has a product "Polo T-Shirt" priced at "$100.00"
|
||||||
|
And it belongs to "Polo T-Shirts"
|
||||||
|
And the promotion gives "$20.00" off if order contains products classified as "T-Shirts" with a minimum value of "$50.00"
|
||||||
|
And I added product "Polo T-Shirt" to the cart
|
||||||
|
When I check the details of my cart
|
||||||
|
Then my cart total should be "$100.00"
|
||||||
|
And there should be no discount applied
|
||||||
|
|
|
||||||
|
|
@ -635,6 +635,19 @@ final readonly class PromotionContext implements Context
|
||||||
$this->createFixedPromotion($promotion, $discount, [], $rule);
|
$this->createFixedPromotion($promotion, $discount, [], $rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Given('/^([^"]+) gives ("(?:€|£|\$)[^"]+") off if order contains products (classified as "[^"]+") with a minimum value of ("(?:€|£|\$)[^"]+"), including child taxons$/')]
|
||||||
|
public function thePromotionGivesOffIfOrderContainsProductsClassifiedAsAndPricedAtIncludingChildTaxons(
|
||||||
|
PromotionInterface $promotion,
|
||||||
|
int $discount,
|
||||||
|
TaxonInterface $taxon,
|
||||||
|
int $amount,
|
||||||
|
): void {
|
||||||
|
$channelCode = $this->getChannelCode();
|
||||||
|
$rule = $this->ruleFactory->createItemsFromTaxonTotal($channelCode, $taxon->getCode(), $amount, true);
|
||||||
|
|
||||||
|
$this->createFixedPromotion($promotion, $discount, [], $rule);
|
||||||
|
}
|
||||||
|
|
||||||
#[Given('/^([^"]+) gives ("(?:€|£|\$)[^"]+") off customer\'s (\d)(?:st|nd|rd|th) order$/')]
|
#[Given('/^([^"]+) gives ("(?:€|£|\$)[^"]+") off customer\'s (\d)(?:st|nd|rd|th) order$/')]
|
||||||
public function itGivesFixedOffCustomersNthOrder(PromotionInterface $promotion, int $discount, int $nth): void
|
public function itGivesFixedOffCustomersNthOrder(PromotionInterface $promotion, int $discount, int $nth): void
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ use Sylius\Bundle\TaxonomyBundle\Form\Type\TaxonAutocompleteChoiceType;
|
||||||
use Sylius\Component\Core\Model\TaxonInterface;
|
use Sylius\Component\Core\Model\TaxonInterface;
|
||||||
use Sylius\Resource\Doctrine\Persistence\RepositoryInterface;
|
use Sylius\Resource\Doctrine\Persistence\RepositoryInterface;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\Form\ReversedTransformer;
|
use Symfony\Component\Form\ReversedTransformer;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
@ -40,6 +41,10 @@ final class TotalOfItemsFromTaxonConfigurationType extends AbstractType
|
||||||
'label' => 'sylius.form.promotion_rule.total_of_items_from_taxon.amount',
|
'label' => 'sylius.form.promotion_rule.total_of_items_from_taxon.amount',
|
||||||
'currency' => $options['currency'],
|
'currency' => $options['currency'],
|
||||||
])
|
])
|
||||||
|
->add('include_child_taxons', CheckboxType::class, [
|
||||||
|
'label' => 'sylius.form.promotion_rule.total_of_items_from_taxon.include_child_taxons',
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
;
|
;
|
||||||
|
|
||||||
$builder->get('taxon')->addModelTransformer(
|
$builder->get('taxon')->addModelTransformer(
|
||||||
|
|
|
||||||
|
|
@ -205,8 +205,9 @@ sylius:
|
||||||
product:
|
product:
|
||||||
products: Products
|
products: Products
|
||||||
total_of_items_from_taxon:
|
total_of_items_from_taxon:
|
||||||
taxon: Taxon
|
|
||||||
amount: Amount
|
amount: Amount
|
||||||
|
include_child_taxons: Include products from child taxons
|
||||||
|
taxon: Taxon
|
||||||
payment_method:
|
payment_method:
|
||||||
channels: Channels
|
channels: Channels
|
||||||
product_attribute:
|
product_attribute:
|
||||||
|
|
|
||||||
|
|
@ -54,13 +54,16 @@ final class PromotionRuleFactory implements PromotionRuleFactoryInterface
|
||||||
return $this->createPromotionRule(HasTaxonRuleChecker::TYPE, ['taxons' => $taxons]);
|
return $this->createPromotionRule(HasTaxonRuleChecker::TYPE, ['taxons' => $taxons]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createItemsFromTaxonTotal(string $channelCode, string $taxonCode, int $amount): PromotionRuleInterface
|
public function createItemsFromTaxonTotal(
|
||||||
{
|
string $channelCode,
|
||||||
|
string $taxonCode,
|
||||||
|
int $amount,
|
||||||
|
bool $includeChildTaxons = false,
|
||||||
|
): PromotionRuleInterface {
|
||||||
return $this->createPromotionRule(
|
return $this->createPromotionRule(
|
||||||
TotalOfItemsFromTaxonRuleChecker::TYPE,
|
TotalOfItemsFromTaxonRuleChecker::TYPE,
|
||||||
[$channelCode => ['taxon' => $taxonCode, 'amount' => $amount]],
|
[$channelCode => ['amount' => $amount, 'include_child_taxons' => $includeChildTaxons, 'taxon' => $taxonCode]],
|
||||||
)
|
);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createNthOrder(int $nth): PromotionRuleInterface
|
public function createNthOrder(int $nth): PromotionRuleInterface
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,15 @@ final class TotalOfItemsFromTaxonRuleChecker implements RuleCheckerInterface
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$includeChildTaxons = $configuration['include_child_taxons'] ?? false;
|
||||||
$itemsWithTaxonTotal = 0;
|
$itemsWithTaxonTotal = 0;
|
||||||
|
|
||||||
/** @var OrderItemInterface $item */
|
/** @var OrderItemInterface $item */
|
||||||
foreach ($subject->getItems() as $item) {
|
foreach ($subject->getItems() as $item) {
|
||||||
if ($this->productBelongsToTaxonOrDescendant($item->getProduct(), $targetTaxon)) {
|
$belongs = $includeChildTaxons
|
||||||
|
? $this->productBelongsToTaxonOrDescendant($item->getProduct(), $targetTaxon)
|
||||||
|
: $this->productBelongsToTaxon($item->getProduct(), $targetTaxon);
|
||||||
|
if ($belongs) {
|
||||||
$itemsWithTaxonTotal += $item->getTotal();
|
$itemsWithTaxonTotal += $item->getTotal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,6 +73,15 @@ final class TotalOfItemsFromTaxonRuleChecker implements RuleCheckerInterface
|
||||||
return $itemsWithTaxonTotal >= $configuration['amount'];
|
return $itemsWithTaxonTotal >= $configuration['amount'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function productBelongsToTaxon(?ProductInterface $product, TaxonInterface $targetTaxon): bool
|
||||||
|
{
|
||||||
|
if ($product === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $product->getTaxons()->contains($targetTaxon);
|
||||||
|
}
|
||||||
|
|
||||||
private function productBelongsToTaxonOrDescendant(?ProductInterface $product, TaxonInterface $targetTaxon): bool
|
private function productBelongsToTaxonOrDescendant(?ProductInterface $product, TaxonInterface $targetTaxon): bool
|
||||||
{
|
{
|
||||||
if ($product === null) {
|
if ($product === null) {
|
||||||
|
|
|
||||||
|
|
@ -84,11 +84,20 @@ final class PromotionRuleFactoryTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->decoratedFactory->expects($this->once())->method('createNew')->willReturn($this->rule);
|
$this->decoratedFactory->expects($this->once())->method('createNew')->willReturn($this->rule);
|
||||||
$this->rule->expects($this->once())->method('setType')->with(TotalOfItemsFromTaxonRuleChecker::TYPE);
|
$this->rule->expects($this->once())->method('setType')->with(TotalOfItemsFromTaxonRuleChecker::TYPE);
|
||||||
$this->rule->expects($this->once())->method('setConfiguration')->with(['WEB_US' => ['taxon' => 'spears', 'amount' => 1000]]);
|
$this->rule->expects($this->once())->method('setConfiguration')->with(['WEB_US' => ['amount' => 1000, 'include_child_taxons' => false, 'taxon' => 'spears']]);
|
||||||
|
|
||||||
$this->assertSame($this->rule, $this->factory->createItemsFromTaxonTotal('WEB_US', 'spears', 1000));
|
$this->assertSame($this->rule, $this->factory->createItemsFromTaxonTotal('WEB_US', 'spears', 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testShouldCreateTotalOfItemsFromTaxonRuleWithChildTaxons(): void
|
||||||
|
{
|
||||||
|
$this->decoratedFactory->expects($this->once())->method('createNew')->willReturn($this->rule);
|
||||||
|
$this->rule->expects($this->once())->method('setType')->with(TotalOfItemsFromTaxonRuleChecker::TYPE);
|
||||||
|
$this->rule->expects($this->once())->method('setConfiguration')->with(['WEB_US' => ['amount' => 1000, 'include_child_taxons' => true, 'taxon' => 'spears']]);
|
||||||
|
|
||||||
|
$this->assertSame($this->rule, $this->factory->createItemsFromTaxonTotal('WEB_US', 'spears', 1000, true));
|
||||||
|
}
|
||||||
|
|
||||||
public function testShouldCreateNthOrderRule(): void
|
public function testShouldCreateNthOrderRule(): void
|
||||||
{
|
{
|
||||||
$this->decoratedFactory->expects($this->once())->method('createNew')->willReturn($this->rule);
|
$this->decoratedFactory->expects($this->once())->method('createNew')->willReturn($this->rule);
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,32 @@ final class TotalOfItemsFromTaxonRuleCheckerTest extends TestCase
|
||||||
$recurveBowItem->expects($this->once())->method('getTotal')->willReturn(5000);
|
$recurveBowItem->expects($this->once())->method('getTotal')->willReturn(5000);
|
||||||
|
|
||||||
$this->assertTrue(
|
$this->assertTrue(
|
||||||
$this->ruleChecker->isEligible($this->order, ['WEB_US' => ['taxon' => 'bows', 'amount' => 10000]]),
|
$this->ruleChecker->isEligible($this->order, ['WEB_US' => ['taxon' => 'bows', 'amount' => 10000, 'include_child_taxons' => true]]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testShouldNotRecognizeSubjectAsEligibleIfItHasItemsOnlyFromChildTaxonWhenChildTaxonsExcluded(): void
|
||||||
|
{
|
||||||
|
$recurveBows = $this->createMock(TaxonInterface::class);
|
||||||
|
|
||||||
|
$recurveBowItem = $this->createMock(OrderItemInterface::class);
|
||||||
|
$recurveBow = $this->createMock(ProductInterface::class);
|
||||||
|
|
||||||
|
$this->order->expects($this->once())->method('getChannel')->willReturn($this->channel);
|
||||||
|
$this->channel->expects($this->once())->method('getCode')->willReturn('WEB_US');
|
||||||
|
$this->order->expects($this->once())->method('getItems')->willReturn(new ArrayCollection([
|
||||||
|
$recurveBowItem,
|
||||||
|
]));
|
||||||
|
$this->taxonRepository
|
||||||
|
->expects($this->once())
|
||||||
|
->method('findOneBy')
|
||||||
|
->with(['code' => 'bows'])
|
||||||
|
->willReturn($this->bows);
|
||||||
|
$recurveBowItem->expects($this->once())->method('getProduct')->willReturn($recurveBow);
|
||||||
|
$recurveBow->expects($this->once())->method('getTaxons')->willReturn(new ArrayCollection([$recurveBows]));
|
||||||
|
|
||||||
|
$this->assertFalse(
|
||||||
|
$this->ruleChecker->isEligible($this->order, ['WEB_US' => ['taxon' => 'bows', 'amount' => 5000, 'include_child_taxons' => false]]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue