From 78e57b71dc8b787e195fefb17f350bfd8807e4ac Mon Sep 17 00:00:00 2001 From: Wojdylak Date: Tue, 6 Aug 2024 14:20:45 +0200 Subject: [PATCH] [Api][Order] Enable Cart operations --- ...are.php => LoggedInCustomerEmailAware.php} | 2 +- .../ApiBundle/Attribute/OrderItemIdAware.php | 24 + .../Command/Account/ChangePaymentMethod.php | 3 +- .../ApiBundle/Command/Cart/AddItemToCart.php | 24 +- .../Command/Cart/ChangeItemQuantityInCart.php | 44 +- .../ApiBundle/Command/Cart/PickupCart.php | 36 +- .../Command/Catalog/AddProductReview.php | 4 +- .../Command/Checkout/ChoosePaymentMethod.php | 3 +- .../Command/Checkout/ChooseShippingMethod.php | 42 +- .../ApiBundle/Command/Checkout/UpdateCart.php | 65 +-- ...> LoggedInCustomerEmailAwareInterface.php} | 2 +- ...face.php => OrderItemIdAwareInterface.php} | 6 +- .../Command/OrderTokenValueAwareInterface.php | 2 - .../ApiBundle/Command/SendContactRequest.php | 2 +- .../Command/ShipmentIdAwareInterface.php | 2 - .../Command/SubresourceIdAwareInterface.php | 23 - .../Cart/ChangeItemQuantityInCartHandler.php | 2 +- .../Cart/RemoveItemFromCartHandler.php | 2 +- .../Controller/DeleteOrderItemAction.php | 2 +- ...stomerEmailAwareCommandDataTransformer.php | 62 -- ...nShopUserIdAwareCommandDataTransformer.php | 48 -- ...bresourceIdAwareCommandDataTransformer.php | 45 -- .../config/api_platform/resources/Order.xml | 191 ++++++ .../Commands/Cart/RemoveItemFromCart.xml | 24 - .../ApiBundle/Resources/config/services.xml | 21 +- .../config/services/command_handlers.xml | 26 +- .../config/services/context_builders.xml | 29 +- .../Resources/config/services/serializers.xml | 12 +- .../Resources/config/services/validator.xml | 57 +- .../AddressDenormalizer.php | 5 +- ...gedInCustomerEmailAwareContextBuilder.php} | 8 +- ...ObjectUriVariablesAwareContextBuilder.php} | 27 +- .../OrderTokenValueAwareContextBuilder.php | 59 -- ...gEligibleProductVariantToCartValidator.php | 6 +- .../ChangedItemQuantityInCartValidator.php | 10 +- .../CorrectOrderAddressValidator.php | 2 +- .../UpdateCartEmailNotAllowedValidator.php | 4 +- ...erEmailAwareCommandDataTransformerSpec.php | 68 --- .../ChooseShippingMethodHandlerSpec.php | 26 +- .../Checkout/UpdateCartHandlerSpec.php | 50 +- ...nCustomerEmailAwareContextBuilderSpec.php} | 6 +- ...ectUriVariablesAwareContextBuilderSpec.php | 124 ++++ ...gibleProductVariantToCartValidatorSpec.php | 12 +- ...ChangedItemQuantityInCartValidatorSpec.php | 14 +- ...ShippingMethodEligibilityValidatorSpec.php | 20 +- .../OrderAddressRequirementValidatorSpec.php | 18 +- ...romotionCouponEligibilityValidatorSpec.php | 9 +- ...UpdateCartEmailNotAllowedValidatorSpec.php | 6 +- .../DataFixtures/ORM/cart/existing_cart.yaml | 18 + tests/Api/DataFixtures/ORM/order/new.yaml | 6 +- .../shop/checkout/cart/add_item.json | 3 + .../shop/checkout/cart/create_cart.json | 3 + .../cart/create_cart_with_locale.json | 3 + .../shop/checkout/cart/get_cart.json | 3 + .../shop/checkout/cart/get_empty_cart.json | 3 + ...et_existing_cart_if_customer_has_cart.json | 44 ++ .../shop/checkout/cart/update_cart.json | 5 + .../checkout/cart/update_item_quantity.json | 3 + tests/Api/Shop/Checkout/CartTest.php | 548 ++++++++++++++++++ tests/Api/Utils/OrderPlacerTrait.php | 13 +- 60 files changed, 1210 insertions(+), 721 deletions(-) rename src/Sylius/Bundle/ApiBundle/Attribute/{LoggedInCustomerEmailIfNotSetAware.php => LoggedInCustomerEmailAware.php} (91%) create mode 100644 src/Sylius/Bundle/ApiBundle/Attribute/OrderItemIdAware.php rename src/Sylius/Bundle/ApiBundle/Command/{LoggedInCustomerEmailIfNotSetAwareInterface.php => LoggedInCustomerEmailAwareInterface.php} (86%) rename src/Sylius/Bundle/ApiBundle/Command/{CustomerEmailAwareInterface.php => OrderItemIdAwareInterface.php} (62%) delete mode 100644 src/Sylius/Bundle/ApiBundle/Command/SubresourceIdAwareInterface.php delete mode 100644 src/Sylius/Bundle/ApiBundle/DataTransformer/LoggedInCustomerEmailAwareCommandDataTransformer.php delete mode 100644 src/Sylius/Bundle/ApiBundle/DataTransformer/LoggedInShopUserIdAwareCommandDataTransformer.php delete mode 100644 src/Sylius/Bundle/ApiBundle/DataTransformer/SubresourceIdAwareCommandDataTransformer.php delete mode 100644 src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Commands/Cart/RemoveItemFromCart.xml rename src/Sylius/Bundle/ApiBundle/Serializer/{ => Denormalizer}/AddressDenormalizer.php (81%) rename src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/{LoggedInCustomerEmailIfNotSetAwareContextBuilder.php => LoggedInCustomerEmailAwareContextBuilder.php} (84%) rename src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/{ShipmentAwareContextBuilder.php => ObjectUriVariablesAwareContextBuilder.php} (54%) delete mode 100644 src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/OrderTokenValueAwareContextBuilder.php delete mode 100644 src/Sylius/Bundle/ApiBundle/disabledSpec/DataTransformer/LoggedInCustomerEmailAwareCommandDataTransformerSpec.php rename src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/{LoggedInCustomerEmailIfNotSetAwareContextBuilderSpec.php => LoggedInCustomerEmailAwareContextBuilderSpec.php} (95%) create mode 100644 src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/ObjectUriVariablesAwareContextBuilderSpec.php create mode 100644 tests/Api/DataFixtures/ORM/cart/existing_cart.yaml create mode 100644 tests/Api/Responses/shop/checkout/cart/get_existing_cart_if_customer_has_cart.json create mode 100644 tests/Api/Shop/Checkout/CartTest.php diff --git a/src/Sylius/Bundle/ApiBundle/Attribute/LoggedInCustomerEmailIfNotSetAware.php b/src/Sylius/Bundle/ApiBundle/Attribute/LoggedInCustomerEmailAware.php similarity index 91% rename from src/Sylius/Bundle/ApiBundle/Attribute/LoggedInCustomerEmailIfNotSetAware.php rename to src/Sylius/Bundle/ApiBundle/Attribute/LoggedInCustomerEmailAware.php index 53c81714ac..081e1b338b 100644 --- a/src/Sylius/Bundle/ApiBundle/Attribute/LoggedInCustomerEmailIfNotSetAware.php +++ b/src/Sylius/Bundle/ApiBundle/Attribute/LoggedInCustomerEmailAware.php @@ -14,7 +14,7 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\Attribute; #[\Attribute(\Attribute::TARGET_CLASS)] -final class LoggedInCustomerEmailIfNotSetAware +final class LoggedInCustomerEmailAware { public const DEFAULT_ARGUMENT_NAME = 'email'; diff --git a/src/Sylius/Bundle/ApiBundle/Attribute/OrderItemIdAware.php b/src/Sylius/Bundle/ApiBundle/Attribute/OrderItemIdAware.php new file mode 100644 index 0000000000..457a085ce5 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/Attribute/OrderItemIdAware.php @@ -0,0 +1,24 @@ +orderTokenValue = $tokenValue; - - return $command; + public function __construct( + public string $productVariantCode, + public int $quantity, + public ?string $orderTokenValue = null + ) { } public function getOrderTokenValue(): ?string { return $this->orderTokenValue; } - - public function setOrderTokenValue(?string $orderTokenValue): void - { - $this->orderTokenValue = $orderTokenValue; - } } diff --git a/src/Sylius/Bundle/ApiBundle/Command/Cart/ChangeItemQuantityInCart.php b/src/Sylius/Bundle/ApiBundle/Command/Cart/ChangeItemQuantityInCart.php index b6d9931a90..09f31041ce 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/Cart/ChangeItemQuantityInCart.php +++ b/src/Sylius/Bundle/ApiBundle/Command/Cart/ChangeItemQuantityInCart.php @@ -13,29 +13,16 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\Command\Cart; +use Sylius\Bundle\ApiBundle\Command\OrderItemIdAwareInterface; use Sylius\Bundle\ApiBundle\Command\OrderTokenValueAwareInterface; -use Sylius\Bundle\ApiBundle\Command\SubresourceIdAwareInterface; -class ChangeItemQuantityInCart implements OrderTokenValueAwareInterface, SubresourceIdAwareInterface +class ChangeItemQuantityInCart implements OrderTokenValueAwareInterface, OrderItemIdAwareInterface { - /** @var string|null */ - public $orderTokenValue; - - /** @var string|null */ - public $orderItemId; - - public function __construct(public int $quantity) - { - } - - public static function createFromData(string $tokenValue, string $orderItemId, int $quantity): self - { - $command = new self($quantity); - - $command->orderTokenValue = $tokenValue; - $command->orderItemId = $orderItemId; - - return $command; + public function __construct( + public int $quantity, + public ?int $orderItemId = null, + public ?string $orderTokenValue = null, + ) { } public function getOrderTokenValue(): ?string @@ -43,23 +30,8 @@ class ChangeItemQuantityInCart implements OrderTokenValueAwareInterface, Subreso return $this->orderTokenValue; } - public function setOrderTokenValue(?string $orderTokenValue): void - { - $this->orderTokenValue = $orderTokenValue; - } - - public function getSubresourceId(): ?string + public function getOrderItemId(): ?int { return $this->orderItemId; } - - public function setSubresourceId(?string $subresourceId): void - { - $this->orderItemId = $subresourceId; - } - - public function getSubresourceIdAttributeKey(): string - { - return 'orderItemId'; - } } diff --git a/src/Sylius/Bundle/ApiBundle/Command/Cart/PickupCart.php b/src/Sylius/Bundle/ApiBundle/Command/Cart/PickupCart.php index 333f8da721..0e8ea3b6a1 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/Cart/PickupCart.php +++ b/src/Sylius/Bundle/ApiBundle/Command/Cart/PickupCart.php @@ -14,22 +14,17 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\Command\Cart; use Sylius\Bundle\ApiBundle\Command\ChannelCodeAwareInterface; -use Sylius\Bundle\ApiBundle\Command\CustomerEmailAwareInterface; use Sylius\Bundle\ApiBundle\Command\LocaleCodeAwareInterface; +use Sylius\Bundle\ApiBundle\Command\LoggedInCustomerEmailAwareInterface; -class PickupCart implements ChannelCodeAwareInterface, CustomerEmailAwareInterface, LocaleCodeAwareInterface +class PickupCart implements ChannelCodeAwareInterface, LoggedInCustomerEmailAwareInterface, LocaleCodeAwareInterface { - /** @var string|null */ - public $localeCode; - - /** @var string|null */ - private $channelCode; - - /** @var string|null */ - public $email; - - public function __construct(public ?string $tokenValue = null) - { + public function __construct( + public ?string $tokenValue = null, + public ?string $channelCode = null, + public ?string $email = null, + public ?string $localeCode = null, + ) { } public function getChannelCode(): ?string @@ -37,28 +32,13 @@ class PickupCart implements ChannelCodeAwareInterface, CustomerEmailAwareInterfa return $this->channelCode; } - public function setChannelCode(?string $channelCode): void - { - $this->channelCode = $channelCode; - } - public function getEmail(): ?string { return $this->email; } - public function setEmail(?string $email): void - { - $this->email = $email; - } - public function getLocaleCode(): ?string { return $this->localeCode; } - - public function setLocaleCode(?string $localeCode): void - { - $this->localeCode = $localeCode; - } } diff --git a/src/Sylius/Bundle/ApiBundle/Command/Catalog/AddProductReview.php b/src/Sylius/Bundle/ApiBundle/Command/Catalog/AddProductReview.php index 21f53fbaf4..4a262b1a29 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/Catalog/AddProductReview.php +++ b/src/Sylius/Bundle/ApiBundle/Command/Catalog/AddProductReview.php @@ -14,9 +14,9 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\Command\Catalog; use Sylius\Bundle\ApiBundle\Command\IriToIdentifierConversionAwareInterface; -use Sylius\Bundle\ApiBundle\Command\LoggedInCustomerEmailIfNotSetAwareInterface; +use Sylius\Bundle\ApiBundle\Command\LoggedInCustomerEmailAwareInterface; -readonly class AddProductReview implements IriToIdentifierConversionAwareInterface, LoggedInCustomerEmailIfNotSetAwareInterface +readonly class AddProductReview implements IriToIdentifierConversionAwareInterface, LoggedInCustomerEmailAwareInterface { public function __construct( public string $title, diff --git a/src/Sylius/Bundle/ApiBundle/Command/Checkout/ChoosePaymentMethod.php b/src/Sylius/Bundle/ApiBundle/Command/Checkout/ChoosePaymentMethod.php index fbb45e951f..54b1a586d5 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/Checkout/ChoosePaymentMethod.php +++ b/src/Sylius/Bundle/ApiBundle/Command/Checkout/ChoosePaymentMethod.php @@ -16,9 +16,8 @@ namespace Sylius\Bundle\ApiBundle\Command\Checkout; use Sylius\Bundle\ApiBundle\Command\IriToIdentifierConversionAwareInterface; use Sylius\Bundle\ApiBundle\Command\OrderTokenValueAwareInterface; use Sylius\Bundle\ApiBundle\Command\PaymentMethodCodeAwareInterface; -use Sylius\Bundle\ApiBundle\Command\SubresourceIdAwareInterface; -class ChoosePaymentMethod implements OrderTokenValueAwareInterface, SubresourceIdAwareInterface, PaymentMethodCodeAwareInterface, IriToIdentifierConversionAwareInterface +class ChoosePaymentMethod implements OrderTokenValueAwareInterface, PaymentMethodCodeAwareInterface, IriToIdentifierConversionAwareInterface { /** @var string|null */ public $orderTokenValue; diff --git a/src/Sylius/Bundle/ApiBundle/Command/Checkout/ChooseShippingMethod.php b/src/Sylius/Bundle/ApiBundle/Command/Checkout/ChooseShippingMethod.php index 9b4f256b25..4ad89fe3dc 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/Checkout/ChooseShippingMethod.php +++ b/src/Sylius/Bundle/ApiBundle/Command/Checkout/ChooseShippingMethod.php @@ -15,26 +15,15 @@ namespace Sylius\Bundle\ApiBundle\Command\Checkout; use Sylius\Bundle\ApiBundle\Command\IriToIdentifierConversionAwareInterface; use Sylius\Bundle\ApiBundle\Command\OrderTokenValueAwareInterface; -use Sylius\Bundle\ApiBundle\Command\SubresourceIdAwareInterface; +use Sylius\Bundle\ApiBundle\Command\ShipmentIdAwareInterface; -class ChooseShippingMethod implements OrderTokenValueAwareInterface, SubresourceIdAwareInterface, IriToIdentifierConversionAwareInterface +class ChooseShippingMethod implements OrderTokenValueAwareInterface, ShipmentIdAwareInterface, IriToIdentifierConversionAwareInterface { - /** @var string|null */ - public $orderTokenValue; - - /** @var string|null */ - public $shipmentId; - - /** - * @immutable - * - * @var string - */ - public $shippingMethodCode; - - public function __construct(string $shippingMethodCode) - { - $this->shippingMethodCode = $shippingMethodCode; + public function __construct( + public string $shippingMethodCode, + public ?int $shipmentId = null, + public ?string $orderTokenValue = null, + ) { } public function getOrderTokenValue(): ?string @@ -42,23 +31,8 @@ class ChooseShippingMethod implements OrderTokenValueAwareInterface, Subresource return $this->orderTokenValue; } - public function setOrderTokenValue(?string $orderTokenValue): void - { - $this->orderTokenValue = $orderTokenValue; - } - - public function getSubresourceId(): ?string + public function getShipmentId(): ?int { return $this->shipmentId; } - - public function setSubresourceId(?string $subresourceId): void - { - $this->shipmentId = $subresourceId; - } - - public function getSubresourceIdAttributeKey(): string - { - return 'shipmentId'; - } } diff --git a/src/Sylius/Bundle/ApiBundle/Command/Checkout/UpdateCart.php b/src/Sylius/Bundle/ApiBundle/Command/Checkout/UpdateCart.php index 68a8ba0483..b2b63928c2 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/Checkout/UpdateCart.php +++ b/src/Sylius/Bundle/ApiBundle/Command/Checkout/UpdateCart.php @@ -13,40 +13,21 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\Command\Checkout; -use Sylius\Bundle\ApiBundle\Command\CustomerEmailAwareInterface; use Sylius\Bundle\ApiBundle\Command\LocaleCodeAwareInterface; +use Sylius\Bundle\ApiBundle\Command\LoggedInCustomerEmailAwareInterface; use Sylius\Bundle\ApiBundle\Command\OrderTokenValueAwareInterface; use Sylius\Component\Addressing\Model\AddressInterface; -class UpdateCart implements OrderTokenValueAwareInterface, CustomerEmailAwareInterface, LocaleCodeAwareInterface +class UpdateCart implements OrderTokenValueAwareInterface, LoggedInCustomerEmailAwareInterface, LocaleCodeAwareInterface { - public ?string $orderTokenValue = null; - - /** @immutable */ - public ?string $email = null; - - /** @immutable */ - public ?AddressInterface $billingAddress = null; - - /** @immutable */ - public ?AddressInterface $shippingAddress = null; - - public ?string $couponCode = null; - - public ?string $localeCode = null; - public function __construct( - ?string $email = null, - ?AddressInterface $billingAddress = null, - ?AddressInterface $shippingAddress = null, - ?string $couponCode = null, - ?string $localeCode = null, + public ?string $email = null, + public ?AddressInterface $billingAddress = null, + public ?AddressInterface $shippingAddress = null, + public ?string $couponCode = null, + public ?string $localeCode = null, + public ?string $orderTokenValue = null, ) { - $this->email = $email; - $this->billingAddress = $billingAddress; - $this->shippingAddress = $shippingAddress; - $this->couponCode = $couponCode; - $this->localeCode = $localeCode; } public static function createWithCouponData(?string $couponCode): self @@ -59,58 +40,28 @@ class UpdateCart implements OrderTokenValueAwareInterface, CustomerEmailAwareInt return $this->orderTokenValue; } - public function setOrderTokenValue(?string $orderTokenValue): void - { - $this->orderTokenValue = $orderTokenValue; - } - public function getEmail(): ?string { return $this->email; } - public function setEmail(?string $email): void - { - $this->email = $email; - } - public function getBillingAddress(): ?AddressInterface { return $this->billingAddress; } - public function setBillingAddress(?AddressInterface $billingAddress): void - { - $this->billingAddress = $billingAddress; - } - public function getShippingAddress(): ?AddressInterface { return $this->shippingAddress; } - public function setShippingAddress(?AddressInterface $shippingAddress): void - { - $this->shippingAddress = $shippingAddress; - } - public function getCouponCode(): ?string { return $this->couponCode; } - public function setCouponCode(?string $couponCode): void - { - $this->couponCode = $couponCode; - } - public function getLocaleCode(): ?string { return $this->localeCode; } - - public function setLocaleCode(?string $localeCode): void - { - $this->localeCode = $localeCode; - } } diff --git a/src/Sylius/Bundle/ApiBundle/Command/LoggedInCustomerEmailIfNotSetAwareInterface.php b/src/Sylius/Bundle/ApiBundle/Command/LoggedInCustomerEmailAwareInterface.php similarity index 86% rename from src/Sylius/Bundle/ApiBundle/Command/LoggedInCustomerEmailIfNotSetAwareInterface.php rename to src/Sylius/Bundle/ApiBundle/Command/LoggedInCustomerEmailAwareInterface.php index e8bddb984e..44784a37aa 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/LoggedInCustomerEmailIfNotSetAwareInterface.php +++ b/src/Sylius/Bundle/ApiBundle/Command/LoggedInCustomerEmailAwareInterface.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\Command; -interface LoggedInCustomerEmailIfNotSetAwareInterface +interface LoggedInCustomerEmailAwareInterface { public function getEmail(): ?string; } diff --git a/src/Sylius/Bundle/ApiBundle/Command/CustomerEmailAwareInterface.php b/src/Sylius/Bundle/ApiBundle/Command/OrderItemIdAwareInterface.php similarity index 62% rename from src/Sylius/Bundle/ApiBundle/Command/CustomerEmailAwareInterface.php rename to src/Sylius/Bundle/ApiBundle/Command/OrderItemIdAwareInterface.php index 1fe31dc631..e6324d1505 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/CustomerEmailAwareInterface.php +++ b/src/Sylius/Bundle/ApiBundle/Command/OrderItemIdAwareInterface.php @@ -13,9 +13,7 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\Command; -interface CustomerEmailAwareInterface extends CommandAwareDataTransformerInterface +interface OrderItemIdAwareInterface extends CommandAwareDataTransformerInterface { - public function getEmail(): ?string; - - public function setEmail(?string $email): void; + public function getOrderItemId(): ?int; } diff --git a/src/Sylius/Bundle/ApiBundle/Command/OrderTokenValueAwareInterface.php b/src/Sylius/Bundle/ApiBundle/Command/OrderTokenValueAwareInterface.php index c00800949b..b89857ca89 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/OrderTokenValueAwareInterface.php +++ b/src/Sylius/Bundle/ApiBundle/Command/OrderTokenValueAwareInterface.php @@ -16,6 +16,4 @@ namespace Sylius\Bundle\ApiBundle\Command; interface OrderTokenValueAwareInterface extends CommandAwareDataTransformerInterface { public function getOrderTokenValue(): ?string; - - public function setOrderTokenValue(?string $orderTokenValue): void; } diff --git a/src/Sylius/Bundle/ApiBundle/Command/SendContactRequest.php b/src/Sylius/Bundle/ApiBundle/Command/SendContactRequest.php index 54894f6a5d..437623bdaf 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/SendContactRequest.php +++ b/src/Sylius/Bundle/ApiBundle/Command/SendContactRequest.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\Command; -class SendContactRequest implements ChannelCodeAwareInterface, LocaleCodeAwareInterface, LoggedInCustomerEmailIfNotSetAwareInterface +class SendContactRequest implements ChannelCodeAwareInterface, LocaleCodeAwareInterface, LoggedInCustomerEmailAwareInterface { public function __construct( protected ?string $channelCode, diff --git a/src/Sylius/Bundle/ApiBundle/Command/ShipmentIdAwareInterface.php b/src/Sylius/Bundle/ApiBundle/Command/ShipmentIdAwareInterface.php index 4440bdb6f3..f51b9b788e 100644 --- a/src/Sylius/Bundle/ApiBundle/Command/ShipmentIdAwareInterface.php +++ b/src/Sylius/Bundle/ApiBundle/Command/ShipmentIdAwareInterface.php @@ -16,6 +16,4 @@ namespace Sylius\Bundle\ApiBundle\Command; interface ShipmentIdAwareInterface extends CommandAwareDataTransformerInterface { public function getShipmentId(): ?int; - - public function setShipmentId(?int $shipmentId): void; } diff --git a/src/Sylius/Bundle/ApiBundle/Command/SubresourceIdAwareInterface.php b/src/Sylius/Bundle/ApiBundle/Command/SubresourceIdAwareInterface.php deleted file mode 100644 index 82f61189f7..0000000000 --- a/src/Sylius/Bundle/ApiBundle/Command/SubresourceIdAwareInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -attributes->get('itemId'); + $orderItemId = $request->attributes->get('orderItemId'); $tokenValue = $request->attributes->get('tokenValue'); if (null === $orderItemId || null === $tokenValue) { throw new OrderItemNotFoundException(); diff --git a/src/Sylius/Bundle/ApiBundle/DataTransformer/LoggedInCustomerEmailAwareCommandDataTransformer.php b/src/Sylius/Bundle/ApiBundle/DataTransformer/LoggedInCustomerEmailAwareCommandDataTransformer.php deleted file mode 100644 index 59ef110f25..0000000000 --- a/src/Sylius/Bundle/ApiBundle/DataTransformer/LoggedInCustomerEmailAwareCommandDataTransformer.php +++ /dev/null @@ -1,62 +0,0 @@ -getCustomer(); - - /** @var CustomerEmailAwareInterface|mixed $object */ - Assert::object($object, CustomerEmailAwareInterface::class); - - if ($customer !== null) { - $object->setEmail($customer->getEmail()); - } - - return $object; - } - - public function supportsTransformation($object): bool - { - return $object instanceof CustomerEmailAwareInterface; - } - - private function getCustomer(): ?CustomerInterface - { - /** @var UserInterface|null $user */ - $user = $this->userContext->getUser(); - if ($user instanceof ShopUserInterface) { - $customer = $user->getCustomer(); - Assert::nullOrIsInstanceOf($customer, CustomerInterface::class); - - return $customer; - } - - return null; - } -} diff --git a/src/Sylius/Bundle/ApiBundle/DataTransformer/LoggedInShopUserIdAwareCommandDataTransformer.php b/src/Sylius/Bundle/ApiBundle/DataTransformer/LoggedInShopUserIdAwareCommandDataTransformer.php deleted file mode 100644 index b44944e316..0000000000 --- a/src/Sylius/Bundle/ApiBundle/DataTransformer/LoggedInShopUserIdAwareCommandDataTransformer.php +++ /dev/null @@ -1,48 +0,0 @@ -userContext->getUser(); - - if (!$user instanceof ShopUserInterface) { - return $object; - } - - $object->setShopUserId($user->getId()); - - return $object; - } - - public function supportsTransformation($object): bool - { - return $object instanceof ShopUserIdAwareInterface; - } -} diff --git a/src/Sylius/Bundle/ApiBundle/DataTransformer/SubresourceIdAwareCommandDataTransformer.php b/src/Sylius/Bundle/ApiBundle/DataTransformer/SubresourceIdAwareCommandDataTransformer.php deleted file mode 100644 index 2464bd7380..0000000000 --- a/src/Sylius/Bundle/ApiBundle/DataTransformer/SubresourceIdAwareCommandDataTransformer.php +++ /dev/null @@ -1,45 +0,0 @@ -requestStack->getCurrentRequest()->attributes; - - $attributeKey = $object->getSubresourceIdAttributeKey(); - Assert::true($attributes->has($attributeKey), 'Path does not have subresource id'); - - /** @var string $subresourceId */ - $subresourceId = $attributes->get($object->getSubresourceIdAttributeKey()); - - $object->setSubresourceId($subresourceId); - - return $object; - } - - public function supportsTransformation($object): bool - { - return $object instanceof SubresourceIdAwareInterface; - } -} diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Order.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Order.xml index 1d36af2b4e..596a9e6965 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Order.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Order.xml @@ -123,6 +123,197 @@ + + + + + + + sylius + + + + + + + + + sylius:shop:order:create + + + + + + + + + sylius:shop:order:show + sylius:shop:cart:show + + + + + + + Pickups a new cart. + + + + + + + + + + sylius + + + + + + + + + sylius:shop:cart:add_item + + + + + + + + + sylius:shop:cart:show + + + + + + + Adds an item to the cart. + + + + + + + + + + sylius + + + + + + + + + sylius:shop:cart:update + + + + + + + + + sylius:shop:order:show + sylius:shop:cart:show + + + + + + + Addresses cart to given location, logged in Customer does not have to provide an email. Applies coupon to cart. + + + + + + + + + + + + + + sylius + + + + + + + + + sylius:shop:cart:change_quantity + + + + + + + + + sylius:shop:cart:show + + + + + + + Changes quantity of an item in the cart. + + + + + + + + Deletes cart. + + + + + + + + + + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Commands/Cart/RemoveItemFromCart.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Commands/Cart/RemoveItemFromCart.xml deleted file mode 100644 index a0c9f3d498..0000000000 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Commands/Cart/RemoveItemFromCart.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - shop:cart:remove_item - sylius:shop:cart:remove_item - - - diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml index aaa6b9ad9f..d0d54b033a 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml @@ -40,9 +40,9 @@ - - - + + Sylius\Component\Addressing\Model\AddressInterface + @@ -52,21 +52,6 @@ - - - - - - - - - - - - - - - diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/command_handlers.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/command_handlers.xml index 6486c245dc..8ea72fde00 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/command_handlers.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/command_handlers.xml @@ -51,12 +51,12 @@ - - - - - - + + + + + + @@ -118,13 +118,13 @@ - - - - - - - + + + + + + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/context_builders.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/context_builders.xml index aa6fcd0e91..ae1336f1a2 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/context_builders.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/context_builders.xml @@ -30,13 +30,13 @@ - Sylius\Bundle\ApiBundle\Attribute\LoggedInCustomerEmailIfNotSetAware - Sylius\Bundle\ApiBundle\Attribute\LoggedInCustomerEmailIfNotSetAware::DEFAULT_ARGUMENT_NAME + Sylius\Bundle\ApiBundle\Attribute\LoggedInCustomerEmailAware + Sylius\Bundle\ApiBundle\Attribute\LoggedInCustomerEmailAware::DEFAULT_ARGUMENT_NAME @@ -89,23 +89,42 @@ Sylius\Bundle\ApiBundle\Attribute\ShipmentIdAware Sylius\Bundle\ApiBundle\Attribute\ShipmentIdAware::DEFAULT_ARGUMENT_NAME + Sylius\Bundle\ApiBundle\Command\ShipmentIdAwareInterface + Sylius\Component\Core\Model\ShipmentInterface Sylius\Bundle\ApiBundle\Attribute\OrderTokenValueAware Sylius\Bundle\ApiBundle\Attribute\OrderTokenValueAware::DEFAULT_ARGUMENT_NAME + Sylius\Bundle\ApiBundle\Command\OrderTokenValueAwareInterface + Sylius\Component\Core\Model\OrderInterface + + + + + Sylius\Bundle\ApiBundle\Attribute\OrderItemIdAware + Sylius\Bundle\ApiBundle\Attribute\OrderItemIdAware::DEFAULT_ARGUMENT_NAME + Sylius\Bundle\ApiBundle\Command\OrderItemIdAwareInterface + Sylius\Component\Core\Model\OrderItemInterface diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml index 83cf0d2514..9d96016ed8 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml @@ -18,12 +18,12 @@ - - - - - - + + + %sylius.model.address.class% + %sylius.model.address.interface% + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/validator.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/validator.xml index 2d9a549196..21b911b2c1 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/validator.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/validator.xml @@ -22,10 +22,11 @@ - - - - + + + + @@ -63,24 +64,27 @@ - - - - - - + + + + + + - - - - - - + + + + + + - - - - + + + + @@ -107,12 +111,13 @@ - - - - - - + + + + + + diff --git a/src/Sylius/Bundle/ApiBundle/Serializer/AddressDenormalizer.php b/src/Sylius/Bundle/ApiBundle/Serializer/Denormalizer/AddressDenormalizer.php similarity index 81% rename from src/Sylius/Bundle/ApiBundle/Serializer/AddressDenormalizer.php rename to src/Sylius/Bundle/ApiBundle/Serializer/Denormalizer/AddressDenormalizer.php index bbc83c24d4..9047d9fd4c 100644 --- a/src/Sylius/Bundle/ApiBundle/Serializer/AddressDenormalizer.php +++ b/src/Sylius/Bundle/ApiBundle/Serializer/Denormalizer/AddressDenormalizer.php @@ -11,12 +11,11 @@ declare(strict_types=1); -namespace Sylius\Bundle\ApiBundle\Serializer; +namespace Sylius\Bundle\ApiBundle\Serializer\Denormalizer; -use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; -final class AddressDenormalizer implements ContextAwareDenormalizerInterface +final readonly class AddressDenormalizer implements DenormalizerInterface { public function __construct( private DenormalizerInterface $objectNormalizer, diff --git a/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/LoggedInCustomerEmailIfNotSetAwareContextBuilder.php b/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/LoggedInCustomerEmailAwareContextBuilder.php similarity index 84% rename from src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/LoggedInCustomerEmailIfNotSetAwareContextBuilder.php rename to src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/LoggedInCustomerEmailAwareContextBuilder.php index 9f39f7793e..b35d13e998 100644 --- a/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/LoggedInCustomerEmailIfNotSetAwareContextBuilder.php +++ b/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/LoggedInCustomerEmailAwareContextBuilder.php @@ -14,7 +14,7 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\SerializerContextBuilder; use ApiPlatform\Serializer\SerializerContextBuilderInterface; -use Sylius\Bundle\ApiBundle\Command\LoggedInCustomerEmailIfNotSetAwareInterface; +use Sylius\Bundle\ApiBundle\Command\LoggedInCustomerEmailAwareInterface; use Sylius\Bundle\ApiBundle\Context\UserContextInterface; use Sylius\Component\Core\Model\CustomerInterface; use Sylius\Component\Core\Model\ShopUserInterface; @@ -22,7 +22,7 @@ use Sylius\Component\User\Model\UserInterface; use Symfony\Component\HttpFoundation\Request; use Webmozart\Assert\Assert; -final class LoggedInCustomerEmailIfNotSetAwareContextBuilder extends AbstractInputContextBuilder +final class LoggedInCustomerEmailAwareContextBuilder extends AbstractInputContextBuilder { public function __construct( SerializerContextBuilderInterface $decoratedContextBuilder, @@ -35,12 +35,12 @@ final class LoggedInCustomerEmailIfNotSetAwareContextBuilder extends AbstractInp protected function supportsClass(string $class): bool { - return is_a($class, LoggedInCustomerEmailIfNotSetAwareInterface::class, true); + return is_a($class, LoggedInCustomerEmailAwareInterface::class, true); } protected function supports(Request $request, array $context, ?array $extractedAttributes): bool { - return !array_key_exists('email', $request->toArray()) && + return !isset($request->toArray()['email']) && $this->getCustomer() !== null; } diff --git a/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/ShipmentAwareContextBuilder.php b/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/ObjectUriVariablesAwareContextBuilder.php similarity index 54% rename from src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/ShipmentAwareContextBuilder.php rename to src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/ObjectUriVariablesAwareContextBuilder.php index 836fb19721..1e0e91937c 100644 --- a/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/ShipmentAwareContextBuilder.php +++ b/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/ObjectUriVariablesAwareContextBuilder.php @@ -14,28 +14,37 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\SerializerContextBuilder; use ApiPlatform\Metadata\HttpOperation; -use Sylius\Bundle\ApiBundle\Command\ShipmentIdAwareInterface; -use Sylius\Component\Core\Model\ShipmentInterface; +use ApiPlatform\Serializer\SerializerContextBuilderInterface; use Symfony\Component\HttpFoundation\Request; -final class ShipmentAwareContextBuilder extends AbstractInputContextBuilder +final class ObjectUriVariablesAwareContextBuilder extends AbstractInputContextBuilder { + public function __construct( + SerializerContextBuilderInterface $decoratedContextBuilder, + string $attributeClass, + string $defaultConstructorArgumentName, + private readonly string $commandInterface, + private readonly string $objectInterface, + ) { + parent::__construct($decoratedContextBuilder, $attributeClass, $defaultConstructorArgumentName); + } + protected function supportsClass(string $class): bool { - return is_a($class, ShipmentIdAwareInterface::class, true); + return is_a($class, $this->commandInterface, true); } protected function supports(Request $request, array $context, ?array $extractedAttributes): bool { - return null !== $this->resolveShipmentIdFromUriVariables($context, $extractedAttributes); + return null !== $this->resolveValueFromUriVariables($context, $extractedAttributes); } protected function resolveValue(array $context, ?array $extractedAttributes): mixed { - return $this->resolveShipmentIdFromUriVariables($context, $extractedAttributes); + return $this->resolveValueFromUriVariables($context, $extractedAttributes); } - private function resolveShipmentIdFromUriVariables(array $context, ?array $attributes): ?string + private function resolveValueFromUriVariables(array $context, ?array $attributes): ?string { if ( null !== $attributes && @@ -44,11 +53,11 @@ final class ShipmentAwareContextBuilder extends AbstractInputContextBuilder ) { $operation = $attributes['operation']; foreach ($operation->getUriVariables() as $uriVariable) { - if (false === is_a($uriVariable->getFromClass(), ShipmentInterface::class, true)) { + if (false === is_a($uriVariable->getFromClass(), $this->objectInterface, true)) { continue; } - $identifier = $uriVariable->getFromProperty() ?? $uriVariable->getParameterName() ?? 'id'; + $identifier = $uriVariable->getParameterName() ?? $this->defaultConstructorArgumentName; return $context['uri_variables'][$identifier] ?? null; } diff --git a/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/OrderTokenValueAwareContextBuilder.php b/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/OrderTokenValueAwareContextBuilder.php deleted file mode 100644 index 59a6becad5..0000000000 --- a/src/Sylius/Bundle/ApiBundle/SerializerContextBuilder/OrderTokenValueAwareContextBuilder.php +++ /dev/null @@ -1,59 +0,0 @@ -resolveOrderTokenValueFromUriVariables($context, $extractedAttributes); - } - - protected function resolveValue(array $context, ?array $extractedAttributes): mixed - { - return $this->resolveOrderTokenValueFromUriVariables($context, $extractedAttributes); - } - - private function resolveOrderTokenValueFromUriVariables(array $context, ?array $attributes): ?string - { - if ( - null !== $attributes && - isset($attributes['operation']) && - $attributes['operation'] instanceof HttpOperation - ) { - $operation = $attributes['operation']; - foreach ($operation->getUriVariables() as $uriVariable) { - if (false === is_a($uriVariable->getFromClass(), OrderInterface::class, true)) { - continue; - } - - $identifier = $uriVariable->getFromProperty() ?? $uriVariable->getParameterName() ?? 'id'; - - return $context['uri_variables'][$identifier] ?? null; - } - } - - return null; - } -} diff --git a/src/Sylius/Bundle/ApiBundle/Validator/Constraints/AddingEligibleProductVariantToCartValidator.php b/src/Sylius/Bundle/ApiBundle/Validator/Constraints/AddingEligibleProductVariantToCartValidator.php index 526fad1906..4b9ff4606f 100644 --- a/src/Sylius/Bundle/ApiBundle/Validator/Constraints/AddingEligibleProductVariantToCartValidator.php +++ b/src/Sylius/Bundle/ApiBundle/Validator/Constraints/AddingEligibleProductVariantToCartValidator.php @@ -27,9 +27,9 @@ use Webmozart\Assert\Assert; final class AddingEligibleProductVariantToCartValidator extends ConstraintValidator { public function __construct( - private ProductVariantRepositoryInterface $productVariantRepository, - private OrderRepositoryInterface $orderRepository, - private AvailabilityCheckerInterface $availabilityChecker, + private readonly ProductVariantRepositoryInterface $productVariantRepository, + private readonly OrderRepositoryInterface $orderRepository, + private readonly AvailabilityCheckerInterface $availabilityChecker, ) { } diff --git a/src/Sylius/Bundle/ApiBundle/Validator/Constraints/ChangedItemQuantityInCartValidator.php b/src/Sylius/Bundle/ApiBundle/Validator/Constraints/ChangedItemQuantityInCartValidator.php index 911bf81ec7..dfcec44082 100644 --- a/src/Sylius/Bundle/ApiBundle/Validator/Constraints/ChangedItemQuantityInCartValidator.php +++ b/src/Sylius/Bundle/ApiBundle/Validator/Constraints/ChangedItemQuantityInCartValidator.php @@ -27,13 +27,11 @@ use Webmozart\Assert\Assert; final class ChangedItemQuantityInCartValidator extends ConstraintValidator { - /** - * @param OrderItemRepositoryInterface $orderItemRepository - */ + /** @param OrderItemRepositoryInterface $orderItemRepository */ public function __construct( - private OrderItemRepositoryInterface $orderItemRepository, - private OrderRepositoryInterface $orderRepository, - private AvailabilityCheckerInterface $availabilityChecker, + private readonly OrderItemRepositoryInterface $orderItemRepository, + private readonly OrderRepositoryInterface $orderRepository, + private readonly AvailabilityCheckerInterface $availabilityChecker, ) { } diff --git a/src/Sylius/Bundle/ApiBundle/Validator/Constraints/CorrectOrderAddressValidator.php b/src/Sylius/Bundle/ApiBundle/Validator/Constraints/CorrectOrderAddressValidator.php index ba058a5781..61735ed5fa 100644 --- a/src/Sylius/Bundle/ApiBundle/Validator/Constraints/CorrectOrderAddressValidator.php +++ b/src/Sylius/Bundle/ApiBundle/Validator/Constraints/CorrectOrderAddressValidator.php @@ -23,7 +23,7 @@ use Webmozart\Assert\Assert; final class CorrectOrderAddressValidator extends ConstraintValidator { - public function __construct(private RepositoryInterface $countryRepository) + public function __construct(private readonly RepositoryInterface $countryRepository) { } diff --git a/src/Sylius/Bundle/ApiBundle/Validator/Constraints/UpdateCartEmailNotAllowedValidator.php b/src/Sylius/Bundle/ApiBundle/Validator/Constraints/UpdateCartEmailNotAllowedValidator.php index 0efeb2af85..fea2f341c9 100644 --- a/src/Sylius/Bundle/ApiBundle/Validator/Constraints/UpdateCartEmailNotAllowedValidator.php +++ b/src/Sylius/Bundle/ApiBundle/Validator/Constraints/UpdateCartEmailNotAllowedValidator.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace Sylius\Bundle\ApiBundle\Validator\Constraints; -use Sylius\Bundle\ApiBundle\Command\CustomerEmailAwareInterface; +use Sylius\Bundle\ApiBundle\Command\LoggedInCustomerEmailAwareInterface; use Sylius\Bundle\ApiBundle\Command\OrderTokenValueAwareInterface; use Sylius\Bundle\ApiBundle\Context\UserContextInterface; use Sylius\Component\Core\Model\OrderInterface; @@ -33,7 +33,7 @@ final class UpdateCartEmailNotAllowedValidator extends ConstraintValidator public function validate(mixed $value, Constraint $constraint): void { Assert::isInstanceOf($value, OrderTokenValueAwareInterface::class); - Assert::isInstanceOf($value, CustomerEmailAwareInterface::class); + Assert::isInstanceOf($value, LoggedInCustomerEmailAwareInterface::class); /** @var UpdateCartEmailNotAllowed $constraint */ Assert::isInstanceOf($constraint, UpdateCartEmailNotAllowed::class); diff --git a/src/Sylius/Bundle/ApiBundle/disabledSpec/DataTransformer/LoggedInCustomerEmailAwareCommandDataTransformerSpec.php b/src/Sylius/Bundle/ApiBundle/disabledSpec/DataTransformer/LoggedInCustomerEmailAwareCommandDataTransformerSpec.php deleted file mode 100644 index f224ee2aaf..0000000000 --- a/src/Sylius/Bundle/ApiBundle/disabledSpec/DataTransformer/LoggedInCustomerEmailAwareCommandDataTransformerSpec.php +++ /dev/null @@ -1,68 +0,0 @@ -beConstructedWith($userContext); - } - - function it_adds_email_to_customer_email_aware_commands_from_logged_in_customer( - UserContextInterface $userContext, - CustomerEmailAwareInterface $command, - ShopUserInterface $shopUser, - CustomerInterface $customer, - ): void { - $userContext->getUser()->willReturn($shopUser); - $shopUser->getCustomer()->willReturn($customer); - - $customer->getEmail()->willReturn('sample@email.com'); - - $command->setEmail('sample@email.com')->shouldBeCalled(); - - $this->transform( - $command, - 'Sylius\Component\Core\Model\ProductReview', - [], - ); - } - - function it_does_not_add_email_to_customer_email_aware_for_visitor( - UserContextInterface $userContext, - CustomerEmailAwareInterface $command, - ): void { - $userContext->getUser()->willReturn(null); - - $command->setEmail('sample@email.com')->shouldNotBeCalled(); - - $this->transform( - $command, - 'Sylius\Component\Core\Model\ProductReview', - [], - ); - } - - function it_supports_command_with_customer_email_aware_interface(CustomerEmailAwareInterface $command): void - { - $this->supportsTransformation($command)->shouldReturn(true); - } -} diff --git a/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/Checkout/ChooseShippingMethodHandlerSpec.php b/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/Checkout/ChooseShippingMethodHandlerSpec.php index 0a5a016653..080b62b806 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/Checkout/ChooseShippingMethodHandlerSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/Checkout/ChooseShippingMethodHandlerSpec.php @@ -58,9 +58,7 @@ final class ChooseShippingMethodHandlerSpec extends ObjectBehavior ShipmentInterface $shipment, WinzouStateMachineInterface $stateMachine, ): void { - $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD'); - $chooseShippingMethod->setOrderTokenValue('ORDERTOKEN'); - $chooseShippingMethod->setSubresourceId('123'); + $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD', 123, 'ORDERTOKEN'); $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); @@ -101,9 +99,7 @@ final class ChooseShippingMethodHandlerSpec extends ObjectBehavior $stateMachine, ); - $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD'); - $chooseShippingMethod->setOrderTokenValue('ORDERTOKEN'); - $chooseShippingMethod->setSubresourceId('123'); + $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD', 123, 'ORDERTOKEN'); $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); @@ -136,9 +132,7 @@ final class ChooseShippingMethodHandlerSpec extends ObjectBehavior ShipmentInterface $shipment, WinzouStateMachineInterface $stateMachine, ): void { - $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD'); - $chooseShippingMethod->setOrderTokenValue('ORDERTOKEN'); - $chooseShippingMethod->setSubresourceId('123'); + $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD', 123, 'ORDERTOKEN'); $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); @@ -168,8 +162,7 @@ final class ChooseShippingMethodHandlerSpec extends ObjectBehavior OrderRepositoryInterface $orderRepository, ShipmentInterface $shipment, ): void { - $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD'); - $chooseShippingMethod->setOrderTokenValue('ORDERTOKEN'); + $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD', null, 'ORDERTOKEN'); $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn(null); @@ -189,8 +182,7 @@ final class ChooseShippingMethodHandlerSpec extends ObjectBehavior WinzouStateMachineInterface $stateMachine, ShipmentInterface $shipment, ): void { - $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD'); - $chooseShippingMethod->setOrderTokenValue('ORDERTOKEN'); + $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD', null, 'ORDERTOKEN'); $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); $shippingMethodRepository->findOneBy(['code' => 'DHL_SHIPPING_METHOD'])->willReturn(null); @@ -215,9 +207,7 @@ final class ChooseShippingMethodHandlerSpec extends ObjectBehavior WinzouStateMachineInterface $stateMachine, ShipmentInterface $shipment, ): void { - $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD'); - $chooseShippingMethod->setOrderTokenValue('ORDERTOKEN'); - $chooseShippingMethod->setSubresourceId('123'); + $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD', 123, 'ORDERTOKEN'); $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); @@ -244,9 +234,7 @@ final class ChooseShippingMethodHandlerSpec extends ObjectBehavior ShippingMethodInterface $shippingMethod, WinzouStateMachineInterface $stateMachine, ): void { - $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD'); - $chooseShippingMethod->setOrderTokenValue('ORDERTOKEN'); - $chooseShippingMethod->setSubresourceId('123'); + $chooseShippingMethod = new ChooseShippingMethod('DHL_SHIPPING_METHOD', 123, 'ORDERTOKEN'); $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); diff --git a/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/Checkout/UpdateCartHandlerSpec.php b/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/Checkout/UpdateCartHandlerSpec.php index 591a66b445..0127b3959c 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/Checkout/UpdateCartHandlerSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/Checkout/UpdateCartHandlerSpec.php @@ -62,8 +62,13 @@ final class UpdateCartHandlerSpec extends ObjectBehavior $orderPromotionCodeAssigner->assign($order, 'coupon')->shouldNotBeCalled(); - $updateCart = new UpdateCart('john.doe@email.com', $billingAddress->getWrappedObject(), $shippingAddress->getWrappedObject(), 'coupon'); - $updateCart->setOrderTokenValue('cart'); + $updateCart = new UpdateCart( + email: 'john.doe@email.com', + billingAddress: $billingAddress->getWrappedObject(), + shippingAddress: $shippingAddress->getWrappedObject(), + couponCode: 'coupon', + orderTokenValue: 'cart', + ); $this->shouldThrow(\InvalidArgumentException::class) ->during('__invoke', [$updateCart]) @@ -77,8 +82,10 @@ final class UpdateCartHandlerSpec extends ObjectBehavior OrderInterface $order, AddressInterface $billingAddress, ): void { - $updateCart = new UpdateCart(null, $billingAddress->getWrappedObject()); - $updateCart->setOrderTokenValue('cart'); + $updateCart = new UpdateCart( + billingAddress: $billingAddress->getWrappedObject(), + orderTokenValue: 'cart', + ); $orderRepository->findOneBy(['tokenValue' => 'cart'])->willReturn($order); @@ -105,9 +112,10 @@ final class UpdateCartHandlerSpec extends ObjectBehavior OrderInterface $order, AddressInterface $shippingAddress, ): void { - $updateCart = new UpdateCart(null, null, $shippingAddress->getWrappedObject(), null); - - $updateCart->setOrderTokenValue('cart'); + $updateCart = new UpdateCart( + shippingAddress: $shippingAddress->getWrappedObject(), + orderTokenValue: 'cart', + ); $orderRepository->findOneBy(['tokenValue' => 'cart'])->willReturn($order->getWrappedObject()); @@ -137,8 +145,10 @@ final class UpdateCartHandlerSpec extends ObjectBehavior OrderPromotionCodeAssignerInterface $orderPromotionCodeAssigner, OrderInterface $order, ): void { - $updateCart = new UpdateCart(null, null, null, 'couponCode'); - $updateCart->setOrderTokenValue('cart'); + $updateCart = new UpdateCart( + couponCode: 'couponCode', + orderTokenValue: 'cart', + ); $orderRepository->findOneBy(['tokenValue' => 'cart'])->willReturn($order->getWrappedObject()); @@ -166,14 +176,13 @@ final class UpdateCartHandlerSpec extends ObjectBehavior CustomerResolverInterface $customerResolver, ): void { $updateCart = new UpdateCart( - 'john.doe@email.com', - $billingAddress->getWrappedObject(), - $shippingAddress->getWrappedObject(), - 'couponCode', + email: 'john.doe@email.com', + billingAddress: $billingAddress->getWrappedObject(), + shippingAddress: $shippingAddress->getWrappedObject(), + couponCode: 'couponCode', + orderTokenValue: 'cart', ); - $updateCart->setOrderTokenValue('cart'); - $orderRepository->findOneBy(['tokenValue' => 'cart'])->willReturn($order->getWrappedObject()); $customerResolver->resolve('john.doe@email.com')->shouldBeCalled()->willReturn($customer); @@ -208,14 +217,13 @@ final class UpdateCartHandlerSpec extends ObjectBehavior CustomerInterface $customer, ): void { $updateCart = new UpdateCart( - 'john.doe@email.com', - $billingAddress->getWrappedObject(), - $shippingAddress->getWrappedObject(), - 'couponCode', + email: 'john.doe@email.com', + billingAddress: $billingAddress->getWrappedObject(), + shippingAddress: $shippingAddress->getWrappedObject(), + couponCode: 'couponCode', + orderTokenValue: 'cart', ); - $updateCart->setOrderTokenValue('cart'); - $orderRepository->findOneBy(['tokenValue' => 'cart'])->willReturn($order->getWrappedObject()); $customerResolver->resolve('john.doe@email.com')->shouldBeCalled()->willReturn($customer); diff --git a/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/LoggedInCustomerEmailIfNotSetAwareContextBuilderSpec.php b/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/LoggedInCustomerEmailAwareContextBuilderSpec.php similarity index 95% rename from src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/LoggedInCustomerEmailIfNotSetAwareContextBuilderSpec.php rename to src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/LoggedInCustomerEmailAwareContextBuilderSpec.php index 0e7f18c1ff..02fe533a57 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/LoggedInCustomerEmailIfNotSetAwareContextBuilderSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/LoggedInCustomerEmailAwareContextBuilderSpec.php @@ -15,7 +15,7 @@ namespace spec\Sylius\Bundle\ApiBundle\SerializerContextBuilder; use ApiPlatform\Serializer\SerializerContextBuilderInterface; use PhpSpec\ObjectBehavior; -use Sylius\Bundle\ApiBundle\Attribute\LoggedInCustomerEmailIfNotSetAware; +use Sylius\Bundle\ApiBundle\Attribute\LoggedInCustomerEmailAware; use Sylius\Bundle\ApiBundle\Command\SendContactRequest; use Sylius\Bundle\ApiBundle\Context\UserContextInterface; use Sylius\Component\Core\Model\AdminUserInterface; @@ -24,7 +24,7 @@ use Sylius\Component\Core\Model\ShopUserInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; -final class LoggedInCustomerEmailIfNotSetAwareContextBuilderSpec extends ObjectBehavior +final class LoggedInCustomerEmailAwareContextBuilderSpec extends ObjectBehavior { function let( SerializerContextBuilderInterface $decoratedContextBuilder, @@ -32,7 +32,7 @@ final class LoggedInCustomerEmailIfNotSetAwareContextBuilderSpec extends ObjectB ): void { $this->beConstructedWith( $decoratedContextBuilder, - LoggedInCustomerEmailIfNotSetAware::class, + LoggedInCustomerEmailAware::class, 'email', $userContext, ); diff --git a/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/ObjectUriVariablesAwareContextBuilderSpec.php b/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/ObjectUriVariablesAwareContextBuilderSpec.php new file mode 100644 index 0000000000..7c6129c5e8 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/ObjectUriVariablesAwareContextBuilderSpec.php @@ -0,0 +1,124 @@ +beConstructedWith( + $decoratedContextBuilder, + ShipmentIdAware::class, + 'shipmentId', + ShipmentIdAwareInterface::class, + ShipmentInterface::class, + ); + } + + function it_does_nothing_if_there_is_no_input_class( + SerializerContextBuilderInterface $decoratedContextBuilder, + Request $request, + ): void { + $decoratedContextBuilder + ->createFromRequest($request, true, []) + ->willReturn([]) + ; + + $this->createFromRequest($request, true, [])->shouldReturn([]); + } + + function it_does_nothing_if_input_class_is_no_supported_attribute( + SerializerContextBuilderInterface $decoratedContextBuilder, + Request $request, + ): void { + $decoratedContextBuilder + ->createFromRequest($request, true, []) + ->willReturn(['input' => ['class' => \stdClass::class]]) + ; + + $this + ->createFromRequest($request, true, []) + ->shouldReturn(['input' => ['class' => \stdClass::class]]) + ; + } + + function it_does_nothing_if_there_is_no_uri_variable( + SerializerContextBuilderInterface $decoratedContextBuilder, + Request $request, + HttpOperation $operation, + ): void { + $decoratedContextBuilder + ->createFromRequest($request, true, ['operation' => $operation]) + ->willReturn(['input' => ['class' => ShipmentIdAwareInterface::class]]) + ; + $operation->getUriVariables()->willReturn([]); + + $this + ->createFromRequest($request, true, ['operation' => $operation]) + ->shouldReturn(['input' => ['class' => ShipmentIdAwareInterface::class]]) + ; + } + + function it_does_nothing_if_there_is_different_uri_variable( + SerializerContextBuilderInterface $decoratedContextBuilder, + Request $request, + HttpOperation $operation, + ): void { + $decoratedContextBuilder + ->createFromRequest($request, true, ['operation' => $operation]) + ->willReturn(['input' => ['class' => ShipmentIdAwareInterface::class]]) + ; + $uriVariable = new Link(fromClass: 'stdClass'); + $operation->getUriVariables()->willReturn([$uriVariable]); + + $this + ->createFromRequest($request, true, ['operation' => $operation]) + ->shouldReturn(['input' => ['class' => ShipmentIdAwareInterface::class]]) + ; + } + + function it_set_shipment_id_as_a_constructor_argument( + SerializerContextBuilderInterface $decoratedContextBuilder, + Request $request, + HttpOperation $operation, + ): void { + $decoratedContextBuilder + ->createFromRequest($request, true, ['operation' => $operation]) + ->willReturn(['input' => ['class' => ShipmentIdAwareInterface::class], 'uri_variables' => ['shipmentId' => '123']]) + ; + $uriVariable = new Link(fromClass: ShipmentInterface::class, parameterName: 'shipmentId'); + $operation->getUriVariables()->willReturn([$uriVariable]); + + $this + ->createFromRequest($request, true, ['operation' => $operation]) + ->shouldReturn([ + 'input' => ['class' => ShipmentIdAwareInterface::class], + 'uri_variables' => ['shipmentId' => '123'], + 'default_constructor_arguments' => [ + ShipmentIdAwareInterface::class => ['shipmentId' => '123'], + ], + ]) + ; + } +} diff --git a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/AddingEligibleProductVariantToCartValidatorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/AddingEligibleProductVariantToCartValidatorSpec.php index 41068710b2..5c4832110a 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/AddingEligibleProductVariantToCartValidatorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/AddingEligibleProductVariantToCartValidatorSpec.php @@ -149,8 +149,7 @@ final class AddingEligibleProductVariantToCartValidatorSpec extends ObjectBehavi ): void { $this->initialize($executionContext); - $command = new AddItemToCart('productVariantCode', 1); - $command->setOrderTokenValue('TOKEN'); + $command = new AddItemToCart('productVariantCode', 1, 'TOKEN'); $productVariantRepository->findOneBy(['code' => 'productVariantCode'])->willReturn($productVariant); $productVariant->getCode()->willReturn('productVariantCode'); @@ -198,8 +197,7 @@ final class AddingEligibleProductVariantToCartValidatorSpec extends ObjectBehavi ): void { $this->initialize($executionContext); - $command = new AddItemToCart('productVariantCode', 1); - $command->setOrderTokenValue('TOKEN'); + $command = new AddItemToCart('productVariantCode', 1, 'TOKEN'); $productVariantRepository->findOneBy(['code' => 'productVariantCode'])->willReturn($productVariant); $productVariant->getCode()->willReturn('productVariantCode'); @@ -248,8 +246,7 @@ final class AddingEligibleProductVariantToCartValidatorSpec extends ObjectBehavi ): void { $this->initialize($executionContext); - $command = new AddItemToCart('productVariantCode', 1); - $command->setOrderTokenValue('TOKEN'); + $command = new AddItemToCart('productVariantCode', 1, 'TOKEN'); $productVariantRepository->findOneBy(['code' => 'productVariantCode'])->willReturn($productVariant); $productVariant->getCode()->willReturn('productVariantCode'); @@ -299,8 +296,7 @@ final class AddingEligibleProductVariantToCartValidatorSpec extends ObjectBehavi ): void { $this->initialize($executionContext); - $command = new AddItemToCart('productVariantCode', 1); - $command->setOrderTokenValue('TOKEN'); + $command = new AddItemToCart('productVariantCode', 1, 'TOKEN'); $productVariantRepository->findOneBy(['code' => 'productVariantCode'])->willReturn($productVariant); $productVariant->getCode()->willReturn('productVariantCode'); diff --git a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/ChangedItemQuantityInCartValidatorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/ChangedItemQuantityInCartValidatorSpec.php index f14602dde4..ca9ce0c4a8 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/ChangedItemQuantityInCartValidatorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/ChangedItemQuantityInCartValidatorSpec.php @@ -77,7 +77,7 @@ final class ChangedItemQuantityInCartValidatorSpec extends ObjectBehavior $this ->shouldThrow(OrderItemNotFoundException::class) ->during('validate', [ - ChangeItemQuantityInCart::createFromData('token', '11', 2), + new ChangeItemQuantityInCart(2, 11, 'token'), new ChangedItemQuantityInCart(), ]) ; @@ -100,7 +100,7 @@ final class ChangedItemQuantityInCartValidatorSpec extends ObjectBehavior ; $this->validate( - ChangeItemQuantityInCart::createFromData('token', '11', 2), + new ChangeItemQuantityInCart(2, 11, 'token'), new ChangedItemQuantityInCart(), ); } @@ -130,7 +130,7 @@ final class ChangedItemQuantityInCartValidatorSpec extends ObjectBehavior ; $this->validate( - ChangeItemQuantityInCart::createFromData('token', '11', 2), + new ChangeItemQuantityInCart(2, 11, 'token'), new ChangedItemQuantityInCart(), ); } @@ -162,7 +162,7 @@ final class ChangedItemQuantityInCartValidatorSpec extends ObjectBehavior ; $this->validate( - ChangeItemQuantityInCart::createFromData('token', '11', 2), + new ChangeItemQuantityInCart(2, 11, 'token'), new ChangedItemQuantityInCart(), ); } @@ -197,7 +197,7 @@ final class ChangedItemQuantityInCartValidatorSpec extends ObjectBehavior ; $this->validate( - ChangeItemQuantityInCart::createFromData('token', '11', 2), + new ChangeItemQuantityInCart(2, 11, 'token'), new ChangedItemQuantityInCart(), ); } @@ -242,7 +242,7 @@ final class ChangedItemQuantityInCartValidatorSpec extends ObjectBehavior ; $this->validate( - ChangeItemQuantityInCart::createFromData('token', '11', 2), + new ChangeItemQuantityInCart(2, 11, 'token'), new ChangedItemQuantityInCart(), ); } @@ -295,7 +295,7 @@ final class ChangedItemQuantityInCartValidatorSpec extends ObjectBehavior ; $this->validate( - ChangeItemQuantityInCart::createFromData('token', '11', 2), + new ChangeItemQuantityInCart(2, 11, 'token'), new ChangedItemQuantityInCart(), ); } diff --git a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/ChosenShippingMethodEligibilityValidatorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/ChosenShippingMethodEligibilityValidatorSpec.php index aa0a24e6e8..96c8d4e28d 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/ChosenShippingMethodEligibilityValidatorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/ChosenShippingMethodEligibilityValidatorSpec.php @@ -75,9 +75,7 @@ final class ChosenShippingMethodEligibilityValidatorSpec extends ObjectBehavior OrderInterface $order, AddressInterface $shippingAddress, ): void { - $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE'); - $command->setOrderTokenValue('ORDER_TOKEN'); - $command->setSubresourceId('123'); + $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE', 123, 'ORDER_TOKEN'); $shippingMethodRepository->findOneBy(['code' => 'SHIPPING_METHOD_CODE'])->willReturn($shippingMethod); $shippingMethod->getName()->willReturn('DHL'); @@ -108,9 +106,7 @@ final class ChosenShippingMethodEligibilityValidatorSpec extends ObjectBehavior OrderInterface $order, AddressInterface $shippingAddress, ): void { - $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE'); - $command->setOrderTokenValue('ORDER_TOKEN'); - $command->setSubresourceId('123'); + $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE', 123, 'ORDER_TOKEN'); $shippingMethodRepository->findOneBy(['code' => 'SHIPPING_METHOD_CODE'])->willReturn($shippingMethod); @@ -135,9 +131,7 @@ final class ChosenShippingMethodEligibilityValidatorSpec extends ObjectBehavior ShippingMethodRepositoryInterface $shippingMethodRepository, ExecutionContextInterface $executionContext, ): void { - $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE'); - $command->setOrderTokenValue('ORDER_TOKEN'); - $command->setSubresourceId('123'); + $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE', 123, 'ORDER_TOKEN'); $shippingMethodRepository->findOneBy(['code' => 'SHIPPING_METHOD_CODE'])->willReturn(null); @@ -164,9 +158,7 @@ final class ChosenShippingMethodEligibilityValidatorSpec extends ObjectBehavior OrderInterface $order, AddressInterface $shippingAddress, ): void { - $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE'); - $command->setOrderTokenValue('ORDER_TOKEN'); - $command->setSubresourceId('123'); + $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE', 123, 'ORDER_TOKEN'); $shippingMethodRepository->findOneBy(['code' => 'SHIPPING_METHOD_CODE'])->willReturn($shippingMethod); @@ -192,9 +184,7 @@ final class ChosenShippingMethodEligibilityValidatorSpec extends ObjectBehavior ExecutionContextInterface $executionContext, ShippingMethodInterface $shippingMethod, ): void { - $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE'); - $command->setOrderTokenValue('ORDER_TOKEN'); - $command->setSubresourceId('123'); + $command = new ChooseShippingMethod('SHIPPING_METHOD_CODE', 123, 'ORDER_TOKEN'); $shippingMethodRepository->findOneBy(['code' => 'SHIPPING_METHOD_CODE'])->willReturn($shippingMethod); diff --git a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/OrderAddressRequirementValidatorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/OrderAddressRequirementValidatorSpec.php index e3840ab5e9..6094e1ec2a 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/OrderAddressRequirementValidatorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/OrderAddressRequirementValidatorSpec.php @@ -74,8 +74,7 @@ final class OrderAddressRequirementValidatorSpec extends ObjectBehavior ): void { $orderRepository->findCartByTokenValue('TOKEN')->willReturn(null); - $updateCart = new UpdateCart(billingAddress: $billingAddress->getWrappedObject()); - $updateCart->setOrderTokenValue('TOKEN'); + $updateCart = new UpdateCart(billingAddress: $billingAddress->getWrappedObject(), orderTokenValue: 'TOKEN'); $this ->shouldThrow(ChannelNotFoundException::class) @@ -91,8 +90,7 @@ final class OrderAddressRequirementValidatorSpec extends ObjectBehavior $orderRepository->findCartByTokenValue('TOKEN')->willReturn($order); $order->getChannel()->willReturn(null); - $updateCart = new UpdateCart(billingAddress: $billingAddress->getWrappedObject()); - $updateCart->setOrderTokenValue('TOKEN'); + $updateCart = new UpdateCart(billingAddress: $billingAddress->getWrappedObject(), orderTokenValue: 'TOKEN'); $this ->shouldThrow(ChannelNotFoundException::class) @@ -111,8 +109,7 @@ final class OrderAddressRequirementValidatorSpec extends ObjectBehavior $order->getChannel()->willReturn($channel); $channel->isShippingAddressInCheckoutRequired()->willReturn(true); - $updateCart = new UpdateCart(shippingAddress: $shippingAddress->getWrappedObject()); - $updateCart->setOrderTokenValue('TOKEN'); + $updateCart = new UpdateCart(shippingAddress: $shippingAddress->getWrappedObject(), orderTokenValue: 'TOKEN'); $this->validate($updateCart, new OrderAddressRequirement()); @@ -130,8 +127,7 @@ final class OrderAddressRequirementValidatorSpec extends ObjectBehavior $order->getChannel()->willReturn($channel); $channel->isShippingAddressInCheckoutRequired()->willReturn(false); - $updateCart = new UpdateCart(billingAddress: $billingAddress->getWrappedObject()); - $updateCart->setOrderTokenValue('TOKEN'); + $updateCart = new UpdateCart(billingAddress: $billingAddress->getWrappedObject(), orderTokenValue: 'TOKEN'); $this->validate($updateCart, new OrderAddressRequirement()); @@ -149,8 +145,7 @@ final class OrderAddressRequirementValidatorSpec extends ObjectBehavior $order->getChannel()->willReturn($channel); $channel->isShippingAddressInCheckoutRequired()->willReturn(true); - $updateCart = new UpdateCart(billingAddress: $billingAddress->getWrappedObject()); - $updateCart->setOrderTokenValue('TOKEN'); + $updateCart = new UpdateCart(billingAddress: $billingAddress->getWrappedObject(), orderTokenValue: 'TOKEN'); $this->validate($updateCart, new OrderAddressRequirement()); @@ -168,8 +163,7 @@ final class OrderAddressRequirementValidatorSpec extends ObjectBehavior $order->getChannel()->willReturn($channel); $channel->isShippingAddressInCheckoutRequired()->willReturn(false); - $updateCart = new UpdateCart(shippingAddress: $shippingAddress->getWrappedObject()); - $updateCart->setOrderTokenValue('TOKEN'); + $updateCart = new UpdateCart(shippingAddress: $shippingAddress->getWrappedObject(), orderTokenValue: 'TOKEN'); $this->validate($updateCart, new OrderAddressRequirement()); diff --git a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/PromotionCouponEligibilityValidatorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/PromotionCouponEligibilityValidatorSpec.php index 29aa47345e..3848e685a8 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/PromotionCouponEligibilityValidatorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/PromotionCouponEligibilityValidatorSpec.php @@ -65,8 +65,7 @@ final class PromotionCouponEligibilityValidatorSpec extends ObjectBehavior $this->initialize($executionContext); $constraint = new PromotionCouponEligibility(); - $value = UpdateCart::createWithCouponData('couponCode'); - $value->setOrderTokenValue('token'); + $value = new UpdateCart(couponCode: 'couponCode', orderTokenValue: 'token'); $promotionCouponRepository->findOneBy(['code' => 'couponCode'])->willReturn($promotionCoupon); $orderRepository->findCartByTokenValue('token')->willReturn($cart); @@ -93,8 +92,7 @@ final class PromotionCouponEligibilityValidatorSpec extends ObjectBehavior $constraint = new PromotionCouponEligibility(); $constraint->message = 'message'; - $value = UpdateCart::createWithCouponData('couponCode'); - $value->setOrderTokenValue('token'); + $value = new UpdateCart(couponCode: 'couponCode', orderTokenValue: 'token'); $promotionCouponRepository->findOneBy(['code' => 'couponCode'])->willReturn($promotionCoupon); $orderRepository->findCartByTokenValue('token')->willReturn($cart); @@ -120,8 +118,7 @@ final class PromotionCouponEligibilityValidatorSpec extends ObjectBehavior $constraint = new PromotionCouponEligibility(); $constraint->message = 'message'; - $value = UpdateCart::createWithCouponData('couponCode'); - $value->setOrderTokenValue('token'); + $value = new UpdateCart(couponCode: 'couponCode', orderTokenValue: 'token'); $promotionCouponRepository->findOneBy(['code' => 'couponCode'])->willReturn(null); diff --git a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/UpdateCartEmailNotAllowedValidatorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/UpdateCartEmailNotAllowedValidatorSpec.php index 45e4d71f57..cdfe1a81a6 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/UpdateCartEmailNotAllowedValidatorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/Validator/Constraints/UpdateCartEmailNotAllowedValidatorSpec.php @@ -87,8 +87,7 @@ final class UpdateCartEmailNotAllowedValidatorSpec extends ObjectBehavior ): void { $this->initialize($executionContext); - $value = new UpdateCart('sylius@example.com'); - $value->setOrderTokenValue('token'); + $value = new UpdateCart(email: 'sylius@example.com', orderTokenValue: 'token'); $orderRepository->findOneBy(['tokenValue' => 'token'])->willReturn($order); $userContext->getUser()->shouldBeCalled()->willReturn($user); @@ -106,8 +105,7 @@ final class UpdateCartEmailNotAllowedValidatorSpec extends ObjectBehavior ): void { $this->initialize($executionContext); - $value = new UpdateCart('sylius@example.com'); - $value->setOrderTokenValue('token'); + $value = new UpdateCart(email: 'sylius@example.com', orderTokenValue: 'token'); $orderRepository->findOneBy(['tokenValue' => 'token'])->willReturn($order); $userContext->getUser()->shouldBeCalled()->willReturn(null); diff --git a/tests/Api/DataFixtures/ORM/cart/existing_cart.yaml b/tests/Api/DataFixtures/ORM/cart/existing_cart.yaml new file mode 100644 index 0000000000..59e8962794 --- /dev/null +++ b/tests/Api/DataFixtures/ORM/cart/existing_cart.yaml @@ -0,0 +1,18 @@ +Sylius\Component\Core\Model\Order: + existing_cart: + channel: "@channel_web" + currencyCode: "USD" + localeCode: "en_US" + state: "cart" + paymentState: "cart" + shippingState: "cart" + checkoutState: "cart" + tokenValue: "existingCartToken" + __calls: + - setCustomerWithAuthorization: ["@customer_dave"] + + +Sylius\Component\Core\Model\OrderItem: + existing_cart_order_item: + variant: "@product_variant_mug_blue" + order: "@existing_cart" diff --git a/tests/Api/DataFixtures/ORM/order/new.yaml b/tests/Api/DataFixtures/ORM/order/new.yaml index 9057a53be3..5ed53fdddb 100644 --- a/tests/Api/DataFixtures/ORM/order/new.yaml +++ b/tests/Api/DataFixtures/ORM/order/new.yaml @@ -28,9 +28,9 @@ Sylius\Component\Core\Model\Order: currencyCode: "USD" localeCode: "en_US" state: "cart" - paymentState: "paid" - shippingState: "ready" - checkoutState: "completed" + paymentState: "cart" + shippingState: "cart" + checkoutState: "cart" tokenValue: "cartToken" customer: "@customer_dave" diff --git a/tests/Api/Responses/shop/checkout/cart/add_item.json b/tests/Api/Responses/shop/checkout/cart/add_item.json index 4a37d80663..2a37ddd386 100644 --- a/tests/Api/Responses/shop/checkout/cart/add_item.json +++ b/tests/Api/Responses/shop/checkout/cart/add_item.json @@ -2,6 +2,8 @@ "@context": "\/api\/v2\/contexts\/Order", "@id": "\/api\/v2\/shop\/orders\/nAWw2jewpA", "@type": "Order", + "shippingAddress": null, + "billingAddress": null, "payments": [ { "@id": "\/api\/v2\/shop\/payments\/@integer@", @@ -25,6 +27,7 @@ "shippingState": "cart", "tokenValue": "nAWw2jewpA", "id": "@integer@", + "number": null, "items": [ { "@id": "\/api\/v2\/shop\/order-items\/@integer@", diff --git a/tests/Api/Responses/shop/checkout/cart/create_cart.json b/tests/Api/Responses/shop/checkout/cart/create_cart.json index 6cda8e2d66..67782429a3 100644 --- a/tests/Api/Responses/shop/checkout/cart/create_cart.json +++ b/tests/Api/Responses/shop/checkout/cart/create_cart.json @@ -3,6 +3,8 @@ "@id": "\/api\/v2\/shop\/orders\/@string@", "@type": "Order", "channel": "\/api\/v2\/shop\/channels\/WEB", + "shippingAddress": null, + "billingAddress": null, "payments": [], "shipments": [], "currencyCode": "USD", @@ -12,6 +14,7 @@ "shippingState": "cart", "tokenValue": "@string@", "id": "@integer@", + "number": null, "items": [], "itemsTotal": 0, "total": 0, diff --git a/tests/Api/Responses/shop/checkout/cart/create_cart_with_locale.json b/tests/Api/Responses/shop/checkout/cart/create_cart_with_locale.json index 48a5b4fc6f..03f0941be3 100644 --- a/tests/Api/Responses/shop/checkout/cart/create_cart_with_locale.json +++ b/tests/Api/Responses/shop/checkout/cart/create_cart_with_locale.json @@ -3,6 +3,8 @@ "@id": "\/api\/v2\/shop\/orders\/@string@", "@type": "Order", "channel": "\/api\/v2\/shop\/channels\/WEB", + "shippingAddress": null, + "billingAddress": null, "payments": [], "shipments": [], "currencyCode": "USD", @@ -12,6 +14,7 @@ "shippingState": "cart", "tokenValue": "@string@", "id": "@integer@", + "number": null, "items": [], "itemsTotal": 0, "total": 0, diff --git a/tests/Api/Responses/shop/checkout/cart/get_cart.json b/tests/Api/Responses/shop/checkout/cart/get_cart.json index ef44a0f732..74074b7215 100644 --- a/tests/Api/Responses/shop/checkout/cart/get_cart.json +++ b/tests/Api/Responses/shop/checkout/cart/get_cart.json @@ -2,6 +2,8 @@ "@context": "\/api\/v2\/contexts\/Order", "@id": "\/api\/v2\/shop\/orders\/nAWw2jewpA", "@type": "Order", + "shippingAddress": null, + "billingAddress": null, "payments": [ { "@id": "\/api\/v2\/shop\/payments\/@integer@", @@ -25,6 +27,7 @@ "shippingState": "cart", "tokenValue": "nAWw2jewpA", "id": "@integer@", + "number": null, "items": [ { "@id": "\/api\/v2\/shop\/order-items\/@integer@", diff --git a/tests/Api/Responses/shop/checkout/cart/get_empty_cart.json b/tests/Api/Responses/shop/checkout/cart/get_empty_cart.json index 55df073133..a2d7376ca8 100644 --- a/tests/Api/Responses/shop/checkout/cart/get_empty_cart.json +++ b/tests/Api/Responses/shop/checkout/cart/get_empty_cart.json @@ -2,6 +2,8 @@ "@context": "\/api\/v2\/contexts\/Order", "@id": "\/api\/v2\/shop\/orders\/nAWw2jewpA", "@type": "Order", + "shippingAddress": null, + "billingAddress": null, "payments": [], "shipments": [], "currencyCode": "USD", @@ -11,6 +13,7 @@ "shippingState": "cart", "tokenValue": "nAWw2jewpA", "id": "@integer@", + "number": null, "items": [], "itemsTotal": 0, "total": 0, diff --git a/tests/Api/Responses/shop/checkout/cart/get_existing_cart_if_customer_has_cart.json b/tests/Api/Responses/shop/checkout/cart/get_existing_cart_if_customer_has_cart.json new file mode 100644 index 0000000000..40cabab1c0 --- /dev/null +++ b/tests/Api/Responses/shop/checkout/cart/get_existing_cart_if_customer_has_cart.json @@ -0,0 +1,44 @@ +{ + "@context": "\/api\/v2\/contexts\/Order", + "@id": "\/api\/v2\/shop\/orders\/existingCartToken", + "@type": "Order", + "channel": "\/api\/v2\/shop\/channels\/WEB", + "shippingAddress": null, + "billingAddress": null, + "payments": [], + "shipments": [], + "currencyCode": "USD", + "localeCode": "en_US", + "checkoutState": "cart", + "paymentState": "cart", + "shippingState": "cart", + "tokenValue": "existingCartToken", + "id": "@integer@", + "number": null, + "items": [ + { + "@id": "\/api\/v2\/shop\/order-items\/@integer@", + "@type": "OrderItem", + "variant": "\/api\/v2\/shop\/product-variants\/MUG_BLUE", + "productName": "Mug", + "id": "@integer@", + "quantity": 0, + "unitPrice": 0, + "originalUnitPrice": 0, + "total": 0, + "discountedUnitPrice": 0, + "subtotal": 0 + } + ], + "itemsTotal": 0, + "total": 0, + "state": "cart", + "itemsSubtotal": 0, + "taxTotal": 0, + "shippingTaxTotal": 0, + "taxExcludedTotal": 0, + "taxIncludedTotal": 0, + "shippingTotal": 0, + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 +} diff --git a/tests/Api/Responses/shop/checkout/cart/update_cart.json b/tests/Api/Responses/shop/checkout/cart/update_cart.json index 2c81573230..d78387986f 100644 --- a/tests/Api/Responses/shop/checkout/cart/update_cart.json +++ b/tests/Api/Responses/shop/checkout/cart/update_cart.json @@ -9,8 +9,10 @@ "firstName": "Updated: Jane", "lastName": "Updated: Doe", "phoneNumber": "123456789", + "company": null, "countryCode": "US", "provinceCode": "US-MI", + "provinceName": null, "street": "Updated: Top secret", "city": "Updated: Nebraska", "postcode": "121212" @@ -21,8 +23,10 @@ "firstName": "Updated: Jane", "lastName": "Updated: Doe", "phoneNumber": "123456789", + "company": null, "countryCode": "US", "provinceCode": "US-MI", + "provinceName": null, "street": "Updated: Top secret", "city": "Updated: Nebraska", "postcode": "10001" @@ -50,6 +54,7 @@ "shippingState": "cart", "tokenValue": "nAWw2jewpA", "id": "@integer@", + "number": null, "items": [ { "@id": "\/api\/v2\/shop\/order-items\/@integer@", diff --git a/tests/Api/Responses/shop/checkout/cart/update_item_quantity.json b/tests/Api/Responses/shop/checkout/cart/update_item_quantity.json index 3a832f3568..8b907bad81 100644 --- a/tests/Api/Responses/shop/checkout/cart/update_item_quantity.json +++ b/tests/Api/Responses/shop/checkout/cart/update_item_quantity.json @@ -2,6 +2,8 @@ "@context": "\/api\/v2\/contexts\/Order", "@id": "\/api\/v2\/shop\/orders\/nAWw2jewpA", "@type": "Order", + "shippingAddress": null, + "billingAddress": null, "payments": [ { "@id": "\/api\/v2\/shop\/payments\/@integer@", @@ -25,6 +27,7 @@ "shippingState": "cart", "tokenValue": "nAWw2jewpA", "id": "@integer@", + "number": null, "items": [ { "@id": "\/api\/v2\/shop\/order-items\/@integer@", diff --git a/tests/Api/Shop/Checkout/CartTest.php b/tests/Api/Shop/Checkout/CartTest.php new file mode 100644 index 0000000000..bd8e9046de --- /dev/null +++ b/tests/Api/Shop/Checkout/CartTest.php @@ -0,0 +1,548 @@ +setUpOrderPlacer(); + + parent::setUp(); + } + + /** @test */ + public function it_creates_empty_cart(): void + { + $this->loadFixturesFromFiles(['channel.yaml', 'cart.yaml']); + + $this->client->request( + method: 'POST', + uri: '/api/v2/shop/orders', + server: array_merge([], self::CONTENT_TYPE_HEADER), + content: '{}', + ); + + $this->assertResponse( + $this->client->getResponse(), + 'shop/checkout/cart/create_cart', + Response::HTTP_CREATED, + ); + } + + /** @test */ + public function it_creates_empty_cart_with_provided_locale(): void + { + $this->loadFixturesFromFiles(['channel.yaml', 'cart.yaml']); + + $this->client->request( + method: 'POST', + uri: '/api/v2/shop/orders', + server: array_merge(['HTTP_ACCEPT_LANGUAGE' => 'pl_PL'], self::CONTENT_TYPE_HEADER), + content: '{}', + ); + + $this->assertResponse( + $this->client->getResponse(), + 'shop/checkout/cart/create_cart_with_locale', + Response::HTTP_CREATED, + ); + } + + /** @test */ + public function it_gets_existing_cart_if_customer_has_cart(): void + { + $this->loadFixturesFromFiles([ + 'authentication/shop_user.yaml', + 'channel.yaml', + 'cart.yaml', + 'cart/existing_cart.yaml', + ]); + + $this->client->request( + method: 'POST', + uri: '/api/v2/shop/orders', + server: $this->headerBuilder()->withJsonLdAccept()->withJsonLdContentType()->withShopUserAuthorization('dave@doe.com')->build(), + content: '{}', + ); + + $this->assertResponse( + $this->client->getResponse(), + 'shop/checkout/cart/get_existing_cart_if_customer_has_cart', + Response::HTTP_CREATED, + ); + } + + /** @test */ + public function it_gets_empty_cart(): void + { + $this->setUpDefaultGetHeaders(); + $this->loadFixturesFromFiles(['channel.yaml', 'cart.yaml']); + + $tokenValue = $this->pickUpCart(); + + $this->requestGet(sprintf('/api/v2/shop/orders/%s', $tokenValue)); + + $this->assertResponseSuccessful('shop/checkout/cart/get_empty_cart'); + } + + /** @test */ + public function it_gets_a_cart(): void + { + $this->setUpDefaultGetHeaders(); + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->requestGet(sprintf('/api/v2/shop/orders/%s', $tokenValue)); + + $this->assertResponseSuccessful('shop/checkout/cart/get_cart'); + } + + /** @test */ + public function it_adds_item_to_order(): void + { + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + + $this->client->request( + method: 'POST', + uri: sprintf('/api/v2/shop/orders/%s/items', $tokenValue), + server: self::CONTENT_TYPE_HEADER, + content: json_encode([ + 'productVariant' => '/api/v2/shop/product-variants/MUG_BLUE', + 'quantity' => 4, + ], \JSON_THROW_ON_ERROR), + ); + + $this->assertResponse( + $this->client->getResponse(), + 'shop/checkout/cart/add_item', + Response::HTTP_CREATED, + ); + } + + /** @test */ + public function it_does_not_allow_to_add_item_to_order_with_missing_fields(): void + { + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + + $this->client->request( + method: 'POST', + uri: sprintf('/api/v2/shop/orders/%s/items', $tokenValue), + server: self::CONTENT_TYPE_HEADER, + content: '{}', + ); + + $this->assertResponse( + $this->client->getResponse(), + 'shop/checkout/cart/add_item_with_missing_fields', + Response::HTTP_BAD_REQUEST, + ); + } + + /** @test */ + public function it_removes_item_from_the_cart(): void + { + $this->setUpDefaultGetHeaders(); + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->requestGet(sprintf('/api/v2/shop/orders/%s', $tokenValue)); + $itemId = json_decode($this->client->getResponse()->getContent(), true)['items'][0]['id']; + + $this->requestDelete(sprintf('/api/v2/shop/orders/%s/items/%s', $tokenValue, $itemId)); + + $this->assertResponseCode($this->client->getResponse(), Response::HTTP_NO_CONTENT); + } + + /** @test */ + public function it_does_not_allow_to_remove_item_from_the_cart_if_invalid_id_item(): void + { + $this->setUpDefaultDeleteHeaders(); + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->requestDelete(sprintf('/api/v2/shop/orders/%s/items/STRING-INSTEAD-OF-ID', $tokenValue)); + + $this->assertResponseCode($this->client->getResponse(), Response::HTTP_NOT_FOUND); + } + + /** @test */ + public function it_does_not_allow_to_remove_item_from_the_cart_if_invalid_order_token(): void + { + $this->setUpDefaultDeleteHeaders(); + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->requestDelete('/api/v2/shop/orders/INVALID/items/STRING-INSTEAD-OF-ID'); + + $this->assertResponseCode($this->client->getResponse(), Response::HTTP_NOT_FOUND); + } + + /** @test */ + public function it_updates_item_quantity_in_cart(): void + { + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->requestGet(sprintf('/api/v2/shop/orders/%s', $tokenValue)); + $itemId = json_decode($this->client->getResponse()->getContent(), true)['items'][0]['id']; + + $this->client->request( + method: 'PATCH', + uri: sprintf('/api/v2/shop/orders/%s/items/%s', $tokenValue, $itemId), + server: $this->headerBuilder()->withMergePatchJsonContentType()->withJsonLdAccept()->build(), + content: json_encode([ + 'quantity' => 5, + ], \JSON_THROW_ON_ERROR), + ); + + $this->assertResponse( + $this->client->getResponse(), + 'shop/checkout/cart/update_item_quantity', + ); + } + + /** @test */ + public function it_does_not_allow_to_update_item_quantity_in_cart_with_missing_fields(): void + { + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->requestGet(sprintf('/api/v2/shop/orders/%s', $tokenValue)); + $itemId = json_decode($this->client->getResponse()->getContent(), true)['items'][0]['id']; + + $this->client->request( + method: 'PATCH', + uri: sprintf('/api/v2/shop/orders/%s/items/%s', $tokenValue, $itemId), + server: $this->headerBuilder()->withMergePatchJsonContentType()->withJsonLdAccept()->build(), + content: '{}', + ); + + $this->assertResponse( + $this->client->getResponse(), + 'shop/checkout/cart/update_item_quantity_with_missing_fields', + Response::HTTP_BAD_REQUEST, + ); + } + + /** @test */ + public function it_does_not_allow_to_update_item_quantity_if_invalid_id_item(): void + { + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + + $this->client->request( + method: 'PATCH', + uri: sprintf('/api/v2/shop/orders/%s/items/%s', $tokenValue, 'invalid-item-id'), + server: $this->headerBuilder()->withMergePatchJsonContentType()->withJsonLdAccept()->build(), + content: json_encode(['quantity' => 5]), + ); + + $this->assertResponseCode($this->client->getResponse(), Response::HTTP_NOT_FOUND); + } + + /** @test */ + public function it_updates_cart(): void + { + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->client->request( + method: 'PUT', + uri: sprintf('/api/v2/shop/orders/%s', $tokenValue), + server: self::CONTENT_TYPE_HEADER, + content: json_encode([ + 'email' => 'oliver@doe.com', + 'billingAddress' => [ + 'firstName' => 'Updated: Jane', + 'lastName' => 'Updated: Doe', + 'phoneNumber' => '123456789', + 'countryCode' => 'US', + 'provinceCode' => 'US-MI', + 'city' => 'Updated: Nebraska', + 'street' => 'Updated: Top secret', + 'postcode' => '10001', + ], + 'shippingAddress' => [ + 'firstName' => 'Updated: Jane', + 'lastName' => 'Updated: Doe', + 'phoneNumber' => '123456789', + 'countryCode' => 'US', + 'provinceCode' => 'US-MI', + 'city' => 'Updated: Nebraska', + 'street' => 'Updated: Top secret', + 'postcode' => '121212', + ], + ], \JSON_THROW_ON_ERROR), + ); + + $this->assertResponse( + $this->client->getResponse(), + 'shop/checkout/cart/update_cart', + ); + } + + /** @test */ + public function it_does_not_allow_update_without_items(): void + { + $this->loadFixturesFromFiles(['channel.yaml', 'cart.yaml']); + + $tokenValue = $this->pickUpCart(); + + $this->client->request( + method: 'PUT', + uri: sprintf('/api/v2/shop/orders/%s', $tokenValue), + server: self::CONTENT_TYPE_HEADER, + content: json_encode([ + 'email' => 'oliver@doe.com', + ], \JSON_THROW_ON_ERROR), + ); + + $this->assertResponseViolations( + $this->client->getResponse(), + [ + ['propertyPath' => '', 'message' => 'An empty order cannot be processed.'], + ], + ); + } + + /** @test */ + public function it_does_not_allow_update_without_required_billing_address(): void + { + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->client->request( + method: 'PUT', + uri: sprintf('/api/v2/shop/orders/%s', $tokenValue), + server: self::CONTENT_TYPE_HEADER, + content: json_encode([ + 'email' => 'oliver@doe.com', + 'shippingAddress' => [ + 'firstName' => 'Oliver', + 'lastName' => 'Doe', + 'phoneNumber' => '123456789', + 'countryCode' => 'US', + 'provinceCode' => 'US-MI', + 'city' => 'New York', + 'street' => 'Broadway', + 'postcode' => '10001', + ], + ], \JSON_THROW_ON_ERROR), + ); + + $this->assertResponseViolations( + $this->client->getResponse(), + [ + ['propertyPath' => '', 'message' => 'Please provide a billing address.'], + ], + ); + } + + /** @test */ + public function it_does_not_allow_update_without_required_shipping_address(): void + { + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + ]); + + $tokenValue = $this->pickUpCart(channelCode: 'MOBILE'); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->client->request( + method: 'PUT', + uri: sprintf('/api/v2/shop/orders/%s', $tokenValue), + server: self::CONTENT_TYPE_HEADER, + content: json_encode([ + 'email' => 'oliver@doe.com', + 'billingAddress' => [ + 'firstName' => 'Oliver', + 'lastName' => 'Doe', + 'phoneNumber' => '123456789', + 'countryCode' => 'US', + 'provinceCode' => 'US-MI', + 'city' => 'New York', + 'street' => 'Broadway', + 'postcode' => '10001', + ], + ], \JSON_THROW_ON_ERROR), + ); + + $this->assertResponseViolations( + $this->client->getResponse(), + [ + ['propertyPath' => '', 'message' => 'Please provide a shipping address.'], + ], + ); + } + + /** @test */ + public function it_does_not_allow_update_with_invalid_data(): void + { + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + ]); + + $tokenValue = $this->pickUpCart(channelCode: 'MOBILE'); + $this->addItemToCart('MUG_BLUE', 3, $tokenValue); + + $this->client->request( + method: 'PUT', + uri: sprintf('/api/v2/shop/orders/%s', $tokenValue), + server: self::CONTENT_TYPE_HEADER, + content: json_encode([ + 'billingAddress' => [ + 'countryCode' => 'invalid-code', + ], + 'shippingAddress' => [], + 'couponCode' => 'invalid', + ], \JSON_THROW_ON_ERROR), + ); + + $this->assertResponseViolations( + $this->client->getResponse(), + [ + ['propertyPath' => '', 'message' => 'The country invalid-code does not exist.'], + ['propertyPath' => '', 'message' => 'The address without country cannot exist'], + ['propertyPath' => 'couponCode', 'message' => 'Coupon code is invalid.'], + ['propertyPath' => 'billingAddress.firstName', 'message' => 'Please enter first name.'], + ['propertyPath' => 'billingAddress.lastName', 'message' => 'Please enter last name.'], + ['propertyPath' => 'billingAddress.countryCode', 'message' => 'This value is not a valid country.'], + ['propertyPath' => 'billingAddress.street', 'message' => 'Please enter street.'], + ['propertyPath' => 'billingAddress.city', 'message' => 'Please enter city.'], + ['propertyPath' => 'billingAddress.postcode', 'message' => 'Please enter postcode.'], + ['propertyPath' => 'shippingAddress.firstName', 'message' => 'Please enter first name.'], + ['propertyPath' => 'shippingAddress.lastName', 'message' => 'Please enter last name.'], + ['propertyPath' => 'shippingAddress.countryCode', 'message' => 'Please select country.'], + ['propertyPath' => 'shippingAddress.street', 'message' => 'Please enter street.'], + ['propertyPath' => 'shippingAddress.city', 'message' => 'Please enter city.'], + ['propertyPath' => 'shippingAddress.postcode', 'message' => 'Please enter postcode.'], + ], + ); + } + + /** @test */ + public function it_deletes_cart(): void + { + $this->setUpDefaultGetHeaders(); + $this->loadFixturesFromFiles([ + 'channel.yaml', + 'cart.yaml', + 'country.yaml', + 'shipping_method.yaml', + 'payment_method.yaml', + ]); + + $tokenValue = $this->pickUpCart(); + + $this->requestDelete(sprintf('/api/v2/shop/orders/%s', $tokenValue)); + + $this->assertResponseCode($this->client->getResponse(), Response::HTTP_NO_CONTENT); + } +} diff --git a/tests/Api/Utils/OrderPlacerTrait.php b/tests/Api/Utils/OrderPlacerTrait.php index 929d2d2bc8..886725198c 100644 --- a/tests/Api/Utils/OrderPlacerTrait.php +++ b/tests/Api/Utils/OrderPlacerTrait.php @@ -190,8 +190,10 @@ trait OrderPlacerTrait protected function pickUpCart(string $tokenValue = 'nAWw2jewpA', string $channelCode = 'WEB'): string { - $pickupCartCommand = new PickupCart($tokenValue); - $pickupCartCommand->setChannelCode($channelCode); + $pickupCartCommand = new PickupCart( + tokenValue: $tokenValue, + channelCode: $channelCode, + ); $this->commandBus->dispatch($pickupCartCommand); @@ -200,8 +202,11 @@ trait OrderPlacerTrait protected function addItemToCart(string $productVariantCode, int $quantity, string $tokenValue): string { - $addItemToCartCommand = new AddItemToCart($productVariantCode, $quantity); - $addItemToCartCommand->setOrderTokenValue($tokenValue); + $addItemToCartCommand = new AddItemToCart( + productVariantCode: $productVariantCode, + quantity: $quantity, + orderTokenValue: $tokenValue, + ); $this->commandBus->dispatch($addItemToCartCommand);