mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-15 17:40:58 +00:00
Merge pull request #5882 from Arminek/verify-complete-checkout
[Checkout][Inventory] Verify complete checkout
This commit is contained in:
commit
66d152dc69
14 changed files with 163 additions and 10 deletions
|
|
@ -1,4 +1,4 @@
|
|||
@shopping_cart
|
||||
@inventory
|
||||
Feature: Inability to add a specific product to the cart when it is out of stock
|
||||
In order to buy only available products
|
||||
As a Visitor
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
@inventory
|
||||
Feature: Being unable to buy products that are out of stock
|
||||
In order to be sure that products I buy are available
|
||||
As a Customer
|
||||
I want to be prevented from placing an order with products that are out of stock
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "United States"
|
||||
And the store has a product "Iron Maiden T-Shirt" priced at "€12.54"
|
||||
And the store also has a product "2Pac T-Shirt" priced at "€13.24"
|
||||
And "Iron Maiden T-Shirt" product is tracked by the inventory
|
||||
And "2Pac T-Shirt" product is also tracked by the inventory
|
||||
And there are 5 units of product "Iron Maiden T-Shirt" available in the inventory
|
||||
And there are 10 units of product "2Pac T-Shirt" available in the inventory
|
||||
And the store ships everywhere for free
|
||||
And the store allows paying offline
|
||||
And I am a logged in customer
|
||||
|
||||
@ui
|
||||
Scenario: Placing an order with products that have sufficient quantity
|
||||
Given I have added 3 products "Iron Maiden T-Shirt" to the cart
|
||||
And I have proceeded selecting "Offline" payment method
|
||||
When I confirm my order
|
||||
Then I should see the thank you page
|
||||
|
||||
@ui
|
||||
Scenario: Being unable to place an order with product that is out of stock
|
||||
Given I have added 5 products "Iron Maiden T-Shirt" to the cart
|
||||
And I have proceeded selecting "Offline" payment method
|
||||
When other customer has bought 2 "Iron Maiden T-Shirt" products by this time
|
||||
And I confirm my order
|
||||
Then I should not see the thank you page
|
||||
And I should be notified that this product does not have sufficient stock
|
||||
|
||||
@ui
|
||||
Scenario: Being unable to place an order with products that are out of stock
|
||||
Given I have added 5 products "Iron Maiden T-Shirt" to the cart
|
||||
And I have added 5 products "2Pac T-Shirt" to the cart
|
||||
And I have proceeded selecting "Offline" payment method
|
||||
When other customer has bought 7 "2Pac T-Shirt" products by this time
|
||||
And I confirm my order
|
||||
Then I should not see the thank you page
|
||||
And I should be notified that this product does not have sufficient stock
|
||||
|
|
@ -126,7 +126,7 @@ final class ProductContext implements Context
|
|||
/**
|
||||
* @Given the store has a product :productName
|
||||
* @Given the store has a :productName product
|
||||
* @Given /^the store has a product "([^"]+)" priced at ("[^"]+")$/
|
||||
* @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+")$/
|
||||
*/
|
||||
public function storeHasAProductPricedAt($productName, $price = 0)
|
||||
{
|
||||
|
|
@ -331,7 +331,8 @@ final class ProductContext implements Context
|
|||
}
|
||||
|
||||
/**
|
||||
* @Given /^there (?:is|are) (\d+) item(?:s) of (product "([^"]+)") available in the inventory$/
|
||||
* @Given /^there (?:is|are) (\d+) (?:item|unit)(?:s) of (product "([^"]+)") available in the inventory$/
|
||||
* @When product :product quantity is changed to :quantity
|
||||
*/
|
||||
public function thereIsQuantityOfProducts($quantity, ProductInterface $product)
|
||||
{
|
||||
|
|
@ -348,6 +349,30 @@ final class ProductContext implements Context
|
|||
$this->setProductsQuantity($product, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When other customer has bought :quantity :product products by this time
|
||||
*/
|
||||
public function otherCustomerHasBoughtProductsByThisTime($quantity, ProductInterface $product)
|
||||
{
|
||||
/** @var ProductVariantInterface $productVariant */
|
||||
$productVariant = $this->defaultVariantResolver->getVariant($product);
|
||||
$productQuantity = $productVariant->getOnHand() - $quantity;
|
||||
|
||||
$this->setProductsQuantity($product, $productQuantity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^(this product) is tracked by the inventory$/
|
||||
* @Given /^("[^"]+" product) is(?:| also) tracked by the inventory$/
|
||||
*/
|
||||
public function thisProductIsTrackedByTheInventory(ProductInterface $product)
|
||||
{
|
||||
$variant = $this->defaultVariantResolver->getVariant($product);
|
||||
$variant->setTracked(true);
|
||||
|
||||
$this->objectManager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^(this product) is available in "([^"]+)" size priced at ("[^"]+")$/
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -34,9 +34,8 @@ final class ProductContext implements Context
|
|||
}
|
||||
|
||||
/**
|
||||
* @Transform /^product "([^"]+)"$/
|
||||
* @Transform /^"([^"]+)" product$/
|
||||
* @Transform /^"([^"]+)" products$/
|
||||
* @Transform /^product(?:|s) "([^"]+)"$/
|
||||
* @Transform /^"([^"]+)" product(?:|s)$/
|
||||
* @Transform /^(?:a|an) "([^"]+)"$/
|
||||
* @Transform :product
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -487,6 +487,17 @@ final class CheckoutContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not see the thank you page
|
||||
*/
|
||||
public function iShouldNotSeeTheThankYouPage()
|
||||
{
|
||||
Assert::false(
|
||||
$this->thankYouPage->isOpen(),
|
||||
'I should not see thank you message, but I do'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given I should be informed with :paymentMethod payment method instructions
|
||||
*/
|
||||
|
|
@ -915,6 +926,17 @@ final class CheckoutContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I should be notified that (this product) does not have sufficient stock$/
|
||||
*/
|
||||
public function iShouldBeNotifiedThatThisProductDoesNotHaveSufficientStock(ProductInterface $product)
|
||||
{
|
||||
Assert::true(
|
||||
$this->completePage->hasProductOutOfStockValidationMessage($product),
|
||||
sprintf('I should see validation message for %s product', $product->getName())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AddressInterface
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -303,10 +303,10 @@ final class CartContext implements Context
|
|||
}
|
||||
|
||||
/**
|
||||
* @Given I have :quantity products :product in the cart
|
||||
* @When I add :quantity products :product to the cart
|
||||
* @Given /^I have(?:| added) (\d+) (products "([^"]+)") (?:to|in) the cart$/
|
||||
* @When /^I add(?:|ed) (\d+) (products "([^"]+)") to the cart$/
|
||||
*/
|
||||
public function iAddProductsToTheCart(ProductInterface $product, $quantity)
|
||||
public function iAddProductsToTheCart($quantity, ProductInterface $product)
|
||||
{
|
||||
$this->productShowPage->open(['slug' => $product->getSlug()]);
|
||||
$this->productShowPage->addToCartWithQuantity($quantity);
|
||||
|
|
|
|||
|
|
@ -193,6 +193,16 @@ class CompletePage extends SymfonyPage implements CompletePageInterface
|
|||
return null !== $productRowElement->find('css', sprintf('td:contains("%s")', $price));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasProductOutOfStockValidationMessage(ProductInterface $product)
|
||||
{
|
||||
$message = sprintf('%s does not have sufficient stock.', $product->getName());
|
||||
|
||||
return $this->getElement('validation_errors')->getText() === $message;
|
||||
}
|
||||
|
||||
public function confirmOrder()
|
||||
{
|
||||
$this->getDocument()->pressButton('Place order');
|
||||
|
|
@ -234,6 +244,7 @@ class CompletePage extends SymfonyPage implements CompletePageInterface
|
|||
'shipping_step_label' => '.steps a:contains("Shipping")',
|
||||
'shipping_total' => '#shipping-total',
|
||||
'tax_total' => '#tax-total',
|
||||
'validation_errors' => '.sylius-validation-error',
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114,6 +114,13 @@ interface CompletePageInterface
|
|||
*/
|
||||
public function hasProductUnitPrice(ProductInterface $product, $price);
|
||||
|
||||
/**
|
||||
* @param ProductInterface $product
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasProductOutOfStockValidationMessage(ProductInterface $product);
|
||||
|
||||
public function changeAddress();
|
||||
|
||||
public function changeShippingMethod();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ imports:
|
|||
- suites/ui/checkout/paying_for_order.yml
|
||||
- suites/ui/currency/currencies.yml
|
||||
- suites/ui/currency/managing_currencies.yml
|
||||
- suites/ui/inventory/inventory.yml
|
||||
- suites/ui/locale/locales.yml
|
||||
- suites/ui/locale/managing_locales.yml
|
||||
- suites/ui/order/managing_orders.yml
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# This file is part of the Sylius package.
|
||||
# (c) Paweł Jędrzejewski
|
||||
|
||||
default:
|
||||
suites:
|
||||
ui_inventory:
|
||||
contexts_as_services:
|
||||
- sylius.behat.context.hook.doctrine_orm
|
||||
|
||||
- sylius.behat.context.setup.channel
|
||||
- sylius.behat.context.setup.currency
|
||||
- sylius.behat.context.setup.geographical
|
||||
- sylius.behat.context.setup.payment
|
||||
- sylius.behat.context.setup.product
|
||||
- sylius.behat.context.setup.shipping
|
||||
- sylius.behat.context.setup.shop_security
|
||||
- sylius.behat.context.setup.user
|
||||
|
||||
- sylius.behat.context.transform.addressing
|
||||
- sylius.behat.context.transform.lexical
|
||||
- sylius.behat.context.transform.payment
|
||||
- sylius.behat.context.transform.product
|
||||
- sylius.behat.context.transform.product_option
|
||||
- sylius.behat.context.transform.shared_storage
|
||||
|
||||
- sylius.behat.context.ui.checkout
|
||||
- sylius.behat.context.ui.paypal
|
||||
- sylius.behat.context.ui.shop.cart
|
||||
- sylius.behat.context.ui.shop.product
|
||||
- sylius.behat.context.ui.user
|
||||
|
||||
filters:
|
||||
tags: "@inventory && @ui"
|
||||
|
|
@ -127,7 +127,10 @@
|
|||
<class name="Sylius\Component\Cart\Model\CartItem">
|
||||
<constraint name="Sylius\Bundle\InventoryBundle\Validator\Constraints\InStock">
|
||||
<option name="stockablePath">variant</option>
|
||||
<option name="groups">sylius</option>
|
||||
<option name="groups">
|
||||
<value>sylius_checkout_complete</value>
|
||||
<value>sylius</value>
|
||||
</option>
|
||||
</constraint>
|
||||
</class>
|
||||
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ sylius_shop_checkout_complete:
|
|||
redirect: sylius_shop_checkout_thank_you
|
||||
form:
|
||||
type: sylius_checkout_complete
|
||||
options:
|
||||
validation_groups: 'sylius_checkout_complete'
|
||||
|
||||
sylius_shop_checkout_thank_you:
|
||||
path: /thank-you
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
{% include '@SyliusShop/Checkout/_steps.html.twig' with {'active': 'complete'} %}
|
||||
<div class="ui padded segment">
|
||||
{{ form_start(form, {'action': path('sylius_shop_checkout_complete'), 'attr': {'class': 'ui loadable form', 'novalidate': 'novalidate'}}) }}
|
||||
{{ form_errors(form) }}
|
||||
<input type="hidden" name="_method" value="PUT" />
|
||||
|
||||
{% include 'SyliusShopBundle:Common/Order:_summary.html.twig' %}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,17 @@
|
|||
namespace Sylius\Component\Variation\Resolver;
|
||||
|
||||
use Sylius\Component\Variation\Model\VariableInterface;
|
||||
use Sylius\Component\Variation\Model\VariantInterface;
|
||||
|
||||
/**
|
||||
* @author Anna Walasek <anna.walasek@lakion.com>
|
||||
*/
|
||||
interface VariantResolverInterface
|
||||
{
|
||||
/**
|
||||
* @param VariableInterface $subject
|
||||
*
|
||||
* @return VariantInterface
|
||||
*/
|
||||
public function getVariant(VariableInterface $subject);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue