mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
Merge branch '1.12' into 1.13
* 1.12: Provide post-CR fixes Fix static analysis Adjust scenarios to use less technical language Prevent placing an order with not available shipping method Add behat scenario covering preventing a placing an order with a disabled shipping method Add behat scenario covering expires session while cart updating [API] Fix CommandDenormalizer ignoring custom property names Update OrderController.php with early return check before refreshing from db
This commit is contained in:
commit
34e77e5d0f
25 changed files with 598 additions and 22 deletions
|
|
@ -11,3 +11,12 @@ Feature: Viewing a cart summary
|
|||
Scenario: Viewing information about empty cart
|
||||
When I see the summary of my cart
|
||||
Then my cart should be empty
|
||||
|
||||
@ui @no-api
|
||||
Scenario: Viewing information about empty cart after clearing cookies
|
||||
Given the store has a product "T-Shirt banana" priced at "$12.54"
|
||||
And I added this product to the cart
|
||||
And I am on the summary of my cart page
|
||||
But I've been gone for a long time
|
||||
When I try to update my cart
|
||||
Then I should see an empty cart
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
@checkout
|
||||
Feature: Preventing placing an order with a disabled shipping method
|
||||
In order to have my order shipped without issues
|
||||
As a Customer
|
||||
I want to be prevented from placing an order with a disabled shipping method
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in the "United States" named "US Web Store"
|
||||
And the store has a product "Ubi T-Shirt" priced at "$19.99"
|
||||
And the store has "Raven Post" shipping method with "$4.00" fee
|
||||
And the store allows paying "Offline"
|
||||
And I am a logged in customer
|
||||
|
||||
@ui @api
|
||||
Scenario: Being prevented from placing an order with a shipping method that's disabled after completing the shipping method choice step
|
||||
Given I added product "Ubi T-Shirt" to the cart
|
||||
And I have proceeded through checkout process with "Raven Post" shipping method
|
||||
But this shipping method has been disabled
|
||||
When I try to confirm my order
|
||||
Then I should not be able to confirm order because the "Raven Post" shipping method is not available
|
||||
|
||||
@ui @api
|
||||
Scenario: Being prevented from placing an order with a shipping method that's has been disabled for the customer's country after completing the shipping method choice step
|
||||
Given I added product "Ubi T-Shirt" to the cart
|
||||
And I have proceeded through checkout process with "Raven Post" shipping method
|
||||
But this shipping method has been disabled for "US Web Store" channel
|
||||
When I try to confirm my order
|
||||
Then I should not be able to confirm order because the "Raven Post" shipping method is not available
|
||||
|
|
@ -39,3 +39,4 @@ parameters:
|
|||
- '/Class Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken constructor invoked with 4 parameters\, 2\-3 required./'
|
||||
- '/Method Symfony\\Component\\Serializer\\Normalizer\\NormalizerInterface\:\:supportsNormalization\(\) invoked with 3 parameters\, 1\-2 required\./'
|
||||
- '/(Interface|Class) [a-zA-Z\\]+ specifies template type (\w+) of interface [a-zA-Z\\]+ as [a-zA-Z\\]+ (of [a-zA-Z\\]+ )?but it''s already specified as/' # turns off a weird generics check behavior, we are basing on Psalm for generics checks
|
||||
- '/Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface::normalize\(\) invoked with 2 parameters, 1 required./'
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@
|
|||
<referencedFunction name="Symfony\Component\HttpKernel\Config\FileLocator::__construct" />
|
||||
<referencedFunction name="Symfony\Contracts\EventDispatcher\EventDispatcherInterface::dispatch" />
|
||||
<referencedFunction name="Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken::__construct" /> <!-- removed parameter in Symfony 5.4 -->
|
||||
<referencedFunction name="Symfony\Component\Serializer\NameConverter\NameConverterInterface::normalize" />
|
||||
</errorLevel>
|
||||
<errorLevel type="suppress">
|
||||
<referencedFunction name="Doctrine\ORM\Query\Expr::andX" />
|
||||
|
|
|
|||
|
|
@ -523,6 +523,22 @@ final class CheckoutContext implements Context
|
|||
$this->iChoosePaymentMethod($paymentMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given I have proceeded through checkout process with :shippingMethod shipping method
|
||||
*/
|
||||
public function iHaveProceededThroughCheckoutProcessWithShippingMethod(ShippingMethodInterface $shippingMethod): void
|
||||
{
|
||||
$this->addressOrder($this->getArrayWithDefaultAddress());
|
||||
|
||||
$this->selectShippingMethod($shippingMethod);
|
||||
|
||||
/** @var PaymentMethodInterface $paymentMethod */
|
||||
$paymentMethod = $this->paymentMethodRepository->findOneBy([]);
|
||||
$this->iChoosePaymentMethod($paymentMethod);
|
||||
|
||||
$this->sharedStorage->set('shipping_method', $shippingMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^(address "[^"]+", "[^"]+", "[^"]+", "[^"]+", "[^"]+", "[^"]+") should be filled as (billing) address$/
|
||||
* @Then /^the visitor should has ("[^"]+", "[^"]+", "[^"]+", "[^"]+", "[^"]+" specified as) (billing) address$/
|
||||
|
|
@ -1226,6 +1242,20 @@ final class CheckoutContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not be able to confirm order because the :shippingMethodName shipping method is not available
|
||||
*/
|
||||
public function iShouldNotBeAbleToConfirmOrderBecauseTheShippingMethodIsNotAvailable(string $shippingMethodName): void
|
||||
{
|
||||
Assert::same(
|
||||
$this->responseChecker->getError($this->client->getLastResponse()),
|
||||
sprintf(
|
||||
'The "%s" shipping method is not available. Please reselect your shipping method.',
|
||||
$shippingMethodName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I should see (product "[^"]+") with unit price ("[^"]+")$/
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -546,6 +546,24 @@ final class ShippingContext implements Context
|
|||
$this->addRuleToShippingMethod($rule, $shippingMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^(this shipping method) has been disabled$/
|
||||
* @Given /^(this shipping method) has been disabled for ("[^"]+" channel)$/
|
||||
*/
|
||||
public function thisShippingMethodHasBeenDisabled(ShippingMethodInterface $shippingMethod, ?ChannelInterface $channel = null): void
|
||||
{
|
||||
/** @var ShippingMethodInterface $shippingMethod */
|
||||
$shippingMethod = $this->shippingMethodRepository->findOneBy(['code' => $shippingMethod->getCode()]);
|
||||
|
||||
if (null === $channel) {
|
||||
$shippingMethod->disable();
|
||||
} else {
|
||||
$shippingMethod->removeChannel($channel);
|
||||
}
|
||||
|
||||
$this->shippingMethodManager->flush();
|
||||
}
|
||||
|
||||
private function getConfigurationByChannels(array $channels, int $amount = 0): array
|
||||
{
|
||||
$configuration = [];
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ namespace Sylius\Behat\Context\Ui\Shop;
|
|||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Mink\Exception\ElementNotFoundException;
|
||||
use Sylius\Behat\Element\BrowserElementInterface;
|
||||
use Sylius\Behat\Element\Shop\CartWidgetElementInterface;
|
||||
use Sylius\Behat\Element\Shop\CheckoutSubtotalElementInterface;
|
||||
use Sylius\Behat\NotificationType;
|
||||
|
|
@ -40,6 +41,7 @@ final class CartContext implements Context
|
|||
private CartWidgetElementInterface $cartWidgetElement,
|
||||
private NotificationCheckerInterface $notificationChecker,
|
||||
private SessionManagerInterface $sessionManager,
|
||||
private BrowserElementInterface $browserElement,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -53,8 +55,17 @@ final class CartContext implements Context
|
|||
$this->summaryPage->open();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given I've been gone for a long time
|
||||
*/
|
||||
public function iveBeenGoneForLongTime(): void
|
||||
{
|
||||
$this->browserElement->resetSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I update my cart
|
||||
* @When I try to update my cart
|
||||
*/
|
||||
public function iUpdateMyCart()
|
||||
{
|
||||
|
|
@ -590,6 +601,14 @@ final class CartContext implements Context
|
|||
Assert::same($this->checkoutSubtotalElement->getProductQuantity($productName), $quantity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should see an empty cart
|
||||
*/
|
||||
public function iShouldSeeAnEmptyCart(): void
|
||||
{
|
||||
Assert::true($this->summaryPage->isEmpty());
|
||||
}
|
||||
|
||||
private function getPriceFromString(string $price): int
|
||||
{
|
||||
return (int) round((float) str_replace(['€', '£', '$'], '', $price) * 100, 2);
|
||||
|
|
|
|||
|
|
@ -372,6 +372,20 @@ final class CheckoutCompleteContext implements Context
|
|||
throw new UnexpectedPageException('It should not be possible to complete checkout complete step.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not be able to confirm order because the :shippingMethodName shipping method is not available
|
||||
*/
|
||||
public function iShouldNotBeAbleToConfirmOrderBecauseTheShippingMethodIsNotAvailable(string $shippingMethodName): void
|
||||
{
|
||||
Assert::same(
|
||||
$this->completePage->getValidationErrors(),
|
||||
sprintf(
|
||||
'The "%s" shipping method is not available. Please reselect your shipping method.',
|
||||
$shippingMethodName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I should see (product "[^"]+") with unit price ("[^"]+")$/
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ use Sylius\Behat\Page\Shop\Checkout\CompletePageInterface;
|
|||
use Sylius\Behat\Page\Shop\Checkout\SelectPaymentPageInterface;
|
||||
use Sylius\Behat\Page\Shop\Checkout\SelectShippingPageInterface;
|
||||
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
|
||||
use Sylius\Behat\Service\SharedStorageInterface;
|
||||
use Sylius\Component\Addressing\Model\CountryInterface;
|
||||
use Sylius\Component\Core\Model\ShippingMethodInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class CheckoutContext implements Context
|
||||
|
|
@ -41,6 +43,7 @@ final class CheckoutContext implements Context
|
|||
private CheckoutAddressingContext $addressingContext,
|
||||
private CheckoutShippingContext $shippingContext,
|
||||
private CheckoutPaymentContext $paymentContext,
|
||||
private SharedStorageInterface $sharedStorage,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -99,6 +102,18 @@ final class CheckoutContext implements Context
|
|||
$this->paymentContext->iCompleteThePaymentStep();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given I have proceeded through checkout process with :shippingMethod shipping method
|
||||
*/
|
||||
public function iHaveProceededThroughCheckoutProcessWithShippingMethod(ShippingMethodInterface $shippingMethod): void
|
||||
{
|
||||
$this->addressingContext->iProceedSelectingBillingCountry();
|
||||
$this->shippingContext->iHaveProceededSelectingShippingMethod($shippingMethod->getName());
|
||||
$this->paymentContext->iCompleteThePaymentStep();
|
||||
|
||||
$this->sharedStorage->set('shipping_method', $shippingMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I proceed selecting ("[^"]+" as billing country) with "([^"]+)" method$/
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -21,4 +21,9 @@ final class BrowserElement extends Element implements BrowserElementInterface
|
|||
{
|
||||
$this->getDriver()->back();
|
||||
}
|
||||
|
||||
public function resetSession(): void
|
||||
{
|
||||
$this->getSession()->setCookie('MOCKSESSID');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@ namespace Sylius\Behat\Element;
|
|||
interface BrowserElementInterface
|
||||
{
|
||||
public function goBack(): void;
|
||||
|
||||
public function resetSession(): void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -372,6 +372,7 @@
|
|||
<argument type="service" id="sylius.behat.context.ui.shop.checkout.addressing" />
|
||||
<argument type="service" id="sylius.behat.context.ui.shop.checkout.shipping" />
|
||||
<argument type="service" id="sylius.behat.context.ui.shop.checkout.payment" />
|
||||
<argument type="service" id="sylius.behat.shared_storage" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.behat.context.ui.shop.checkout.thank_you" class="Sylius\Behat\Context\Ui\Shop\Checkout\CheckoutThankYouContext">
|
||||
|
|
@ -484,6 +485,7 @@
|
|||
<argument type="service" id="Sylius\Behat\Element\Shop\CartWidgetElementInterface" />
|
||||
<argument type="service" id="sylius.behat.notification_checker" />
|
||||
<argument type="service" id="Sylius\Behat\Service\SessionManagerInterface"/>
|
||||
<argument type="service" id="sylius.behat.element.browser" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.behat.context.ui.shop.contact" class="Sylius\Behat\Context\Ui\Shop\ContactContext">
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ default:
|
|||
- sylius.behat.context.setup.zone
|
||||
- Sylius\Behat\Context\Setup\CatalogPromotionContext
|
||||
|
||||
- sylius.behat.context.ui.browser
|
||||
- sylius.behat.context.ui.channel
|
||||
- sylius.behat.context.ui.shop.cart
|
||||
- sylius.behat.context.ui.shop.currency
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
<service id="Sylius\Bundle\ApiBundle\Serializer\CommandDenormalizer">
|
||||
<argument type="service" id="api_platform.serializer.normalizer.item" />
|
||||
<argument type="service" id="api_platform.name_converter" />
|
||||
<tag name="serializer.normalizer" />
|
||||
</service>
|
||||
|
||||
|
|
|
|||
|
|
@ -14,18 +14,19 @@ declare(strict_types=1);
|
|||
namespace Sylius\Bundle\ApiBundle\Serializer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
|
||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
/** @experimental */
|
||||
final class CommandDenormalizer implements ContextAwareDenormalizerInterface
|
||||
{
|
||||
private const OBJECT_TO_POPULATE = 'object_to_populate';
|
||||
|
||||
public function __construct(private DenormalizerInterface $itemNormalizer)
|
||||
{
|
||||
public function __construct(
|
||||
private DenormalizerInterface $itemNormalizer,
|
||||
private NameConverterInterface $nameConverter,
|
||||
) {
|
||||
}
|
||||
|
||||
public function supportsDenormalization($data, $type, $format = null, array $context = []): bool
|
||||
|
|
@ -39,23 +40,28 @@ final class CommandDenormalizer implements ContextAwareDenormalizerInterface
|
|||
return $this->itemNormalizer->denormalize($data, $type, $format, $context);
|
||||
}
|
||||
|
||||
$constructor = (new \ReflectionClass($context['input']['class']))->getConstructor();
|
||||
$class = $context['input']['class'];
|
||||
$constructor = (new \ReflectionClass($class))->getConstructor();
|
||||
|
||||
if (null !== $constructor) {
|
||||
$this->assertConstructorArgumentsPresence($constructor, $data);
|
||||
$this->assertConstructorArgumentsPresence($constructor, $class, $data);
|
||||
}
|
||||
|
||||
return $this->itemNormalizer->denormalize($data, $type, $format, $context);
|
||||
}
|
||||
|
||||
private function assertConstructorArgumentsPresence(\ReflectionMethod $constructor, $data): void
|
||||
{
|
||||
private function assertConstructorArgumentsPresence(
|
||||
\ReflectionMethod $constructor,
|
||||
string $class,
|
||||
mixed $data
|
||||
): void {
|
||||
$parameters = $constructor->getParameters();
|
||||
|
||||
$missingFields = [];
|
||||
foreach ($parameters as $parameter) {
|
||||
if (!isset($data[$parameter->getName()]) && !($parameter->allowsNull() || $parameter->isDefaultValueAvailable())) {
|
||||
$missingFields[] = $parameter->getName();
|
||||
$name = $this->nameConverter->normalize($parameter->getName(), $class);
|
||||
if (!isset($data[$name]) && !($parameter->allowsNull() || $parameter->isDefaultValueAvailable())) {
|
||||
$missingFields[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,28 @@ use Symfony\Component\Validator\Constraint;
|
|||
/** @experimental */
|
||||
final class OrderShippingMethodEligibility extends Constraint
|
||||
{
|
||||
public string $message = 'sylius.order.shipping_method_eligibility';
|
||||
/**
|
||||
* @param array<array-key, mixed> $options
|
||||
*/
|
||||
public function __construct(
|
||||
array $options = [],
|
||||
public string $message = 'sylius.order.shipping_method_eligibility',
|
||||
public string $methodNotAvailableMessage = 'sylius.order.shipping_method_not_available',
|
||||
mixed $groups = null,
|
||||
mixed $payload = null,
|
||||
) {
|
||||
parent::__construct($options, $groups, $payload);
|
||||
}
|
||||
|
||||
public function getMessage(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function getMethodNotAvailableMessage(): string
|
||||
{
|
||||
return $this->methodNotAvailableMessage;
|
||||
}
|
||||
|
||||
public function validatedBy(): string
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ final class OrderShippingMethodEligibilityValidator extends ConstraintValidator
|
|||
) {
|
||||
}
|
||||
|
||||
public function validate($value, Constraint $constraint)
|
||||
public function validate(mixed $value, Constraint $constraint)
|
||||
{
|
||||
Assert::isInstanceOf($value, OrderTokenValueAwareInterface::class);
|
||||
|
||||
|
|
@ -49,9 +49,18 @@ final class OrderShippingMethodEligibilityValidator extends ConstraintValidator
|
|||
/** @var ShippingMethodInterface $shippingMethod */
|
||||
$shippingMethod = $shipment->getMethod();
|
||||
|
||||
if (!$shippingMethod->isEnabled() || !$shippingMethod->getChannels()->contains($order->getChannel())) {
|
||||
$this->context->addViolation(
|
||||
$constraint->getMethodNotAvailableMessage(),
|
||||
['%shippingMethodName%' => $shippingMethod->getName()],
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->eligibilityChecker->isEligible($shipment, $shippingMethod)) {
|
||||
$this->context->addViolation(
|
||||
$constraint->message,
|
||||
$constraint->getMessage(),
|
||||
['%shippingMethodName%' => $shippingMethod->getName()],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,21 +19,29 @@ use Sylius\Bundle\ApiBundle\Command\Account\RegisterShopUser;
|
|||
use Sylius\Bundle\ApiBundle\Command\Account\VerifyCustomerAccount;
|
||||
use Sylius\Component\Core\Model\Customer;
|
||||
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
|
||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
|
||||
final class CommandDenormalizerSpec extends ObjectBehavior
|
||||
{
|
||||
function let(DenormalizerInterface $baseNormalizer): void
|
||||
function let(DenormalizerInterface $baseNormalizer, NameConverterInterface $nameConverter): void
|
||||
{
|
||||
$this->beConstructedWith($baseNormalizer);
|
||||
$this->beConstructedWith($baseNormalizer, $nameConverter);
|
||||
}
|
||||
|
||||
function it_throws_exception_if_not_all_required_parameters_are_present_in_the_context(
|
||||
DenormalizerInterface $baseNormalizer,
|
||||
NameConverterInterface $nameConverter,
|
||||
): void {
|
||||
$baseNormalizer->denormalize(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$nameConverter->normalize('firstName', RegisterShopUser::class)->willReturn('firstName');
|
||||
$nameConverter->normalize('lastName', RegisterShopUser::class)->willReturn('lastName');
|
||||
$nameConverter->normalize('email', RegisterShopUser::class)->willReturn('email');
|
||||
$nameConverter->normalize('password', RegisterShopUser::class)->willReturn('password');
|
||||
$nameConverter->normalize('subscribedToNewsletter', RegisterShopUser::class)->willReturn('subscribedToNewsletter');
|
||||
|
||||
$this
|
||||
->shouldThrow(new MissingConstructorArgumentsException(
|
||||
'Request does not have the following required fields specified: firstName, lastName.',
|
||||
|
|
@ -52,7 +60,14 @@ final class CommandDenormalizerSpec extends ObjectBehavior
|
|||
|
||||
function it_denormalizes_data_if_all_required_parameters_are_specified(
|
||||
DenormalizerInterface $baseNormalizer,
|
||||
NameConverterInterface $nameConverter,
|
||||
): void {
|
||||
$nameConverter->normalize('firstName', RegisterShopUser::class)->willReturn('firstName');
|
||||
$nameConverter->normalize('lastName', RegisterShopUser::class)->willReturn('lastName');
|
||||
$nameConverter->normalize('email', RegisterShopUser::class)->willReturn('email');
|
||||
$nameConverter->normalize('password', RegisterShopUser::class)->willReturn('password');
|
||||
$nameConverter->normalize('subscribedToNewsletter', RegisterShopUser::class)->willReturn('subscribedToNewsletter');
|
||||
|
||||
$baseNormalizer
|
||||
->denormalize(
|
||||
['firstName' => 'John', 'lastName' => 'Doe', 'email' => 'test@example.com', 'password' => 'pa$$word'],
|
||||
|
|
@ -71,6 +86,34 @@ final class CommandDenormalizerSpec extends ObjectBehavior
|
|||
)->shouldReturn(['key' => 'value']);
|
||||
}
|
||||
|
||||
function it_denormalizes_data_if_all_required_parameters_are_specified_based_on_their_normalized_names(
|
||||
DenormalizerInterface $baseNormalizer,
|
||||
NameConverterInterface $nameConverter,
|
||||
): void {
|
||||
$baseNormalizer
|
||||
->denormalize(
|
||||
['first_name' => 'John', 'last_name' => 'Doe', 'email_address' => 'test@example.com', 'pass' => 'pa$$word'],
|
||||
Customer::class,
|
||||
null,
|
||||
['input' => ['class' => RegisterShopUser::class]],
|
||||
)
|
||||
->willReturn(['key' => 'value'])
|
||||
;
|
||||
|
||||
$nameConverter->normalize('firstName', RegisterShopUser::class)->willReturn('first_name');
|
||||
$nameConverter->normalize('lastName', RegisterShopUser::class)->willReturn('last_name');
|
||||
$nameConverter->normalize('email', RegisterShopUser::class)->willReturn('email_address');
|
||||
$nameConverter->normalize('password', RegisterShopUser::class)->willReturn('pass');
|
||||
$nameConverter->normalize('subscribedToNewsletter', RegisterShopUser::class)->willReturn('hasNewsletter');
|
||||
|
||||
$this->denormalize(
|
||||
['first_name' => 'John', 'last_name' => 'Doe', 'email_address' => 'test@example.com', 'pass' => 'pa$$word'],
|
||||
Customer::class,
|
||||
null,
|
||||
['input' => ['class' => RegisterShopUser::class]],
|
||||
)->shouldReturn(['key' => 'value']);
|
||||
}
|
||||
|
||||
function it_does_not_check_parameters_if_there_is_an_object_to_populate(
|
||||
DenormalizerInterface $baseNormalizer,
|
||||
): void {
|
||||
|
|
|
|||
|
|
@ -14,10 +14,12 @@ declare(strict_types=1);
|
|||
namespace spec\Sylius\Bundle\ApiBundle\Validator\Constraints;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ApiBundle\Command\Checkout\CompleteOrder;
|
||||
use Sylius\Bundle\ApiBundle\Command\OrderTokenValueAwareInterface;
|
||||
use Sylius\Bundle\ApiBundle\Validator\Constraints\OrderShippingMethodEligibility;
|
||||
use Sylius\Component\Core\Model\ChannelInterface;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\ShipmentInterface;
|
||||
use Sylius\Component\Core\Model\ShippingMethodInterface;
|
||||
|
|
@ -87,12 +89,102 @@ final class OrderShippingMethodEligibilityValidatorSpec extends ObjectBehavior
|
|||
;
|
||||
}
|
||||
|
||||
function it_adds_a_violation_for_every_not_available_shipping_method_attached_to_the_order(
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
ExecutionContextInterface $context,
|
||||
OrderTokenValueAwareInterface $value,
|
||||
ChannelInterface $channel,
|
||||
OrderInterface $order,
|
||||
ShipmentInterface $shipmentOne,
|
||||
ShipmentInterface $shipmentTwo,
|
||||
ShippingMethodInterface $shippingMethodOne,
|
||||
ShippingMethodInterface $shippingMethodTwo,
|
||||
Collection $channelsCollectionOne,
|
||||
Collection $channelsCollectionTwo,
|
||||
): void {
|
||||
$this->initialize($context);
|
||||
|
||||
$value->getOrderTokenValue()->willReturn('ORDERTOKENVALUE');
|
||||
$orderRepository->findOneBy(['tokenValue' => 'ORDERTOKENVALUE'])->willReturn($order);
|
||||
|
||||
$order->getShipments()->willReturn(new ArrayCollection([$shipmentOne->getWrappedObject(), $shipmentTwo->getWrappedObject()]));
|
||||
$order->getChannel()->willReturn($channel);
|
||||
|
||||
$shipmentOne->getMethod()->willReturn($shippingMethodOne);
|
||||
$shipmentTwo->getMethod()->willReturn($shippingMethodTwo);
|
||||
|
||||
$shippingMethodOne->isEnabled()->willReturn(false);
|
||||
$shippingMethodTwo->isEnabled()->willReturn(true);
|
||||
|
||||
$shippingMethodOne->getChannels()->willReturn($channelsCollectionOne);
|
||||
$shippingMethodTwo->getChannels()->willReturn($channelsCollectionTwo);
|
||||
|
||||
$shippingMethodOne->getName()->willReturn('Shipping method one');
|
||||
$shippingMethodTwo->getName()->willReturn('Shipping method two');
|
||||
|
||||
$channelsCollectionOne->contains($channel)->willReturn(true);
|
||||
$channelsCollectionTwo->contains($channel)->willReturn(false);
|
||||
|
||||
$context->addViolation('sylius.order.shipping_method_not_available', ['%shippingMethodName%' => 'Shipping method one'])->shouldBeCalled();
|
||||
$context->addViolation('sylius.order.shipping_method_not_available', ['%shippingMethodName%' => 'Shipping method two'])->shouldBeCalled();
|
||||
|
||||
$this->validate($value, new OrderShippingMethodEligibility());
|
||||
}
|
||||
|
||||
function it_does_not_add_violation_if_all_shipping_methods_are_available(
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
ShippingMethodEligibilityCheckerInterface $eligibilityChecker,
|
||||
ExecutionContextInterface $context,
|
||||
OrderTokenValueAwareInterface $value,
|
||||
ChannelInterface $channel,
|
||||
OrderInterface $order,
|
||||
ShipmentInterface $shipmentOne,
|
||||
ShipmentInterface $shipmentTwo,
|
||||
ShippingMethodInterface $shippingMethodOne,
|
||||
ShippingMethodInterface $shippingMethodTwo,
|
||||
Collection $channelsCollectionOne,
|
||||
Collection $channelsCollectionTwo,
|
||||
): void {
|
||||
$this->initialize($context);
|
||||
|
||||
$value->getOrderTokenValue()->willReturn('ORDERTOKENVALUE');
|
||||
$orderRepository->findOneBy(['tokenValue' => 'ORDERTOKENVALUE'])->willReturn($order);
|
||||
|
||||
$order->getShipments()->willReturn(new ArrayCollection([$shipmentOne->getWrappedObject(), $shipmentTwo->getWrappedObject()]));
|
||||
$order->getChannel()->willReturn($channel);
|
||||
|
||||
$shipmentOne->getMethod()->willReturn($shippingMethodOne);
|
||||
$shipmentTwo->getMethod()->willReturn($shippingMethodTwo);
|
||||
|
||||
$shippingMethodOne->isEnabled()->willReturn(true);
|
||||
$shippingMethodTwo->isEnabled()->willReturn(true);
|
||||
|
||||
$shippingMethodOne->getChannels()->willReturn($channelsCollectionOne);
|
||||
$shippingMethodTwo->getChannels()->willReturn($channelsCollectionTwo);
|
||||
|
||||
$shippingMethodOne->getName()->willReturn('Shipping method one');
|
||||
$shippingMethodTwo->getName()->willReturn('Shipping method two');
|
||||
|
||||
$channelsCollectionOne->contains($channel)->willReturn(true);
|
||||
$channelsCollectionTwo->contains($channel)->willReturn(true);
|
||||
|
||||
$context->addViolation('sylius.order.shipping_method_not_available', ['%shippingMethodName%' => 'Shipping method one'])->shouldNotBeCalled();
|
||||
$context->addViolation('sylius.order.shipping_method_not_available', ['%shippingMethodName%' => 'Shipping method two'])->shouldNotBeCalled();
|
||||
|
||||
$eligibilityChecker->isEligible($shipmentOne, $shippingMethodOne)->willReturn(true);
|
||||
$eligibilityChecker->isEligible($shipmentTwo, $shippingMethodTwo)->willReturn(true);
|
||||
|
||||
$this->validate($value, new OrderShippingMethodEligibility());
|
||||
}
|
||||
|
||||
function it_adds_violation_if_shipment_does_not_match_with_shipping_method(
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
ShippingMethodEligibilityCheckerInterface $eligibilityChecker,
|
||||
OrderInterface $order,
|
||||
ShipmentInterface $shipment,
|
||||
ShippingMethodInterface $shippingMethod,
|
||||
Collection $channelsCollection,
|
||||
ChannelInterface $channel,
|
||||
ExecutionContextInterface $executionContext,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
|
@ -105,12 +197,17 @@ final class OrderShippingMethodEligibilityValidatorSpec extends ObjectBehavior
|
|||
$orderRepository->findOneBy(['tokenValue' => 'token'])->willReturn($order);
|
||||
|
||||
$order->getShipments()->willReturn(new ArrayCollection([$shipment->getWrappedObject()]));
|
||||
$order->getChannel()->willReturn($channel);
|
||||
|
||||
$shipment->getMethod()->willReturn($shippingMethod);
|
||||
|
||||
$eligibilityChecker->isEligible($shipment, $shippingMethod)->willReturn(false);
|
||||
|
||||
$shippingMethod->getName()->willReturn('InPost');
|
||||
$shippingMethod->isEnabled()->willReturn(true);
|
||||
$shippingMethod->getChannels()->willReturn($channelsCollection);
|
||||
|
||||
$channelsCollection->contains($channel)->willReturn(true);
|
||||
|
||||
$executionContext
|
||||
->addViolation(
|
||||
|
|
@ -129,6 +226,8 @@ final class OrderShippingMethodEligibilityValidatorSpec extends ObjectBehavior
|
|||
OrderInterface $order,
|
||||
ShipmentInterface $shipment,
|
||||
ShippingMethodInterface $shippingMethod,
|
||||
Collection $channelsCollection,
|
||||
ChannelInterface $channel,
|
||||
ExecutionContextInterface $executionContext,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
|
@ -141,12 +240,17 @@ final class OrderShippingMethodEligibilityValidatorSpec extends ObjectBehavior
|
|||
$orderRepository->findOneBy(['tokenValue' => 'token'])->willReturn($order);
|
||||
|
||||
$order->getShipments()->willReturn(new ArrayCollection([$shipment->getWrappedObject()]));
|
||||
$order->getChannel()->willReturn($channel);
|
||||
|
||||
$shipment->getMethod()->willReturn($shippingMethod);
|
||||
|
||||
$eligibilityChecker->isEligible($shipment, $shippingMethod)->willReturn(true);
|
||||
|
||||
$shippingMethod->getName()->willReturn('InPost');
|
||||
$shippingMethod->isEnabled()->willReturn(true);
|
||||
$shippingMethod->getChannels()->willReturn($channelsCollection);
|
||||
|
||||
$channelsCollection->contains($channel)->willReturn(true);
|
||||
|
||||
$executionContext
|
||||
->addViolation(
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@
|
|||
<service id="sylius.validator.product_integrity" class="Sylius\Bundle\CoreBundle\Validator\Constraints\OrderProductEligibilityValidator">
|
||||
<tag name="validator.constraint_validator" alias="sylius_order_product_eligibility_validator" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.validator.channel_default_locale_enabled" class="Sylius\Bundle\CoreBundle\Validator\Constraints\ChannelDefaultLocaleEnabledValidator">
|
||||
<tag name="validator.constraint_validator" alias="sylius_channel_default_locale_enabled" />
|
||||
</service>
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ sylius:
|
|||
payment_method_eligibility: 'This payment method %paymentMethodName% has been disabled. Please reselect your payment method.'
|
||||
product_eligibility: 'This product %productName% has been disabled.'
|
||||
shipping_method_eligibility: 'Product does not fit requirements for %shippingMethodName% shipping method. Please reselect your shipping method.'
|
||||
shipping_method_not_available: 'The "%shippingMethodName%" shipping method is not available. Please reselect your shipping method.'
|
||||
locale:
|
||||
enabled:
|
||||
cannot_disable_base: The base locale cannot be disabled.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,28 @@ use Symfony\Component\Validator\Constraint;
|
|||
|
||||
final class OrderShippingMethodEligibility extends Constraint
|
||||
{
|
||||
public string $message = 'sylius.order.shipping_method_eligibility';
|
||||
/**
|
||||
* @param array<array-key, mixed> $options
|
||||
*/
|
||||
public function __construct(
|
||||
array $options = [],
|
||||
public string $message = 'sylius.order.shipping_method_eligibility',
|
||||
public string $methodNotAvailableMessage = 'sylius.order.shipping_method_not_available',
|
||||
mixed $groups = null,
|
||||
mixed $payload = null,
|
||||
) {
|
||||
parent::__construct($options, $groups, $payload);
|
||||
}
|
||||
|
||||
public function getMessage(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function getMethodNotAvailableMessage(): string
|
||||
{
|
||||
return $this->methodNotAvailableMessage;
|
||||
}
|
||||
|
||||
public function validatedBy(): string
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ declare(strict_types=1);
|
|||
namespace Sylius\Bundle\CoreBundle\Validator\Constraints;
|
||||
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\ShippingMethodInterface;
|
||||
use Sylius\Component\Shipping\Checker\Eligibility\ShippingMethodEligibilityCheckerInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
|
@ -28,7 +29,7 @@ final class OrderShippingMethodEligibilityValidator extends ConstraintValidator
|
|||
/**
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function validate($value, Constraint $constraint): void
|
||||
public function validate(mixed $value, Constraint $constraint): void
|
||||
{
|
||||
/** @var OrderInterface $value */
|
||||
Assert::isInstanceOf($value, OrderInterface::class);
|
||||
|
|
@ -42,9 +43,21 @@ final class OrderShippingMethodEligibilityValidator extends ConstraintValidator
|
|||
}
|
||||
|
||||
foreach ($shipments as $shipment) {
|
||||
if (!$this->methodEligibilityChecker->isEligible($shipment, $shipment->getMethod())) {
|
||||
/** @var ShippingMethodInterface $shippingMethod */
|
||||
$shippingMethod = $shipment->getMethod();
|
||||
|
||||
if (!$shippingMethod->isEnabled() || !$shippingMethod->getChannels()->contains($value->getChannel())) {
|
||||
$this->context->addViolation(
|
||||
$constraint->message,
|
||||
$constraint->getMethodNotAvailableMessage(),
|
||||
['%shippingMethodName%' => $shippingMethod->getName()],
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->methodEligibilityChecker->isEligible($shipment, $shippingMethod)) {
|
||||
$this->context->addViolation(
|
||||
$constraint->getMessage(),
|
||||
['%shippingMethodName%' => $shipment->getMethod()->getName()],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,209 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* 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\CoreBundle\Validator\Constraints;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\CoreBundle\Validator\Constraints\OrderShippingMethodEligibility;
|
||||
use Sylius\Component\Core\Model\ChannelInterface;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\ShipmentInterface;
|
||||
use Sylius\Component\Core\Model\ShippingMethodInterface;
|
||||
use Sylius\Component\Shipping\Checker\Eligibility\ShippingMethodEligibilityCheckerInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidatorInterface;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
final class OrderShippingMethodEligibilityValidatorSpec extends ObjectBehavior
|
||||
{
|
||||
function let(ShippingMethodEligibilityCheckerInterface $eligibilityChecker): void
|
||||
{
|
||||
$this->beConstructedWith($eligibilityChecker);
|
||||
}
|
||||
|
||||
function it_is_a_constraint_validator(): void
|
||||
{
|
||||
$this->shouldImplement(ConstraintValidatorInterface::class);
|
||||
}
|
||||
|
||||
function it_throws_an_exception_if_constraint_does_not_extend_order_token_value_aware_interface(): void
|
||||
{
|
||||
$this
|
||||
->shouldThrow(\InvalidArgumentException::class)
|
||||
->during('validate', ['', new class() extends Constraint {
|
||||
}])
|
||||
;
|
||||
}
|
||||
|
||||
function it_throws_an_exception_if_constraint_is_not_type_of_order_shipping_method_eligibility(Constraint $constraint): void
|
||||
{
|
||||
$this
|
||||
->shouldThrow(\InvalidArgumentException::class)
|
||||
->during('validate', ['', $constraint])
|
||||
;
|
||||
}
|
||||
|
||||
function it_adds_a_violation_for_every_not_available_shipping_method_attached_to_the_order(
|
||||
ExecutionContextInterface $context,
|
||||
ChannelInterface $channel,
|
||||
OrderInterface $value,
|
||||
ShipmentInterface $shipmentOne,
|
||||
ShipmentInterface $shipmentTwo,
|
||||
ShippingMethodInterface $shippingMethodOne,
|
||||
ShippingMethodInterface $shippingMethodTwo,
|
||||
Collection $channelsCollectionOne,
|
||||
Collection $channelsCollectionTwo,
|
||||
): void {
|
||||
$this->initialize($context);
|
||||
|
||||
$value->getShipments()->willReturn(new ArrayCollection([$shipmentOne->getWrappedObject(), $shipmentTwo->getWrappedObject()]));
|
||||
$value->getChannel()->willReturn($channel);
|
||||
|
||||
$shipmentOne->getMethod()->willReturn($shippingMethodOne);
|
||||
$shipmentTwo->getMethod()->willReturn($shippingMethodTwo);
|
||||
|
||||
$shippingMethodOne->isEnabled()->willReturn(false);
|
||||
$shippingMethodTwo->isEnabled()->willReturn(true);
|
||||
|
||||
$shippingMethodOne->getChannels()->willReturn($channelsCollectionOne);
|
||||
$shippingMethodTwo->getChannels()->willReturn($channelsCollectionTwo);
|
||||
|
||||
$shippingMethodOne->getName()->willReturn('Shipping method one');
|
||||
$shippingMethodTwo->getName()->willReturn('Shipping method two');
|
||||
|
||||
$channelsCollectionOne->contains($channel)->willReturn(true);
|
||||
$channelsCollectionTwo->contains($channel)->willReturn(false);
|
||||
|
||||
$context->addViolation('sylius.order.shipping_method_not_available', ['%shippingMethodName%' => 'Shipping method one'])->shouldBeCalled();
|
||||
$context->addViolation('sylius.order.shipping_method_not_available', ['%shippingMethodName%' => 'Shipping method two'])->shouldBeCalled();
|
||||
|
||||
$this->validate($value, new OrderShippingMethodEligibility());
|
||||
}
|
||||
|
||||
function it_does_not_add_violation_if_all_shipping_methods_are_available(
|
||||
ShippingMethodEligibilityCheckerInterface $eligibilityChecker,
|
||||
ExecutionContextInterface $context,
|
||||
ChannelInterface $channel,
|
||||
OrderInterface $value,
|
||||
ShipmentInterface $shipmentOne,
|
||||
ShipmentInterface $shipmentTwo,
|
||||
ShippingMethodInterface $shippingMethodOne,
|
||||
ShippingMethodInterface $shippingMethodTwo,
|
||||
Collection $channelsCollectionOne,
|
||||
Collection $channelsCollectionTwo,
|
||||
): void {
|
||||
$this->initialize($context);
|
||||
|
||||
$value->getShipments()->willReturn(new ArrayCollection([$shipmentOne->getWrappedObject(), $shipmentTwo->getWrappedObject()]));
|
||||
$value->getChannel()->willReturn($channel);
|
||||
|
||||
$shipmentOne->getMethod()->willReturn($shippingMethodOne);
|
||||
$shipmentTwo->getMethod()->willReturn($shippingMethodTwo);
|
||||
|
||||
$shippingMethodOne->isEnabled()->willReturn(true);
|
||||
$shippingMethodTwo->isEnabled()->willReturn(true);
|
||||
|
||||
$shippingMethodOne->getChannels()->willReturn($channelsCollectionOne);
|
||||
$shippingMethodTwo->getChannels()->willReturn($channelsCollectionTwo);
|
||||
|
||||
$shippingMethodOne->getName()->willReturn('Shipping method one');
|
||||
$shippingMethodTwo->getName()->willReturn('Shipping method two');
|
||||
|
||||
$channelsCollectionOne->contains($channel)->willReturn(true);
|
||||
$channelsCollectionTwo->contains($channel)->willReturn(true);
|
||||
|
||||
$context->addViolation('sylius.order.shipping_method_not_available', ['%shippingMethodName%' => 'Shipping method one'])->shouldNotBeCalled();
|
||||
$context->addViolation('sylius.order.shipping_method_not_available', ['%shippingMethodName%' => 'Shipping method two'])->shouldNotBeCalled();
|
||||
|
||||
$eligibilityChecker->isEligible($shipmentOne, $shippingMethodOne)->willReturn(true);
|
||||
$eligibilityChecker->isEligible($shipmentTwo, $shippingMethodTwo)->willReturn(true);
|
||||
|
||||
$this->validate($value, new OrderShippingMethodEligibility());
|
||||
}
|
||||
|
||||
function it_adds_violation_if_shipment_does_not_match_with_shipping_method(
|
||||
ShippingMethodEligibilityCheckerInterface $eligibilityChecker,
|
||||
OrderInterface $value,
|
||||
ShipmentInterface $shipment,
|
||||
ShippingMethodInterface $shippingMethod,
|
||||
Collection $channelsCollection,
|
||||
ChannelInterface $channel,
|
||||
ExecutionContextInterface $executionContext,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$constraint = new OrderShippingMethodEligibility();
|
||||
|
||||
$value->getShipments()->willReturn(new ArrayCollection([$shipment->getWrappedObject()]));
|
||||
$value->getChannel()->willReturn($channel);
|
||||
|
||||
$shipment->getMethod()->willReturn($shippingMethod);
|
||||
|
||||
$eligibilityChecker->isEligible($shipment, $shippingMethod)->willReturn(false);
|
||||
|
||||
$shippingMethod->getName()->willReturn('InPost');
|
||||
$shippingMethod->isEnabled()->willReturn(true);
|
||||
$shippingMethod->getChannels()->willReturn($channelsCollection);
|
||||
|
||||
$channelsCollection->contains($channel)->willReturn(true);
|
||||
|
||||
$executionContext
|
||||
->addViolation(
|
||||
'sylius.order.shipping_method_eligibility',
|
||||
['%shippingMethodName%' => 'InPost'],
|
||||
)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
|
||||
function it_does_not_add_a_violation_if_shipment_matches_with_shipping_method(
|
||||
ShippingMethodEligibilityCheckerInterface $eligibilityChecker,
|
||||
OrderInterface $value,
|
||||
ShipmentInterface $shipment,
|
||||
ShippingMethodInterface $shippingMethod,
|
||||
Collection $channelsCollection,
|
||||
ChannelInterface $channel,
|
||||
ExecutionContextInterface $executionContext,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$constraint = new OrderShippingMethodEligibility();
|
||||
|
||||
$value->getShipments()->willReturn(new ArrayCollection([$shipment->getWrappedObject()]));
|
||||
$value->getChannel()->willReturn($channel);
|
||||
|
||||
$shipment->getMethod()->willReturn($shippingMethod);
|
||||
|
||||
$eligibilityChecker->isEligible($shipment, $shippingMethod)->willReturn(true);
|
||||
|
||||
$shippingMethod->getName()->willReturn('InPost');
|
||||
$shippingMethod->isEnabled()->willReturn(true);
|
||||
$shippingMethod->getChannels()->willReturn($channelsCollection);
|
||||
|
||||
$channelsCollection->contains($channel)->willReturn(true);
|
||||
|
||||
$executionContext
|
||||
->addViolation(
|
||||
'sylius.order.shipping_method_eligibility',
|
||||
['%shippingMethodName%' => 'InPost'],
|
||||
)
|
||||
->shouldNotBeCalled()
|
||||
;
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
}
|
||||
|
|
@ -152,8 +152,12 @@ class OrderController extends ResourceController
|
|||
|
||||
private function resetChangesOnCart(OrderInterface $cart): void
|
||||
{
|
||||
if (!$this->manager->contains($cart)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->manager->refresh($cart);
|
||||
foreach ($cart->getItems() as $item) {
|
||||
foreach($cart->getItems() as $item) {
|
||||
$this->manager->refresh($item);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue