mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 17:10:53 +00:00
[API] Adding product from another channel
This commit is contained in:
parent
7e36ac986e
commit
43f2068de1
10 changed files with 275 additions and 1 deletions
|
|
@ -1,7 +1,7 @@
|
|||
@checkout
|
||||
Feature: Preventing adding to cart disabled products
|
||||
In order to have correct products in cart when adding them
|
||||
As a customer
|
||||
As a Customer
|
||||
I want to have the added products validated
|
||||
|
||||
Background:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
@checkout
|
||||
Feature: Preventing adding to cart product or variant from another channel
|
||||
In order to have correct products in cart when adding them
|
||||
As a Customer
|
||||
I want to have the added products validated
|
||||
|
||||
Background:
|
||||
Given the store operates on a channel named "France" with hostname "france"
|
||||
And the store has a "Baquette" configurable product
|
||||
And this product has "Small", "Medium" and "Large" variants
|
||||
And the store has a "Pain" product
|
||||
And the store operates on a channel named "Poland" with hostname "poland"
|
||||
And I am a logged in customer
|
||||
|
||||
@api
|
||||
Scenario: Preventing customer from adding simple product from another channel
|
||||
Given I am browsing channel "Poland"
|
||||
When I pick up my cart
|
||||
And I try to add product "Pain" to the cart
|
||||
Then I should be informed that product "Pain" does not exist
|
||||
|
||||
@api
|
||||
Scenario: Preventing customer from adding product with variant from another channel
|
||||
Given I am browsing channel "Poland"
|
||||
When I pick up my cart
|
||||
And I try to add "Large" variant of product "Baquette"
|
||||
Then I should be informed that product "Baquette" does not exist
|
||||
|
|
@ -859,6 +859,7 @@ final class CheckoutContext implements Context
|
|||
|
||||
/**
|
||||
* @When /^I try to add ("([^"]+)" product variant)$/
|
||||
* @When /^I try to add ("([^"]+)" variant of product "([^"]+)")$/
|
||||
*/
|
||||
public function iTryToAddProductVariant(ProductVariantInterface $productVariant): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ default:
|
|||
- sylius.behat.context.api.admin.managing_orders
|
||||
|
||||
- sylius.behat.context.api.shop.cart
|
||||
- sylius.behat.context.api.shop.channel
|
||||
- sylius.behat.context.api.shop.address
|
||||
- sylius.behat.context.api.shop.checkout
|
||||
- sylius.behat.context.api.shop.login
|
||||
|
|
|
|||
|
|
@ -38,6 +38,12 @@
|
|||
<tag name="validator.constraint_validator" alias="sylius_api_validator_order_shipping_method_eligibility" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.api.validator.product_available_in_channel" class="Sylius\Bundle\ApiBundle\Validator\Constraints\ProductAvailableInChannelValidator">
|
||||
<argument type="service" id="sylius.repository.product_variant" />
|
||||
<argument type="service" id="sylius.repository.order" />
|
||||
<tag name="validator.constraint_validator" alias="sylius_api_validator_product_available_in_channel" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.api.validator.product_or_variant_enabled" class="Sylius\Bundle\ApiBundle\Validator\Constraints\ProductOrVariantEnabledValidator">
|
||||
<argument type="service" id="sylius.repository.product_variant" />
|
||||
<tag name="validator.constraint_validator" alias="sylius_api_validator_product_or_variant_enabled" />
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@
|
|||
<value>sylius</value>
|
||||
</option>
|
||||
</constraint>
|
||||
<constraint name="Sylius\Bundle\ApiBundle\Validator\Constraints\ProductAvailableInChannel">
|
||||
<option name="groups">
|
||||
<value>sylius</value>
|
||||
</option>
|
||||
</constraint>
|
||||
<property name="quantity">
|
||||
<constraint name="Range">
|
||||
<option name="min">1</option>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
sylius:
|
||||
order:
|
||||
not_empty: 'An empty order cannot be completed.'
|
||||
product:
|
||||
channel:
|
||||
does_not_exist: 'The product %productName% does not exist.'
|
||||
shipment:
|
||||
shipped: 'You cannot ship a shipment that was shipped before.'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\ApiBundle\Validator\Constraints;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/** @experimental */
|
||||
final class ProductAvailableInChannel extends Constraint
|
||||
{
|
||||
/** @var string */
|
||||
public $message = 'sylius.product.channel.does_not_exist';
|
||||
|
||||
public function validatedBy(): string
|
||||
{
|
||||
return 'sylius_api_validator_product_available_in_channel';
|
||||
}
|
||||
|
||||
public function getTargets(): string
|
||||
{
|
||||
return self::CLASS_CONSTRAINT;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\ApiBundle\Validator\Constraints;
|
||||
|
||||
use Sylius\Bundle\ApiBundle\Command\Cart\AddItemToCart;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\ProductInterface;
|
||||
use Sylius\Component\Core\Model\ProductVariantInterface;
|
||||
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
|
||||
use Sylius\Component\Product\Repository\ProductVariantRepositoryInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/** @experimental */
|
||||
final class ProductAvailableInChannelValidator extends ConstraintValidator
|
||||
{
|
||||
/** @var ProductVariantRepositoryInterface */
|
||||
private $productVariantRepository;
|
||||
|
||||
/** @var OrderRepositoryInterface */
|
||||
private $orderRepository;
|
||||
|
||||
public function __construct(
|
||||
ProductVariantRepositoryInterface $productVariantRepository,
|
||||
OrderRepositoryInterface $orderRepository
|
||||
) {
|
||||
$this->productVariantRepository = $productVariantRepository;
|
||||
$this->orderRepository = $orderRepository;
|
||||
}
|
||||
|
||||
public function validate($value, Constraint $constraint)
|
||||
{
|
||||
Assert::isInstanceOf($value, AddItemToCart::class);
|
||||
|
||||
/** @var ProductAvailableInChannel $constraint */
|
||||
Assert::isInstanceOf($constraint, ProductAvailableInChannel::class);
|
||||
|
||||
/** @var OrderInterface $cart */
|
||||
$cart = $this->orderRepository->findCartByTokenValue($value->getOrderTokenValue());
|
||||
|
||||
/** @var ProductVariantInterface $productVariant */
|
||||
$productVariant = $this->productVariantRepository->findOneBy(['code' => $value->productVariantCode]);
|
||||
|
||||
Assert::notNull($cartChannel = $cart->getChannel());
|
||||
|
||||
/** @var ProductInterface $product */
|
||||
$product = $productVariant->getProduct();
|
||||
|
||||
if (!$product->hasChannel($cartChannel)) {
|
||||
$this->context->addViolation(
|
||||
$constraint->message,
|
||||
['%productName%' => $product->getName()]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace spec\Sylius\Bundle\ApiBundle\Validator\Constraints;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ApiBundle\Command\Cart\AddItemToCart;
|
||||
use Sylius\Bundle\ApiBundle\Command\Checkout\CompleteOrder;
|
||||
use Sylius\Bundle\ApiBundle\Validator\Constraints\ProductAvailableInChannel;
|
||||
use Sylius\Component\Core\Model\ChannelInterface;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\ProductInterface;
|
||||
use Sylius\Component\Core\Model\ProductVariantInterface;
|
||||
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
|
||||
use Sylius\Component\Core\Repository\ProductVariantRepositoryInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidatorInterface;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
final class ProductAvailableInChannelValidatorSpec extends ObjectBehavior
|
||||
{
|
||||
function let(
|
||||
ProductVariantRepositoryInterface $productVariantRepository,
|
||||
OrderRepositoryInterface $orderRepository
|
||||
): void {
|
||||
$this->beConstructedWith($productVariantRepository, $orderRepository);
|
||||
}
|
||||
|
||||
function it_is_a_constraint_validator(): void
|
||||
{
|
||||
$this->shouldImplement(ConstraintValidatorInterface::class);
|
||||
}
|
||||
|
||||
function it_throws_an_exception_if_value_is_not_an_instance_of_product_or_variant_enabled_class(): void
|
||||
{
|
||||
$this
|
||||
->shouldThrow(\InvalidArgumentException::class)
|
||||
->during('validate', [new CompleteOrder(), new class() extends Constraint {
|
||||
}]);
|
||||
}
|
||||
|
||||
function it_throws_an_exception_if_constraint_is_not_an_instance_of_add_item_to_cart(): void
|
||||
{
|
||||
$this
|
||||
->shouldThrow(\InvalidArgumentException::class)
|
||||
->during('validate', ['', new class() extends Constraint {
|
||||
}]);
|
||||
}
|
||||
|
||||
function it_adds_violation_if_product_is_not_available_in_channel(
|
||||
ProductVariantRepositoryInterface $productVariantRepository,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
ChannelInterface $channel,
|
||||
ProductVariantInterface $productVariant,
|
||||
ProductInterface $product,
|
||||
OrderInterface $cart,
|
||||
ExecutionContextInterface $executionContext
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$value = new AddItemToCart('productCode', 'productVariantCode', 1);
|
||||
$value->setOrderTokenValue('TOKEN');
|
||||
$constraint = new ProductAvailableInChannel();
|
||||
$constraint->message = 'message';
|
||||
|
||||
$orderRepository->findCartByTokenValue('TOKEN')->willReturn($cart);
|
||||
$productVariantRepository->findOneBy(['code' => 'productVariantCode'])->willReturn($productVariant);
|
||||
$cart->getChannel()->willReturn($channel);
|
||||
|
||||
$productVariant->getProduct()->willReturn($product);
|
||||
|
||||
$product->hasChannel($channel)->willReturn(false);
|
||||
$product->getName()->willReturn('PRODUCTNAME');
|
||||
$executionContext
|
||||
->addViolation(
|
||||
'message',
|
||||
['%productName%' => 'PRODUCTNAME']
|
||||
)
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
|
||||
function it_does_nothing_if_product_is_available_in_channel(
|
||||
ProductVariantRepositoryInterface $productVariantRepository,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
ChannelInterface $channel,
|
||||
ProductVariantInterface $productVariant,
|
||||
ProductInterface $product,
|
||||
OrderInterface $cart,
|
||||
ExecutionContextInterface $executionContext
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$value = new AddItemToCart('productCode', 'productVariantCode', 1);
|
||||
$value->setOrderTokenValue('TOKEN');
|
||||
$constraint = new ProductAvailableInChannel();
|
||||
$constraint->message = 'message';
|
||||
|
||||
$orderRepository->findCartByTokenValue('TOKEN')->willReturn($cart);
|
||||
$productVariantRepository->findOneBy(['code' => 'productVariantCode'])->willReturn($productVariant);
|
||||
$cart->getChannel()->willReturn($channel);
|
||||
|
||||
$productVariant->getProduct()->willReturn($product);
|
||||
|
||||
$product->hasChannel($channel)->willReturn(true);
|
||||
$product->getName()->willReturn('PRODUCTNAME');
|
||||
$executionContext
|
||||
->addViolation(
|
||||
'message',
|
||||
['%productName%' => 'PRODUCTNAME']
|
||||
)
|
||||
->shouldNotBeCalled();
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue