diff --git a/spec/CommandHandler/Wishlist/AddProductsToCartHandlerSpec.php b/spec/CommandHandler/Wishlist/AddProductsToCartHandlerSpec.php index 87c2f49e..3ded2a92 100644 --- a/spec/CommandHandler/Wishlist/AddProductsToCartHandlerSpec.php +++ b/spec/CommandHandler/Wishlist/AddProductsToCartHandlerSpec.php @@ -14,6 +14,8 @@ use BitBag\SyliusWishlistPlugin\Command\Wishlist\AddProductsToCartInterface; use BitBag\SyliusWishlistPlugin\Command\Wishlist\WishlistItemInterface; use BitBag\SyliusWishlistPlugin\CommandHandler\Wishlist\AddProductsToCartHandler; +use BitBag\SyliusWishlistPlugin\Exception\InsufficientProductStockException; +use BitBag\SyliusWishlistPlugin\Exception\InvalidProductQuantity; use Doctrine\Common\Collections\ArrayCollection; use PhpSpec\ObjectBehavior; use Sylius\Bundle\OrderBundle\Controller\AddToCartCommandInterface; @@ -23,23 +25,15 @@ use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Inventory\Checker\AvailabilityCheckerInterface; use Sylius\Component\Order\Modifier\OrderModifierInterface; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; -use Symfony\Component\HttpFoundation\Session\Session; -use Symfony\Contracts\Translation\TranslatorInterface; final class AddProductsToCartHandlerSpec extends ObjectBehavior { public function let( - RequestStack $requestStack, - TranslatorInterface $translator, OrderModifierInterface $orderModifier, OrderRepositoryInterface $orderRepository, AvailabilityCheckerInterface $availabilityChecker, ): void { $this->beConstructedWith( - $requestStack, - $translator, $orderModifier, $orderRepository, $availabilityChecker, @@ -61,10 +55,6 @@ public function it_adds_products_from_wishlist_to_cart( AddToCartCommandInterface $addToCartCommand, OrderModifierInterface $orderModifier, OrderRepositoryInterface $orderRepository, - RequestStack $requestStack, - Session $session, - FlashBagInterface $flashBag, - TranslatorInterface $translator, ): void { $collection = new ArrayCollection([$wishlistProduct->getWrappedObject()]); $addProductsToCart->getWishlistProducts()->willReturn($collection); @@ -80,30 +70,16 @@ public function it_adds_products_from_wishlist_to_cart( $availabilityChecker->isStockSufficient($productVariant, 1)->willReturn(true); - $requestStack->getSession()->willReturn($session); - $session->getFlashBag()->willReturn($flashBag); - $flashBag->has('success')->willReturn(false); - - $translator->trans('bitbag_sylius_wishlist_plugin.ui.added_to_cart')->willReturn('Test translation'); - $flashBag->add('success', 'Test translation')->shouldBeCalled(); - $this->__invoke($addProductsToCart); } - public function it_doesnt_add_products_from_wishlist_to_cart_if_stock_is_insufficient( + public function it_throws_exception_when_stock_is_insufficient( AvailabilityCheckerInterface $availabilityChecker, ProductVariantInterface $productVariant, OrderItemInterface $orderItem, WishlistItemInterface $wishlistProduct, - OrderInterface $order, AddProductsToCartInterface $addProductsToCart, AddToCartCommandInterface $addToCartCommand, - OrderModifierInterface $orderModifier, - OrderRepositoryInterface $orderRepository, - RequestStack $requestStack, - Session $session, - FlashBagInterface $flashBag, - TranslatorInterface $translator, ): void { $collection = new ArrayCollection([$wishlistProduct->getWrappedObject()]); $addProductsToCart->getWishlistProducts()->willReturn($collection); @@ -111,20 +87,32 @@ public function it_doesnt_add_products_from_wishlist_to_cart_if_stock_is_insuffi $wishlistProduct->getCartItem()->willReturn($addToCartCommand); $addToCartCommand->getCartItem()->willReturn($orderItem); $orderItem->getVariant()->willReturn($productVariant); - $orderItem->getQuantity()->willReturn(0); - $addToCartCommand->getCart()->willReturn($order); - $availabilityChecker->isStockSufficient($productVariant, 0)->willReturn(false); + $orderItem->getQuantity()->willReturn(1); + $availabilityChecker->isStockSufficient($productVariant, 1)->willReturn(false); $orderItem->getProductName()->willReturn('Tested Product'); - $orderModifier->addToOrder($order, $orderItem)->shouldNotBeCalled(); - $orderRepository->add($order)->shouldNotBeCalled(); + $this->shouldThrow(InsufficientProductStockException::class)->during('__invoke', [$addProductsToCart]); + } - $requestStack->getSession()->willReturn($session); - $session->getFlashBag()->willReturn($flashBag); - $translator->trans('Tested Product does not have sufficient stock.')->willReturn('Translation test'); - $flashBag->add('error', 'Translation test')->shouldBeCalled(); + public function it_throws_exception_when_quantity_is_not_positive( + AvailabilityCheckerInterface $availabilityChecker, + ProductVariantInterface $productVariant, + OrderItemInterface $orderItem, + WishlistItemInterface $wishlistProduct, + AddProductsToCartInterface $addProductsToCart, + AddToCartCommandInterface $addToCartCommand, + ): void { + $collection = new ArrayCollection([$wishlistProduct->getWrappedObject()]); + $addProductsToCart->getWishlistProducts()->willReturn($collection); - $this->__invoke($addProductsToCart); + $wishlistProduct->getCartItem()->willReturn($addToCartCommand); + $addToCartCommand->getCartItem()->willReturn($orderItem); + $orderItem->getVariant()->willReturn($productVariant); + $orderItem->getQuantity()->willReturn(0); + + $availabilityChecker->isStockSufficient($productVariant, 0)->willReturn(true); + + $this->shouldThrow(InvalidProductQuantity::class)->during('__invoke', [$addProductsToCart]); } } diff --git a/src/CommandHandler/Wishlist/AddProductsToCartHandler.php b/src/CommandHandler/Wishlist/AddProductsToCartHandler.php index a8517121..ba95d520 100644 --- a/src/CommandHandler/Wishlist/AddProductsToCartHandler.php +++ b/src/CommandHandler/Wishlist/AddProductsToCartHandler.php @@ -14,6 +14,8 @@ use BitBag\SyliusWishlistPlugin\Command\Wishlist\AddProductsToCartInterface; use BitBag\SyliusWishlistPlugin\Command\Wishlist\WishlistItem; use BitBag\SyliusWishlistPlugin\Command\Wishlist\WishlistItemInterface; +use BitBag\SyliusWishlistPlugin\Exception\InsufficientProductStockException; +use BitBag\SyliusWishlistPlugin\Exception\InvalidProductQuantity; use Doctrine\Common\Collections\Collection; use Sylius\Bundle\OrderBundle\Controller\AddToCartCommandInterface; use Sylius\Component\Core\Model\OrderItemInterface; @@ -21,18 +23,13 @@ use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Inventory\Checker\AvailabilityCheckerInterface; use Sylius\Component\Order\Modifier\OrderModifierInterface; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Routing\Exception\ResourceNotFoundException; -use Symfony\Contracts\Translation\TranslatorInterface; #[AsMessageHandler] final class AddProductsToCartHandler { public function __construct( - private RequestStack $requestStack, - private TranslatorInterface $translator, private OrderModifierInterface $orderModifier, private OrderRepositoryInterface $orderRepository, private ?AvailabilityCheckerInterface $availabilityChecker = null, @@ -69,6 +66,9 @@ private function productCanBeProcessed(WishlistItemInterface $wishlistProduct): return $this->productIsStockSufficient($cartItem) && $this->productHasPositiveQuantity($cartItem); } + /** + * @throws InsufficientProductStockException + */ private function productIsStockSufficient(OrderItemInterface $product): bool { /** @var ?ProductVariantInterface $variant */ @@ -86,25 +86,19 @@ private function productIsStockSufficient(OrderItemInterface $product): bool return true; } - $message = sprintf('%s does not have sufficient stock.', $product->getProductName()); - - /** @var Session $session */ - $session = $this->requestStack->getSession(); - $session->getFlashBag()->add('error', $this->translator->trans($message)); - - return false; + throw new InsufficientProductStockException((string) $product->getProductName()); } + /** + * @throws InvalidProductQuantity + */ private function productHasPositiveQuantity(OrderItemInterface $product): bool { if (0 < $product->getQuantity()) { return true; } - /** @var Session $session */ - $session = $this->requestStack->getSession(); - $session->getFlashBag()->add('error', $this->translator->trans('bitbag_sylius_wishlist_plugin.ui.increase_quantity')); - return false; + throw new InvalidProductQuantity(); } private function addProductToWishlist(WishlistItemInterface $wishlistProduct): void @@ -121,13 +115,5 @@ private function addProductToWishlist(WishlistItemInterface $wishlistProduct): v $this->orderModifier->addToOrder($cart, $cartItem); $this->orderRepository->add($cart); - - /** @var Session $session */ - $session = $this->requestStack->getSession(); - $flashBag = $session->getFlashBag(); - - if (false === $flashBag->has('success')) { - $flashBag->add('success', $this->translator->trans('bitbag_sylius_wishlist_plugin.ui.added_to_cart')); - } } } diff --git a/src/Controller/Action/AddProductsToCartAction.php b/src/Controller/Action/AddProductsToCartAction.php index b515cb9a..312d0eab 100644 --- a/src/Controller/Action/AddProductsToCartAction.php +++ b/src/Controller/Action/AddProductsToCartAction.php @@ -12,13 +12,42 @@ namespace BitBag\SyliusWishlistPlugin\Controller\Action; use BitBag\SyliusWishlistPlugin\Command\Wishlist\AddProductsToCart; +use BitBag\SyliusWishlistPlugin\Exception\InsufficientProductStockException; +use BitBag\SyliusWishlistPlugin\Exception\InvalidProductQuantity; use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\Messenger\Exception\HandlerFailedException; final class AddProductsToCartAction extends BaseWishlistProductsAction { protected function handleCommand(FormInterface $form): void { + /** @var Session $session */ + $session = $this->requestStack->getSession(); + $flashBag = $session->getFlashBag(); + $command = new AddProductsToCart($form->get('items')->getData()); - $this->messageBus->dispatch($command); + + try { + $this->messageBus->dispatch($command); + if (false === $flashBag->has('success')) { + $flashBag->add('success', $this->translator->trans('bitbag_sylius_wishlist_plugin.ui.added_to_cart')); + } + } catch (HandlerFailedException $exception) { + $flashBag->add('error', $this->getExceptionMessage($exception)); + } + } + + private function getExceptionMessage(HandlerFailedException $exception): string + { + $previous = $exception->getPrevious(); + if ($previous instanceof InsufficientProductStockException) { + return $this->translator->trans('bitbag_sylius_wishlist_plugin.ui.insufficient_stock', ['%productName%' => $previous->getProductName()]); + } + if ($previous instanceof InvalidProductQuantity) { + return $this->translator->trans('bitbag_sylius_wishlist_plugin.ui.increase_quantity'); + } + + return $exception->getMessage(); } } diff --git a/src/Exception/InsufficientProductStockException.php b/src/Exception/InsufficientProductStockException.php new file mode 100644 index 00000000..609870dd --- /dev/null +++ b/src/Exception/InsufficientProductStockException.php @@ -0,0 +1,25 @@ +productName; + } +} diff --git a/src/Exception/InvalidProductQuantity.php b/src/Exception/InvalidProductQuantity.php new file mode 100644 index 00000000..fa18dab2 --- /dev/null +++ b/src/Exception/InvalidProductQuantity.php @@ -0,0 +1,16 @@ + - - diff --git a/src/Resources/translations/messages.en.yml b/src/Resources/translations/messages.en.yml index bcdb5563..e1cf837a 100644 --- a/src/Resources/translations/messages.en.yml +++ b/src/Resources/translations/messages.en.yml @@ -14,6 +14,7 @@ bitbag_sylius_wishlist_plugin: added_to_cart: Wishlist items have been added to your cart. save_wishlist: Save wishlist variant_not_unique: You already have this variant on your wishlist + insufficient_stock: '%productName% does not have sufficient stock.' increase_quantity: Increase the quantity of at least one item. select_products: Select at least one item. added_selected_wishlist_items_to_cart: Selected wishlist items have been added to your cart. diff --git a/src/Resources/translations/messages.pl.yml b/src/Resources/translations/messages.pl.yml index 4fda0000..55556167 100644 --- a/src/Resources/translations/messages.pl.yml +++ b/src/Resources/translations/messages.pl.yml @@ -12,6 +12,7 @@ bitbag_sylius_wishlist_plugin: added_to_cart: Produkty z listy życzeń zostały dodane do koszyka. save_wishlist: Zapisz listę życzeń variant_not_unique: Ten wariant jest już na Twojej liście życzeń + insufficient_stock: '%productName% nie ma wystarczającego stanu magazynowego.' increase_quantity: Zwiększ ilość przynajmniej jednego z produktów. select_products: Wybierz przynajmniej jeden produkt. added_selected_wishlist_items_to_cart: Wybrane produkty zostały dodane do koszyka.