src/Controller/CartController.php line 100

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Exception\InvalidCustomAddressInformation;
  4. use App\Form\CartFormType;
  5. use App\Model\Collection\ProductArticleCollection;
  6. use App\Model\View\CartItem;
  7. use App\Services\CartService;
  8. use App\Services\ConfigService;
  9. use App\Services\CouponService;
  10. use App\Services\Factory\OrderFactory;
  11. use App\Services\GeneralSendMailService;
  12. use App\Services\MollieService;
  13. use App\Services\ReCaptchaService;
  14. use Carbon\Carbon;
  15. use Exception;
  16. use Mollie\Api\Resources\Payment;
  17. use Pimcore\Log\ApplicationLogger;
  18. use Pimcore\Log\Simple;
  19. use Pimcore\Model\DataObject\Fieldcollection\Data\Coupon as CouponF;
  20. use Pimcore\Model\DataObject\Coupon;
  21. use Pimcore\Model\DataObject\Order;
  22. use Pimcore\Model\DataObject\Order\Listing;
  23. use Pimcore\Model\DataObject\ProductArticle;
  24. use Pimcore\Model\DataObject\UserPortal;
  25. use Psr\Log\LoggerInterface;
  26. use Symfony\Component\HttpFoundation\JsonResponse;
  27. use Symfony\Component\HttpFoundation\Request;
  28. use Symfony\Component\HttpFoundation\RequestStack;
  29. use Symfony\Component\HttpFoundation\Response;
  30. use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
  31. use Symfony\Component\Mailer\MailerInterface;
  32. use Symfony\Component\Mime\Email;
  33. use Symfony\Component\Routing\Annotation\Route;
  34. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  35. use Twig\Environment;
  36. class CartController extends BaseController
  37. {
  38.     protected string $recaptchaVersion;
  39.     protected string $recaptchaPublicKey;
  40.     protected ReCaptchaService $recaptcha;
  41.     private CartService $cartService;
  42.     private OrderFactory $orderFactory;
  43.     private MollieService $mollieService;
  44.     private LoggerInterface $logger;
  45.     private  CouponService $couponService;
  46.     protected GeneralSendMailService $generalSendMailService;
  47.     public function __construct(
  48.         Environment $twig,
  49.         RequestStack $requestStack,
  50.         ConfigService $config,
  51.         OrderFactory $orderFactory,
  52.         GeneralSendMailService $generalSendMailService,
  53.         ReCaptchaService $recaptcha,
  54.         CartService $cartService,
  55.         MollieService $mollieService,
  56.         LoggerInterface $logger,
  57.         CouponService $couponService
  58.     ) {
  59.         parent::__construct($twig$requestStack$config);
  60.         $this->recaptcha $recaptcha;
  61.         $this->recaptchaVersion $recaptcha->getVersion();
  62.         $this->recaptchaPublicKey $recaptcha->getPublicKey();
  63.         $this->generalSendMailService $generalSendMailService;
  64.         $this->cartService $cartService;
  65.         $this->mollieService $mollieService;
  66.         $this->orderFactory $orderFactory;
  67.         $this->logger $logger;
  68.         $this->couponService $couponService;
  69.     }
  70.     /**
  71.      * View cart page
  72.      *
  73.      * @Route("{_locale}/cart", name="cart-page")
  74.      *
  75.      * @param Request $request
  76.      * @return Response
  77.      */
  78.     public function indexAction(Request $request): Response
  79.     {
  80.         $session $request->getSession();
  81.         $user $this->cartService->getUserFromSession($session);
  82.         $cartItems $this->cartService->getCartFromSession($session);
  83.         $cartItemsViewModels = [];
  84.         foreach ($cartItems as $cartItem) {
  85.             $cartItemsViewModels[] = new CartItem($cartItem);
  86.         }
  87.         if (empty($cartItems)) {
  88.             return $this->render('cart/index.html.twig', [
  89.                 'user' => $user
  90.             ]);
  91.         }
  92.         $sessionProductArticleCollection $this->cartService->getProductArticleCollectionFromSession($session);
  93.         $cartTotal $sessionProductArticleCollection $sessionProductArticleCollection->getTotalValue() : 0;
  94.         return $this->render('cart/index.html.twig', [
  95.             'cartItems' => $cartItemsViewModels,
  96.             'cartTotal' => CartService::formatPrice($cartTotal),
  97.             'user' => $user,
  98.             'amountIsEditable' => true
  99.         ]);
  100.     }
  101.     /**
  102.      *    Update cart page
  103.      *
  104.      * @Route("{_locale}/cart/update", name="cartupdate-page")
  105.      *
  106.      * @param Request $request
  107.      * @return JsonResponse
  108.      * @throws Exception
  109.      */
  110.     public function cartUpdateAction(Request $request): JsonResponse
  111.     {
  112.         $session $request->getSession();
  113.         $sessionCart $this->cartService->getProductArticleCollectionFromSession($session);
  114.         $productId $request->get('productId');
  115.         $amount $request->get('amount');
  116.         $actionWeb $request->get('action');
  117.         if ($request->isXmlHttpRequest()) {
  118.             if (!$sessionCart instanceof ProductArticleCollection) {
  119.                 $sessionCart = new ProductArticleCollection();
  120.                 $session->set(CartService::$sessionCartIdentifier$sessionCart);
  121.             }
  122.             $productArticle ProductArticle::getById($productId);
  123.             if (!$productArticle instanceof ProductArticle) {
  124.                 return $this->returnJsonErrorToCart(sprintf('Could not find article with id %s'$productId));
  125.             }
  126.             switch ($actionWeb) {
  127.                 case 'add':
  128.                     $sessionCart->addProductArticle($productArticle$amount);
  129.                     break;
  130.                 case 'update':
  131.                     $sessionCart->updateProductArticleCount($productArticle$amount);
  132.                     break;
  133.                 case 'remove':
  134.                     $sessionCart->removeProductArticle($productArticle);
  135.                     break;
  136.             }
  137.             $cartCount $sessionCart->getCartCount();
  138.             $cartValue CartService::formatPrice($sessionCart->getTotalValue());
  139.             $totalProductValue CartService::formatPrice($sessionCart->getTotalProductValue($productArticle));
  140.             return $this->returnJsonSuccess($actionWeb$productArticle$amount$cartCount$cartValue$totalProductValue);
  141.         }
  142.         return $this->returnJsonErrorToCart();
  143.     }
  144.     /**
  145.      * empty cart
  146.      *
  147.      * @Route("{_locale}/cart/clear", name="cart-clear")
  148.      *
  149.      * @param Request $request
  150.      * @return Response
  151.      */
  152.     public function emptyCartAction(Request $request): Response
  153.     {
  154.         $session $request->getSession();
  155.         $oldSessionCart $this->cartService->getProductArticleCollectionFromSession($session);
  156.         if ($oldSessionCart instanceof ProductArticleCollection) {
  157.             $oldOrder $oldSessionCart->getOrder();
  158.             if ($oldOrder instanceof Order) {
  159.                 try {
  160.                     $oldOrder->delete();
  161.                 } catch (Exception $e) {
  162.                     $this->logger->error(sprintf('empty cart action threw exception: %s'$e->getMessage()));
  163.                 }
  164.             }
  165.         }
  166.         $session->set(CartService::$sessionCartIdentifier,new ProductArticleCollection());
  167.         return new JsonResponse(['message' => 'cleared'], Response::HTTP_OK);
  168.     }
  169.     /**
  170.      * empty cart
  171.      *
  172.      * @Route("{_locale}/cart/clear-coupon", name="cart-clear-coupon")
  173.      *
  174.      * @param Request $request
  175.      * @return Response
  176.      */
  177.     public function emptyCouponAction(Request $request): Response
  178.     {
  179.         $session $request->getSession();
  180.         $oldSessionCart $this->cartService->getProductArticleCollectionFromSession($session);
  181.         if ($oldSessionCart instanceof ProductArticleCollection) {
  182.             $order $oldSessionCart->getOrder();
  183.             if ($order instanceof Order) {
  184.                 try {
  185.                     $order->setCode('');
  186.                     $order->setPercentage(0);
  187.                     $order->setOldprice(0);
  188.                     $order->setNewprice(0);
  189.                     $order->setOrderTotal(CartService::formatPrice($order->getCartTotal() + $order->getShippingCost()));
  190.                     $order->setCoupon(false);
  191.                     $order->save();
  192.                 } catch (Exception $e) {
  193.                     $this->logger->error(sprintf('empty coupon action threw exception: %s'$e->getMessage()));
  194.                 }
  195.             }
  196.         }
  197.         return new JsonResponse(['message' => 'cleared'], Response::HTTP_OK);
  198.     }
  199.     /**
  200.      * Display form for delivery information + create order + link order to cart
  201.      *
  202.      * @Route("{_locale}/cart/delivery", name="cart-delivery")
  203.      *
  204.      * @param Request $request
  205.      * @return Response
  206.      * @throws Exception
  207.      */
  208.     public function deliveryAction(Request $request): Response
  209.     {
  210.         $session $request->getSession();
  211.         $user $this->cartService->getUserFromSession($session);
  212.         $cart $this->cartService->getProductArticleCollectionFromSession($session);
  213.         //no product articlecollection means there is no cart, redirect to cart page
  214.         //or when cart is empty, this step cannot be completed because this would result in an empty order
  215.         if (
  216.             !$cart instanceof ProductArticleCollection ||
  217.             $cart->getCartCount() === 0
  218.         ) {
  219.             return $this->redirectToRoute('cart-page');
  220.         }
  221.         $formName CartFormType::class;
  222.         $form $this->createForm($formName);
  223.         $form->handleRequest($request);
  224.         //User's shipping information is submitted
  225.         if ($form->isSubmitted() && $form->isValid()) {
  226.             $shippingInformation $form->getData();
  227.             $params $request->request->all();
  228.             /*dd($shippingInformation['shipping_option']);*/
  229.             if($this->recaptchaVersion) {
  230.                 if($this->recaptcha->captchaverify($params)){
  231.                     if ($user instanceof UserPortal) {
  232.                         try {
  233.                             $order $this->cartService->getOrderFromSession($session);
  234.                             if (!$order instanceof Order) {
  235.                                 $order $this->orderFactory->createOrder($user$shippingInformation$cart);
  236.                                 $cart->setOrder($order);
  237.                             } else {
  238.                                 $order $this->orderFactory->updateOrder($user$order$shippingInformation$cart);
  239.                                 $cart->setOrder($order);
  240.                             }
  241.                             //successfully created order, redirect to overview to pay
  242.                             return $this->redirectToRoute('cart-overview-page');
  243.                         } catch (InvalidCustomAddressInformation $e) {
  244.                             $this->addFlash(
  245.                                 'warning',
  246.                                 'Fout in leveringsadres, gelieve het leveringsadres correct in te vullen.'
  247.                             );
  248.                             return $this->render('cart/delivery.html.twig', [
  249.                                 'user' => $user,
  250.                                 'form' => $form->createView(),
  251.                             ]);
  252.                         }
  253.                     }
  254.                 }else{
  255.                     $message "Captcha code is niet correct!";
  256.                     $this->addFlash("warning"$message);
  257.                 }
  258.             }
  259.         }
  260.         return $this->render('cart/delivery.html.twig', [
  261.             'user' => $user,
  262.             'form' => $form->createView(),
  263.             'recaptcha' => $this->recaptchaVersion,
  264.             'recaptchaPublic' => $this->recaptchaPublicKey
  265.         ]);
  266.     }
  267.     /**
  268.      * Overview of order (final step)
  269.      *
  270.      * @Route("{_locale}/cart/overview", name="cart-overview-page")
  271.      *
  272.      * @param Request $request
  273.      * @return Response
  274.      * @throws Exception
  275.      */
  276.     public function overviewAction(Request $request,\Pimcore\Config\Config $websiteConfig): Response
  277.     {
  278.         $session $request->getSession();
  279.         $user $this->cartService->getUserFromSession($session);
  280.         $cart $this->cartService->getProductArticleCollectionFromSession($session);
  281.         if (
  282.             !$cart instanceof ProductArticleCollection ||
  283.             $cart->getCartCount() === 0
  284.         ) {
  285.             return $this->redirectToRoute('cart-page');
  286.         }
  287.         $order $this->cartService->getOrderFromSession($session);
  288.         if (!$order instanceof Order) {
  289.             $this->addFlash('waring''Er ging iets mis met het aanmaken van de bestelling, gelieve uw leveringsinformatie opnieuw in te vullen');
  290.             return $this->redirectToRoute('cart-delivery');
  291.         }
  292.         if ($user instanceof UserPortal) {
  293.             $order $this->orderFactory->fillProducts($order$cart);
  294.             $cart->setOrder($order);
  295.         }
  296.         $orderUser $order->getUser();
  297.         $cartItems $this->cartService->getCartFromSession($session);
  298.         $cartItemsViewModels = [];
  299.         foreach ($cartItems as $cartItem) {
  300.             $cartItemsViewModels[] = new CartItem($cartItem);
  301.         }
  302.         $cartTotal $order->getCartTotal();
  303.         $redirectUrl $this->generateUrl(
  304.             'cart-redirect-payment',
  305.             ['order' => $order->getOrderNumber()??''],
  306.             UrlGeneratorInterface::ABSOLUTE_URL
  307.         );
  308.         $webhookUrl $this->generateUrl(
  309.             'cart-check-payment',
  310.             ['order' => $order->getOrderNumber()??''],
  311.             UrlGeneratorInterface::ABSOLUTE_URL
  312.         );
  313.         $payment $this->mollieService->createPaymentForWebOrder($order$redirectUrl$webhookUrl);
  314.         if ($payment instanceof Payment) {
  315.             $this->orderFactory->updatePaymentInformation($order$paymenttrue);
  316.             $paymentRoute $payment->getCheckoutUrl();
  317.         } else {
  318.             $this->addFlash('waring','Er ging iets mis met het ophalen van de betalingslink.');
  319.             return $this->redirectToRoute('cart-delivery');
  320.         }
  321.         return $this->render('cart/overview.html.twig', [
  322.             'user' => $user,
  323.             'order' => $order,
  324.             'orderUser' => $orderUser,
  325.             'cartItems' => $cartItemsViewModels,
  326.             'cartTotal' => CartService::formatPrice($cartTotal),
  327.             'shippingTotal' => CartService::formatPrice($order->getShippingCost()),
  328.             'total' => $order->getOrderTotal(),
  329.             'paymentRoute' => $paymentRoute,
  330.             'totalCoupon' => $order->getNewprice(),
  331.         ]);
  332.     }
  333.     /**
  334.      * User will be redirected to this page after payment, order status gets checked and updated here
  335.      *
  336.      * @Route("{_locale}/cart/redirectpayment", name="cart-redirect-payment")
  337.      *
  338.      * @param Request $request
  339.      *
  340.      * @return Response
  341.      * @throws Exception
  342.      * @throws TransportExceptionInterface
  343.      */
  344.     public function redirectPaymentAction(Request $request,ApplicationLogger $logger): Response
  345.     {
  346.         $session $request->getSession();
  347.         $session->set(CartService::$sessionCartIdentifier, new ProductArticleCollection()); //empty original cart, since order was finished
  348.         $orderNumber $request->get('order');
  349.         $user $this->cartService->getUserFromSession($request->getSession());
  350.         /** @var Listing $order */
  351.         $orderListing Order::getByOrderNumber($orderNumber);
  352.         if (!empty($orderListing) && count($orderListing) === 1) {
  353.             $order = ($orderListing->getData())[0];
  354.             Simple::log('payment-redirect''OrderListing && count orderlisting OK');
  355.             $logger->info('OrderListing && count orderlisting OK',[ 'relatedObject' => $order]);
  356.             if ($order instanceof Order) {
  357.                 Simple::log('payment-redirect''$order instance of Order OK');
  358.                 $logger->info('$order instance of Order OK',['relatedObject' => $order]);
  359.                 $orderUser $order->getUser();
  360.                 //extra validation so other users can not find this user's order
  361.                 if (
  362.                     $user instanceof UserPortal &&
  363.                     $orderUser instanceof UserPortal &&
  364.                     $user->getKey() === $orderUser->getKey()
  365.                 ) {
  366.                     Simple::log('payment-redirect''User -> UserPortal, orderUser -> UserPortal, userKey OK');
  367.                     $logger->info('User -> UserPortal, orderUser -> UserPortal, userKey OK',['relatedObject' => $order]);
  368.                     $paymentId $order->getPaymentId();
  369.                     $payment $this->mollieService->getPaymentById($paymentId);
  370.                     if (($payment instanceof Payment)) {
  371.                         Simple::log('payment-redirect''Payment OK');
  372.                         $logger->info('Payment OK',['relatedObject' => $order]);
  373.                         $this->orderFactory->updatePaymentInformation($order$paymentfalse);
  374.                     }
  375.                     if ($order->getPaymentStatus() == 'paid'){
  376.                         Simple::log('payment-redirect''Mailstatus OK');
  377.                         return $this->render('cart/thank_you.html.twig', [
  378.                             'orderNumber' => $order->getOrderNumber()
  379.                         ]);
  380.                     }else{
  381.                         $this->redirectToRoute('cart-overview-page');
  382.                     }
  383.                 }
  384.             }
  385.         }
  386.         //this should not happen, but when this happens log this
  387.         if (count($orderListing)>1) {
  388.             $this->logger->error(sprintf('Duplicate orderNumber detected %s'$orderNumber));
  389.         }
  390.         Simple::log('payment-redirect''ReturnType Broken');
  391.         return $this->render('cart/thank_you.html.twig', []);
  392.     }
  393.     /**
  394.      * Webhook route for payment, if update is posted to order, it gets sent to this order
  395.      *
  396.      * @Route("{_locale}/cart/checkpayment", name="cart-check-payment")
  397.      *
  398.      * @param Request $request
  399.      * @return Response
  400.      * @throws Exception
  401.      */
  402.     public function checkPaymentAction(Request $request): Response
  403.     {
  404.         if($request->isMethod('POST')) {
  405.             $orderNumber $request->get('order');
  406.             $orderListing Order::getByOrderNumber($orderNumber);
  407.             if (!empty($orderListing) && count($orderListing) === 1) {
  408.                 $order = ($orderListing->getData())[0]; //get order from listing result
  409.                 $paymentId $order->getPaymentId();
  410.                 if (!empty($paymentId)) {
  411.                     $payment $this->mollieService->getPaymentById($paymentId);
  412.                     if (($payment instanceof Payment) && $order instanceof Order) {
  413.                         $this->orderFactory->updatePaymentInformation($order$paymentfalse);
  414.                     }
  415.                 }
  416.             }
  417.             //this should not happen, but when this happens log this
  418.             if (count($orderListing) > 1) {
  419.                 $this->logger->error(sprintf('Duplicate orderNumber detected %s'$orderNumber));
  420.             }
  421.         }
  422.         $language $request->attributes->get('_locale');
  423.         return $this->redirect(sprintf('/%s/'$language));
  424.     }
  425.     /**
  426.      * @param string|null $message
  427.      * @return JsonResponse
  428.      */
  429.     private function returnJsonErrorToCart(?string $message null): JsonResponse
  430.     {
  431.         $errorMessage $message ?? 'Something went wrong while adding article to cart';
  432.         return new JsonResponse(
  433.             [$errorMessage],
  434.             Response::HTTP_INTERNAL_SERVER_ERROR
  435.         );
  436.     }
  437.     /**
  438.      * @param string $actionWeb
  439.      * @param ProductArticle $productArticle
  440.      * @param string|null $amount
  441.      * @param string $cartCount
  442.      * @param string $cartValue
  443.      * @param string|null $totalProductValue
  444.      *
  445.      * @return JsonResponse
  446.      */
  447.     private function returnJsonSuccess(
  448.         string $actionWeb,
  449.         ProductArticle $productArticle,
  450.         ?string $amount,
  451.         string $cartCount,
  452.         string $cartValue,
  453.         ?string $totalProductValue,
  454.     ): JsonResponse
  455.     {
  456.         if (empty($amount)) {
  457.             $amount '0';
  458.         }
  459.         return new JsonResponse([
  460.             'action' => $actionWeb,
  461.             'article' => $productArticle,
  462.             'amount' => $amount,
  463.             'cartCount' => $cartCount,
  464.             'cartValue' => $cartValue,
  465.             'totalProductValue' => $totalProductValue,
  466.         ], Response::HTTP_OK);
  467.     }
  468. }