custom/plugins/AbasBecoCustomizations/src/Storefront/Controller/CustomCheckoutController.php line 193

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace AbasBecoCustomizations\Storefront\Controller;
  3. use AbasBecoCustomizations\Components\BecoCustomerData;
  4. use Shopware\Core\Checkout\Cart\Cart;
  5. use Shopware\Core\Checkout\Cart\Error\Error;
  6. use Shopware\Core\Checkout\Cart\Error\ErrorCollection;
  7. use Shopware\Core\Checkout\Cart\Exception\CartTokenNotFoundException;
  8. use Shopware\Core\Checkout\Cart\Exception\CustomerNotLoggedInException;
  9. use Shopware\Core\Checkout\Cart\Exception\InvalidCartException;
  10. use Shopware\Core\Checkout\Cart\Exception\OrderNotFoundException;
  11. use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
  12. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLogoutRoute;
  13. use Shopware\Core\Checkout\Order\Exception\EmptyCartException;
  14. use Shopware\Core\Checkout\Order\SalesChannel\OrderService;
  15. use Shopware\Core\Checkout\Payment\Exception\InvalidOrderException;
  16. use Shopware\Core\Checkout\Payment\Exception\PaymentProcessException;
  17. use Shopware\Core\Checkout\Payment\Exception\UnknownPaymentMethodException;
  18. use Shopware\Core\Checkout\Payment\PaymentService;
  19. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  20. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  21. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  22. use Shopware\Core\Framework\Routing\Annotation\Since;
  23. use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
  24. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  25. use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
  26. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  27. use Shopware\Core\System\SystemConfig\SystemConfigService;
  28. use Shopware\Storefront\Checkout\Cart\Error\PaymentMethodChangedError;
  29. use Shopware\Storefront\Checkout\Cart\Error\ShippingMethodChangedError;
  30. use Shopware\Storefront\Controller\CheckoutController;
  31. use Shopware\Storefront\Controller\StorefrontController;
  32. use Shopware\Storefront\Framework\AffiliateTracking\AffiliateTrackingListener;
  33. use Shopware\Storefront\Framework\Routing\Annotation\NoStore;
  34. use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedHook;
  35. use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoader;
  36. use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedHook;
  37. use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoader;
  38. use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedHook;
  39. use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoader;
  40. use Shopware\Storefront\Page\Checkout\Offcanvas\CheckoutInfoWidgetLoadedHook;
  41. use Shopware\Storefront\Page\Checkout\Offcanvas\CheckoutOffcanvasWidgetLoadedHook;
  42. use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoader;
  43. use Symfony\Component\HttpFoundation\RedirectResponse;
  44. use Symfony\Component\HttpFoundation\Request;
  45. use Symfony\Component\HttpFoundation\Response;
  46. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  47. use Symfony\Component\Routing\Annotation\Route;
  48. /**
  49.  * @RouteScope(scopes={"storefront"})
  50.  */
  51. class CustomCheckoutController extends CheckoutController
  52. {
  53.     private const REDIRECTED_FROM_SAME_ROUTE 'redirected';
  54.     /**
  55.      * @var CartService
  56.      */
  57.     private $cartService;
  58.     /**
  59.      * @var CheckoutCartPageLoader
  60.      */
  61.     private $cartPageLoader;
  62.     /**
  63.      * @var CheckoutConfirmPageLoader
  64.      */
  65.     private $confirmPageLoader;
  66.     /**
  67.      * @var CheckoutFinishPageLoader
  68.      */
  69.     private $finishPageLoader;
  70.     /**
  71.      * @var OrderService
  72.      */
  73.     private $orderService;
  74.     /**
  75.      * @var PaymentService
  76.      */
  77.     private $paymentService;
  78.     /**
  79.      * @var OffcanvasCartPageLoader
  80.      */
  81.     private $offcanvasCartPageLoader;
  82.     /**
  83.      * @var SystemConfigService
  84.      */
  85.     private $config;
  86.     /**
  87.      * @var AbstractLogoutRoute
  88.      */
  89.     private $logoutRoute;
  90.     /**
  91.      * @var EntityRepositoryInterface
  92.      */
  93.     private $orderRepository;
  94.     public function __construct(
  95.         CartService               $cartService,
  96.         CheckoutCartPageLoader    $cartPageLoader,
  97.         CheckoutConfirmPageLoader $confirmPageLoader,
  98.         CheckoutFinishPageLoader  $finishPageLoader,
  99.         OrderService              $orderService,
  100.         PaymentService            $paymentService,
  101.         OffcanvasCartPageLoader   $offcanvasCartPageLoader,
  102.         SystemConfigService       $config,
  103.         AbstractLogoutRoute       $logoutRoute,
  104.         EntityRepositoryInterface $orderRepository
  105.     )
  106.     {
  107.         parent::__construct(
  108.             $cartService,
  109.             $cartPageLoader,
  110.             $confirmPageLoader,
  111.             $finishPageLoader,
  112.             $orderService,
  113.             $paymentService,
  114.             $offcanvasCartPageLoader,
  115.             $config,
  116.             $logoutRoute);
  117.         $this->cartService $cartService;
  118.         $this->cartPageLoader $cartPageLoader;
  119.         $this->confirmPageLoader $confirmPageLoader;
  120.         $this->finishPageLoader $finishPageLoader;
  121.         $this->orderService $orderService;
  122.         $this->paymentService $paymentService;
  123.         $this->offcanvasCartPageLoader $offcanvasCartPageLoader;
  124.         $this->config $config;
  125.         $this->logoutRoute $logoutRoute;
  126.         $this->orderRepository $orderRepository;
  127.     }
  128.     /**
  129.      * @param Cart $cart
  130.      * @param string $commissionNumber
  131.      * @param string $orderComment
  132.      * @return Cart
  133.      */
  134.     public function addAndGetBecoCustomerDataExtension(Cart $cart$commissionNumber ""$orderComment ""): Cart
  135.     {
  136.         $becoCustomCartData = new BecoCustomerData();
  137.         $becoCustomCartData->setOrderCommissionNumber($commissionNumber);
  138.         $becoCustomCartData->setOrderComment($orderComment);
  139.         if ($cart->hasExtension("beco_customer_data")) {
  140.             $cart->removeExtension("beco_customer_data");
  141.         }
  142.         $cart->addExtension("beco_customer_data"$becoCustomCartData);
  143.         return $cart;
  144.     }
  145.     /**
  146.      * @Since("6.0.0.0")
  147.      * @NoStore
  148.      * @Route("/checkout/cart", name="frontend.checkout.cart.page", options={"seo"="false"}, methods={"GET"})
  149.      */
  150.     public function cartPage(Request $requestSalesChannelContext $context): Response
  151.     {
  152.         $page $this->cartPageLoader->load($request$context);
  153.         $cart $page->getCart();
  154.         $cartErrors $cart->getErrors();
  155.         $this->addAndGetBecoCustomerDataExtension($cart);
  156.         $this->hook(new CheckoutCartPageLoadedHook($page$context));
  157.         $this->addCartErrors($cart);
  158.         if (!$request->query->getBoolean(self::REDIRECTED_FROM_SAME_ROUTE) && $this->routeNeedsReload($cartErrors)) {
  159.             $cartErrors->clear();
  160.             // To prevent redirect loops add the identifier that the request already got redirected from the same origin
  161.             return $this->redirectToRoute(
  162.                 'frontend.checkout.cart.page',
  163.                 [
  164.                     self::REDIRECTED_FROM_SAME_ROUTE => true,
  165.                 ]
  166.             );
  167.         }
  168.         $cartErrors->clear();
  169.         return $this->renderStorefront('@Storefront/storefront/page/checkout/cart/index.html.twig', ['page' => $page]);
  170.     }
  171.     /**
  172.      * @Since("6.0.0.0")
  173.      * @NoStore
  174.      * @Route("/checkout/confirm", name="frontend.checkout.confirm.page", options={"seo"="false"}, methods={"GET"}, defaults={"XmlHttpRequest"=true})
  175.      */
  176.     public function confirmPage(Request $requestSalesChannelContext $context): Response
  177.     {
  178.         $orderCommissionNumber $request->get("orderCommissionNumber");
  179.         $orderComment $request->get("orderComment");
  180.         if (!$context->getCustomer()) {
  181.             return $this->redirectToRoute('frontend.checkout.register.page');
  182.         }
  183.         if ($this->cartService->getCart($context->getToken(), $context)->getLineItems()->count() === 0) {
  184.             return $this->redirectToRoute('frontend.checkout.cart.page');
  185.         }
  186.         $page $this->confirmPageLoader->load($request$context);
  187.         $cart $page->getCart();
  188.         $cart $this->addAndGetBecoCustomerDataExtension($cart$orderCommissionNumber$orderComment);
  189.         $errors $cart->getErrors();
  190.         $errors->remove("billing-address-invalid");
  191.         $errors->remove("shipping-address-invalid");
  192.         $cart->setErrors($errors);
  193.         $page->setCart($cart);
  194.         $this->hook(new CheckoutConfirmPageLoadedHook($page$context));
  195.         $this->addCartErrors($page->getCart());
  196.         return $this->renderStorefront('@Storefront/storefront/page/checkout/confirm/index.html.twig', ['page' => $page]);
  197.     }
  198.     /**
  199.      * @Since("6.0.0.0")
  200.      * @Route("/checkout/finish", name="frontend.checkout.finish.page", options={"seo"="false"}, methods={"GET"})
  201.      * @NoStore
  202.      *
  203.      * @throws CustomerNotLoggedInException
  204.      * @throws MissingRequestParameterException
  205.      * @throws OrderNotFoundException
  206.      */
  207.     public function finishPage(Request $requestSalesChannelContext $contextRequestDataBag $dataBag): Response
  208.     {
  209.         if ($context->getCustomer() === null) {
  210.             return $this->redirectToRoute('frontend.checkout.register.page');
  211.         }
  212.         $page $this->finishPageLoader->load($request$context);
  213.         $this->hook(new CheckoutFinishPageLoadedHook($page$context));
  214.         if ($page->isPaymentFailed() === true) {
  215.             return $this->redirectToRoute(
  216.                 'frontend.account.edit-order.page',
  217.                 [
  218.                     'orderId' => $request->get('orderId'),
  219.                     'error-code' => 'CHECKOUT__UNKNOWN_ERROR',
  220.                 ]
  221.             );
  222.         }
  223.         if ($context->getCustomer()->getGuest() && $this->config->get('core.cart.logoutGuestAfterCheckout'$context->getSalesChannelId())) {
  224.             $this->logoutRoute->logout($context$dataBag);
  225.         }
  226.         return $this->renderStorefront('@Storefront/storefront/page/checkout/finish/index.html.twig', ['page' => $page]);
  227.     }
  228.     /**
  229.      * @Since("6.0.0.0")
  230.      * @Route("/checkout/order", name="frontend.checkout.finish.order", options={"seo"="false"}, methods={"POST"})
  231.      */
  232.     public function order(RequestDataBag $dataSalesChannelContext $contextRequest $request): Response
  233.     {
  234.         if (!$context->getCustomer()) {
  235.             return $this->redirectToRoute('frontend.checkout.register.page');
  236.         }
  237.         try {
  238.             $this->addAffiliateTracking($data$request->getSession());
  239.             $orderId $this->orderService->createOrder($data$context);
  240.             $order $this->orderRepository->search((new Criteria([$orderId])), $context->getContext())->first();
  241.             if ($order) {
  242.                 $customFields $order->getCustomFields();
  243.                 $orderCommissionNumber $request->get("orderCommissionNumber");
  244.                 $orderComment $request->get("customerComment");
  245.                 $customFields["sms_beco_technic_order_comment"] = $orderComment;
  246.                 $customFields["sms_beco_technic_order_commission_number"] = $orderCommissionNumber;
  247.                 $this->orderRepository->upsert([[
  248.                     "id" => $orderId,
  249.                     "customFields" => $customFields
  250.                 ]], $context->getContext());
  251.                 $this->cartService->deleteCart($context);
  252.             }
  253.         } catch (ConstraintViolationException $formViolations) {
  254.             return $this->forwardToRoute('frontend.checkout.confirm.page', ['formViolations' => $formViolations]);
  255.         } catch (InvalidCartException|Error|EmptyCartException $error) {
  256.             $this->addCartErrors(
  257.                 $this->cartService->getCart($context->getToken(), $context)
  258.             );
  259.             return $this->forwardToRoute('frontend.checkout.confirm.page');
  260.         }
  261.         try {
  262.             $finishUrl $this->generateUrl('frontend.checkout.finish.page', ['orderId' => $orderId]);
  263.             $errorUrl $this->generateUrl('frontend.account.edit-order.page', ['orderId' => $orderId]);
  264.             $response $this->paymentService->handlePaymentByOrder($orderId$data$context$finishUrl$errorUrl);
  265.             return $response ?? new RedirectResponse($finishUrl);
  266.         } catch (PaymentProcessException|InvalidOrderException|UnknownPaymentMethodException $e) {
  267.             return $this->forwardToRoute('frontend.checkout.finish.page', ['orderId' => $orderId'changedPayment' => false'paymentFailed' => true]);
  268.         }
  269.     }
  270.     /**
  271.      * @Since("6.0.0.0")
  272.      * @Route("/widgets/checkout/info", name="frontend.checkout.info", methods={"GET"}, defaults={"XmlHttpRequest"=true})
  273.      *
  274.      * @throws CartTokenNotFoundException
  275.      */
  276.     public function info(Request $requestSalesChannelContext $context): Response
  277.     {
  278.         $page $this->offcanvasCartPageLoader->load($request$context);
  279.         $this->hook(new CheckoutInfoWidgetLoadedHook($page$context));
  280.         $response $this->renderStorefront('@Storefront/storefront/layout/header/actions/cart-widget.html.twig', ['page' => $page]);
  281.         $response->headers->set('x-robots-tag''noindex');
  282.         return $response;
  283.     }
  284.     /**
  285.      * @Since("6.0.0.0")
  286.      * @Route("/checkout/offcanvas", name="frontend.cart.offcanvas", options={"seo"="false"}, methods={"GET"}, defaults={"XmlHttpRequest"=true})
  287.      *
  288.      * @throws CartTokenNotFoundException
  289.      */
  290.     public function offcanvas(Request $requestSalesChannelContext $context): Response
  291.     {
  292.         $page $this->offcanvasCartPageLoader->load($request$context);
  293.         $this->hook(new CheckoutOffcanvasWidgetLoadedHook($page$context));
  294.         $cart $page->getCart();
  295.         $this->addCartErrors($cart);
  296.         $cartErrors $cart->getErrors();
  297.         if (!$request->query->getBoolean(self::REDIRECTED_FROM_SAME_ROUTE) && $this->routeNeedsReload($cartErrors)) {
  298.             $cartErrors->clear();
  299.             // To prevent redirect loops add the identifier that the request already got redirected from the same origin
  300.             return $this->redirectToRoute(
  301.                 'frontend.cart.offcanvas',
  302.                 [
  303.                     self::REDIRECTED_FROM_SAME_ROUTE => true,
  304.                 ]
  305.             );
  306.         }
  307.         $cartErrors->clear();
  308.         return $this->renderStorefront('@Storefront/storefront/component/checkout/offcanvas-cart.html.twig', ['page' => $page]);
  309.     }
  310.     private function addAffiliateTracking(RequestDataBag $dataBagSessionInterface $session): void
  311.     {
  312.         $affiliateCode $session->get(AffiliateTrackingListener::AFFILIATE_CODE_KEY);
  313.         $campaignCode $session->get(AffiliateTrackingListener::CAMPAIGN_CODE_KEY);
  314.         if ($affiliateCode) {
  315.             $dataBag->set(AffiliateTrackingListener::AFFILIATE_CODE_KEY$affiliateCode);
  316.         }
  317.         if ($campaignCode) {
  318.             $dataBag->set(AffiliateTrackingListener::CAMPAIGN_CODE_KEY$campaignCode);
  319.         }
  320.     }
  321.     private function routeNeedsReload(ErrorCollection $cartErrors): bool
  322.     {
  323.         foreach ($cartErrors as $error) {
  324.             if ($error instanceof ShippingMethodChangedError || $error instanceof PaymentMethodChangedError) {
  325.                 return true;
  326.             }
  327.         }
  328.         return false;
  329.     }
  330. }