Skip to content

Commit

Permalink
Merge pull request #2057 from dpfaffenbauer/feature/cart-item-actions
Browse files Browse the repository at this point in the history
[CartPriceRules] introduce feature to allow cart-price rules based on cart-items
  • Loading branch information
dpfaffenbauer authored Aug 18, 2022
2 parents 009f876 + 5899ae8 commit 174b24c
Show file tree
Hide file tree
Showing 86 changed files with 2,398 additions and 164 deletions.
52 changes: 52 additions & 0 deletions features/domain/cart/rules/cart_item/amount_condition.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@domain @cart @cart_item
Feature: Adding a new cart item rule
In order to give the customer discounts
based on the cart, we add a new rule
with a amount condition for specific cart items

Background:
Given the site operates on a store in "Austria"
And the site has a currency "Euro" with iso "EUR"
And I am in country "Austria"
And the site has two categories "Shoes" and "Coats"
And the site has a category "Sneakers"
And the category "Sneakers" is child of category "Shoes"
And the site has a product "Shoe" priced at 10000
And it is in category "Shoes"
And the site has a product "Shoe 2" priced at 15000
And it is in category "Shoes"
And the site has a product "Jacket" priced at 40000
And it is in category "Coats"
And the site has a product "Sneaker" priced at 350000
And it is in category "Sneakers"
And I add the product "Shoe" to my cart

Scenario: Add a new amount condition with is valid
Given adding a cart price rule named "amount"
And the cart rule is active
And the cart rule is not a voucher rule
And the cart rule has a cart-item-action action
And the cart item action has a condition amount with value "90" to "150"
And the cart item action has a action discount-percent with 10% discount
Then I refresh my cart
And the cart discount should be "-1000" excluding tax

Scenario: Add a new amount condition with is invalid cause of min value
Given adding a cart price rule named "amount"
And the cart rule is active
And the cart rule is not a voucher rule
And the cart rule has a cart-item-action action
And the cart item action has a condition amount with value "120" to "500"
And the cart item action has a action discount-percent with 10% discount
Then the cart rule should be valid for my cart
And the cart discount should be "0" excluding tax

Scenario: Add a new amount condition with is invalid cause of max value
Given adding a cart price rule named "amount"
And the cart rule is active
And the cart rule is not a voucher rule
And the cart rule has a cart-item-action action
And the cart item action has a condition amount with value "10" to "90"
And the cart item action has a action discount-percent with 10% discount
Then the cart rule should be valid for my cart
And the cart discount should be "0" excluding tax
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@domain @cart
Feature: Adding a new cart rule
In order to give the customer discounts
based on the cart, we add a new rule

Background:
Given the site operates on a store in "Austria"
And the site has a currency "Euro" with iso "EUR"
And I am in country "Austria"
And the site has a product "Shoe" priced at 10000
And I add the product "Shoe" to my cart

Scenario: Add a new discount rule with 20 percent discount for all products
Given adding a cart price rule named "discount"
And the cart rule is active
And the cart rule is a voucher rule with code "asdf"
And the cart rule has a cart-item-action action
And the cart item action has a action discount with 20 in currency "EUR" off
And I apply the voucher code "asdf" to my cart
Then the cart discount should be "-2000" including tax
Then the cart total should be "8000" including tax

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@domain @cart
Feature: Adding a new cart rule
In order to give the customer discounts
based on the cart, we add a new rule with a 100% discount

Background:
Given the site operates on a store in "Austria"
And the site has a currency "Euro" with iso "EUR"
And I am in country "Austria"
And the site has a tax rate "AT" with "20%" rate
And the site has a tax rule group "AT"
And the tax rule group has a tax rule for country "Austria" with tax rate "AT"
And the site has a product "Shoe" priced at 10000
And the product has the tax rule group "AT"
And I add the product "Shoe" to my cart

Scenario: Add a new discount rule with 100 percent discount
Given adding a cart price rule named "discount-10"
And the cart rule is not a voucher rule
And the cart rule is active
And the cart rule has a action discount-percent with 100% discount
Given adding a cart price rule named "discount-100"
And the cart rule is a voucher rule with code "discount-100"
And the cart rule is active
And the cart rule has a cart-item-action action
And the cart item action has a action discount-percent with 100% discount
And I apply the voucher code "discount-100" to my cart
Then the cart discount should be "-12000" including tax
Then the cart discount should be "-10000" excluding tax
Then the cart total tax should be "0"
Then the cart total should be "0" excluding tax
Then the cart total should be "0" including tax
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@domain @cart
Feature: Adding a new cart rule
In order to give the customer discounts
based on the cart, we add a new rule

Background:
Given the site operates on a store in "Austria"
And the site has a currency "Euro" with iso "EUR"
And I am in country "Austria"
And the site has two categories "Shoes" and "Coats"
And the site has a product "Shoe" priced at 10000
And it is in category "Shoes"
And the site has a product "Shoe 2" priced at 15000
And it is in category "Shoes"
And the site has a product "Jacket" priced at 40000
And it is in category "Coats"
And I add the product "Shoe" to my cart

Scenario: Add a new discount rule with 20 percent discount for all products
Given adding a cart price rule named "discount"
And the cart rule is active
And the cart rule is a voucher rule with code "asdf"
And the cart rule has a cart-item-action action
And the cart item action has a action discount-percent with 10% discount
And I apply the voucher code "asdf" to my cart
Then the cart discount should be "-1000" including tax
Then the cart total should be "9000" including tax
2 changes: 1 addition & 1 deletion features/domain/cart/rules/product_condition.feature
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Feature: Adding a new cart rule
Given the site operates on a store in "Austria"
Given the site has a currency "Euro" with iso "EUR"
Given I am in country "Austria"
Given the site has two categories "Shoes" and "Coats"
Given the site has two categories "Schoes" and "Coats"
Given the site has a product "Shoe" priced at 100
Given the site has a product "Shoe 2" priced at 150
Given the site has a product "Jacket" priced at 400
Expand Down
9 changes: 6 additions & 3 deletions src/CoreShop/Behat/Context/Hook/PimcoreDaoContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,12 @@ public function clearSlugs(): void
$this->connection->executeQuery('DELETE FROM `object_url_slugs`');

$reflection = new \ReflectionClass(DataObject\Data\UrlSlug::class);
$cacheProperty = $reflection->getProperty('cache');
$cacheProperty->setAccessible(true);
$reflection->setStaticPropertyValue('cache', []);

if ($reflection->hasProperty('cache')) {
$cacheProperty = $reflection->getProperty('cache');
$cacheProperty->setAccessible(true);
$reflection->setStaticPropertyValue('cache', []);
}
}

/**
Expand Down
151 changes: 147 additions & 4 deletions src/CoreShop/Behat/Context/Setup/CartPriceRuleContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use CoreShop\Bundle\CoreBundle\Form\Type\Rule\Condition\ZonesConfigurationType;
use CoreShop\Bundle\OrderBundle\Form\Type\CartPriceRuleActionType;
use CoreShop\Bundle\OrderBundle\Form\Type\CartPriceRuleConditionType;
use CoreShop\Bundle\OrderBundle\Form\Type\Rule\Action\CartItemActionConfigurationType;
use CoreShop\Bundle\OrderBundle\Form\Type\Rule\Action\DiscountAmountConfigurationType;
use CoreShop\Bundle\OrderBundle\Form\Type\Rule\Action\DiscountPercentConfigurationType;
use CoreShop\Bundle\OrderBundle\Form\Type\Rule\Action\SurchargeAmountConfigurationType;
Expand All @@ -53,6 +54,7 @@
use CoreShop\Component\Rule\Model\ActionInterface;
use CoreShop\Component\Rule\Model\ConditionInterface;
use Doctrine\Persistence\ObjectManager;
use JMS\Serializer\Serializer;
use Symfony\Component\Form\FormFactoryInterface;
use Webmozart\Assert\Assert;

Expand All @@ -62,8 +64,18 @@ final class CartPriceRuleContext implements Context

use ActionFormTrait;

public function __construct(private SharedStorageInterface $sharedStorage, private ObjectManager $objectManager, private FormFactoryInterface $formFactory, private FormTypeRegistryInterface $conditionFormTypeRegistry, private FormTypeRegistryInterface $actionFormTypeRegistry, private FactoryInterface $cartPriceRuleFactory, private CartPriceRuleVoucherRepositoryInterface $cartPriceRuleVoucherRepository, private CartPriceRuleProcessorInterface $cartPriceRuleProcessor, private CartManagerInterface $cartManager, private FactoryInterface $cartPriceRuleVoucherCodeFactory)
{
public function __construct(
private SharedStorageInterface $sharedStorage,
private ObjectManager $objectManager,
private FormFactoryInterface $formFactory,
private FormTypeRegistryInterface $conditionFormTypeRegistry,
private FormTypeRegistryInterface $actionFormTypeRegistry,
private FactoryInterface $cartPriceRuleFactory,
private CartPriceRuleVoucherRepositoryInterface $cartPriceRuleVoucherRepository,
private CartPriceRuleProcessorInterface $cartPriceRuleProcessor,
private CartManagerInterface $cartManager,
private FactoryInterface $cartPriceRuleVoucherCodeFactory,
) {
}

/**
Expand Down Expand Up @@ -474,20 +486,151 @@ public function theVoucherCodeIsACreditCodeWithCreditInCurrency($voucherCode, in
$this->objectManager->flush();
}

private function addCondition(CartPriceRuleInterface $rule, ConditionInterface $condition): void
/**
* @Given /^the (cart rule "[^"]+") has a cart-item-action action$/
* @Given /^the (cart rule) has a cart-item-action action$/
*/
public function theCartPriceRuleHasACartItemActionAction(CartPriceRuleInterface $rule): void
{
$this->assertActionForm(CartItemActionConfigurationType::class, 'cartItemAction');

$action = $this->addAction($rule, $this->createActionWithForm('cartItemAction', [
'actions' => [],
'conditions' => [],
]));

$this->sharedStorage->set('cart-item-action-action', $action);
}

/**
* @Given /^the (cart item action) has a condition amount with value "([^"]+)" to "([^"]+)"$/
*/
public function theCartItemActionHasAAmountCondition(ActionInterface $action, $minAmount, $maxAmount): void
{
$this->assertConditionForm(AmountConfigurationType::class, 'amount');

$this->actionAddCondition($action, $this->createConditionWithForm('amount', [
'minAmount' => $minAmount,
'maxAmount' => $maxAmount,
]));
}

/**
* @Given /^the (cart item action) has a condition products with (product "[^"]+")$/
* @Given /^the (cart item action) has a condition products with (product "[^"]+") and (product "[^"]+")$/
*/
public function theCartItemActionHasAProductCondition(ActionInterface $action, ProductInterface $product, ProductInterface $product2 = null): void
{
$this->assertConditionForm(ProductsConfigurationType::class, 'products');

$configuration = [
'products' => [
$product->getId(),
],
'include_variants' => false,
];

if (null !== $product2) {
$configuration['products'][] = $product2->getId();
}

$this->actionAddCondition($action, $this->createConditionWithForm('products', $configuration));
}

/**
* @Given /^the (cart item action) has a condition categories with (category "[^"]+")$/
*/
public function theCartItemActionHasACategoriesCondition(ActionInterface $action, CategoryInterface $category): void
{
$this->assertConditionForm(CategoriesConfigurationType::class, 'categories');

$this->actionAddCondition($action, $this->createConditionWithForm('categories', [
'categories' => [$category->getId()],
]));
}

/**
* @Given /^the (cart item action) has a action discount-percent with ([^"]+)% discount$/
*/
public function theCartItemActionHasADiscountPercentAction(ActionInterface $action, $discount): void
{
$this->assertActionForm(DiscountPercentConfigurationType::class, 'discountPercent');

$this->actionAddAction($action, $this->createActionWithForm('discountPercent', [
'percent' => (int)$discount,
]));
}

/**
* @Given /^the (cart item action) has a action discount with ([^"]+) in (currency "[^"]+") off$/
* @Given /^the (cart item action) has a action discount with ([^"]+) in (currency "[^"]+") off applied on ([^"]+)$/
*/
public function theCartItemActionHasADiscountAmountAction(ActionInterface $action, $amount, CurrencyInterface $currency, string $appliedOn = 'total'): void
{
$this->assertActionForm(DiscountAmountConfigurationType::class, 'discountAmount');

$this->actionAddAction($action, $this->createActionWithForm('discountAmount', [
'amount' => (int)$amount,
'currency' => $currency->getId(),
'applyOn' => $appliedOn,
]));
}

private function actionAddCondition(ActionInterface $action, ConditionInterface $condition): ConditionInterface
{
$config = $action->getConfiguration();

if (!isset($config['conditions'])) {
$config['conditions'] = [];
}

$config['conditions'][] = $condition;

$action->setConfiguration($config);

$this->objectManager->persist($action);
$this->objectManager->flush();

return $condition;
}


private function actionAddAction(ActionInterface $action, ActionInterface $newAction): ActionInterface
{
$config = $action->getConfiguration();

if (!isset($config['actions'])) {
$config['actions'] = [];
}

$config['actions'][] = $newAction;

$action->setConfiguration($config);

$this->objectManager->persist($action);
$this->objectManager->flush();

return $newAction;
}

private function addCondition(CartPriceRuleInterface $rule, ConditionInterface $condition): ConditionInterface
{
$rule->addCondition($condition);

$this->objectManager->persist($rule);
$this->objectManager->flush();

return $condition;
}

private function addAction(CartPriceRuleInterface $rule, ActionInterface $action): void
private function addAction(CartPriceRuleInterface $rule, ActionInterface $action): ActionInterface
{
$rule->addAction($action);

$this->objectManager->persist($rule);
$this->objectManager->flush();

return $action;
}

protected function getConditionFormRegistry(): FormTypeRegistryInterface
Expand Down
15 changes: 14 additions & 1 deletion src/CoreShop/Behat/Context/Transform/CartPriceRuleContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use CoreShop\Behat\Service\SharedStorageInterface;
use CoreShop\Component\Order\Model\CartPriceRuleInterface;
use CoreShop\Component\Order\Repository\CartPriceRuleRepositoryInterface;
use CoreShop\Component\Rule\Model\ActionInterface;
use Webmozart\Assert\Assert;

final class CartPriceRuleContext implements Context
Expand All @@ -43,10 +44,22 @@ public function getCartPriceRuleByProductAndName($ruleName): CartPriceRuleInterf
*/
public function getLatestCartPriceRule(): CartPriceRuleInterface
{
$resource = $this->sharedStorage->getLatestResource();
$resource = $this->sharedStorage->get('cart-price-rule');

Assert::isInstanceOf($resource, CartPriceRuleInterface::class);

return $resource;
}

/**
* @Transform /^(cart item action)$/
*/
public function getCartItemAction(): ActionInterface
{
$resource = $this->sharedStorage->get('cart-item-action-action');

Assert::isInstanceOf($resource, ActionInterface::class);

return $resource;
}
}
Loading

0 comments on commit 174b24c

Please sign in to comment.