src/Controller/CheckoutPageController.php line 710

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Controller\Api\ApiCheckoutController;
  4. use App\Entity\EndUser;
  5. use App\Entity\FunnelVisitor;
  6. use App\Entity\Order;
  7. use App\Entity\Product;
  8. use App\Entity\Tracker;
  9. use App\Form\Type\OrderType;
  10. use App\Form\Type\PostUpsellOrderType;
  11. use App\Helper\Order\OrderHelper;
  12. use App\Service\EndUserManager;
  13. use App\Service\EventProvider\EventProvider;
  14. use App\Service\EventProviderManager;
  15. use App\Service\FunnelVisitorManager;
  16. use App\Service\OrderHolderManager;
  17. use App\Service\OrderManager;
  18. use App\Service\OrderReminderManager;
  19. use App\Service\OrderSubscriptionManager;
  20. use App\Service\ProductManager;
  21. use App\Service\ProductPostUpsellManager;
  22. use App\Service\TrackerManager;
  23. use App\Service\UpsellCheckoutManager;
  24. use App\Service\VisitorsTracker;
  25. use App\Service\VoucherService;
  26. use Detection\MobileDetect;
  27. use GeoIp2\Database\Reader;
  28. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  29. use Symfony\Component\Form\FormInterface;
  30. use Symfony\Component\HttpFoundation\Request;
  31. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  32. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  33. use Symfony\Component\Routing\Annotation\Route;
  34. use Symfony\Component\HttpFoundation\Response;
  35. use App\Service\ReplacerTextManager;
  36. use App\Service\ProductVariantManager;
  37. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  38. final class CheckoutPageController extends CustomAbstractController
  39. {
  40.     private $productManager;
  41.     private $orderManager;
  42.     private $session;
  43.     private $endUserManager;
  44.     private $replacerTextManager;
  45.     private $orderReminderManager;
  46.     private $trackerManager;
  47.     private $productVariantManager;
  48.     private $productPostUpsellManager;
  49.     private $eventProviderManager;
  50.     private $orderHolderManager;
  51.     private $orderSubscriptionManager;
  52.     private $visitorsTracker;
  53.     private UpsellCheckoutManager $upsellCheckoutManager;
  54.     private FunnelVisitorManager $funnelVisitorManager;
  55.     private VoucherService $voucherService;
  56.     public function __construct(
  57.         ProductManager           $productManager,
  58.         SessionInterface         $session,
  59.         OrderManager             $orderManager,
  60.         EndUserManager           $endUserManager,
  61.         ReplacerTextManager      $replacerTextManager,
  62.         OrderReminderManager     $orderReminderManager,
  63.         TrackerManager           $trackerManager,
  64.         ProductVariantManager    $productVariantManager,
  65.         ProductPostUpsellManager $productPostUpsellManager,
  66.         EventProviderManager     $eventProviderManager,
  67.         OrderHolderManager       $orderHolderManager,
  68.         OrderSubscriptionManager $orderSubscriptionManager,
  69.         VisitorsTracker          $visitorsTracker,
  70.         FunnelVisitorManager     $funnelVisitorManager,
  71.         UpsellCheckoutManager    $upsellCheckoutManager,
  72.         VoucherService           $voucherService
  73.     )
  74.     {
  75.         $this->productManager $productManager;
  76.         $this->orderManager $orderManager;
  77.         $this->session $session;
  78.         $this->endUserManager $endUserManager;
  79.         $this->replacerTextManager $replacerTextManager;
  80.         $this->orderReminderManager $orderReminderManager;
  81.         $this->trackerManager $trackerManager;
  82.         $this->productVariantManager $productVariantManager;
  83.         $this->productPostUpsellManager $productPostUpsellManager;
  84.         $this->eventProviderManager $eventProviderManager;
  85.         $this->orderHolderManager $orderHolderManager;
  86.         $this->orderSubscriptionManager $orderSubscriptionManager;
  87.         $this->visitorsTracker $visitorsTracker;
  88.         $this->funnelVisitorManager $funnelVisitorManager;
  89.         $this->upsellCheckoutManager $upsellCheckoutManager;
  90.         $this->voucherService $voucherService;
  91.     }
  92.     /**
  93.      * @Route("/{_locale}/product1/{urlTitle}", name="product_page1")
  94.      * @param Request $request
  95.      * @param string $url_title
  96.      * @return Response
  97.      */
  98.     public function checkoutPage(Request $requeststring $url_title): Response
  99.     {
  100.         $order = new Order();
  101.         $this->defineCountry($request);
  102.         $product $this->productManager->getProduct($url_title$request->server->get('HTTP_HOST'));
  103.         $productVariant $this->productVariantManager->getPreselectedProductVariant($product);
  104.         $this->initiateCart($product$product->getUpsells());
  105.         $cartKey OrderHelper::cartKey($productApiCheckoutController::SESSION_UPSELL_KEY);
  106.         $upsells $this->session->has($cartKey) ? $this->session->get($cartKey) : [];
  107. //        $this->checkOrderReminder($request, $order, $url_title);
  108.         $isStepTwo $this->session->has('order') && isset($this->session->get('order')[$url_title]);
  109.         if ($isStepTwo) {
  110.             $productVariant $this->productManager->getProductVariant($product$this->session->get('variantId'));
  111.             $this->handleStepTwo($request$order$url_title$product$productVariant);
  112.         } else {
  113.             $this->handleStepOne($request$productVariant$product);
  114.         }
  115.         $form $this->createOrderForm($order$product$isStepTwo$request);
  116.         $form->handleRequest($request);
  117.         if ($form->isSubmitted() && $form->isValid()) {
  118.             return $this->handleFormSubmission($form$request$url_title$product$productVariant$upsells$isStepTwo);
  119.         }
  120.         return $this->renderCheckoutPage($request$isStepTwo$product$productVariant$form$upsells);
  121.     }
  122.     private function handleStepTwo(Request $requestOrder $orderstring $url_titleProduct $product$productVariant)
  123.     {
  124.         $stepOneOrder $this->session->get('order')[$url_title];
  125.         $formEndUser $stepOneOrder->getEndUser();
  126.         $endUser $this->endUserManager->findUserByEmail($formEndUser->getEmail()) ?? $formEndUser;
  127.         $endUser
  128.             ->setLocale($request->getLocale())
  129.             ->setSubscribed($formEndUser->isSubscribed());
  130.         $order->setEndUser($endUser)
  131.             ->setTermsAndConditions($stepOneOrder->isTermsAndConditions())
  132.             ->setEventId($this->session->get('eventID'))
  133.             ->setEventAdditionalParams($this->eventProviderManager->processRequestEventParams())
  134.             ->setType($stepOneOrder->getType())
  135.             ->setSubscriptionId($stepOneOrder->getSubscriptionId());
  136.         if (!$this->session->has('orderReminder')) {
  137.             $orderReminder $this->orderReminderManager->save($product$productVariant$endUser);
  138.             $this->session->set('orderReminder'$orderReminder);
  139.         }
  140.         $this->funnelVisitorManager->internalTrack(
  141.             FunnelVisitor::INTERNAL_PAGE_ADD_PAYMENT_INFO,
  142.             $request,
  143.             $product
  144.         );
  145.     }
  146.     private function handleStepOne(Request $request$productVariant$product)
  147.     {
  148.         if ($request->isMethod($request::METHOD_GET)) {
  149. //            $this->eventProviderManager->sendEvent(
  150. //                EventProvider::EVENT_ADD_TO_CART,
  151. //                $productVariant
  152. //            );
  153.             $this->visitorsTracker->tracking($request$product);
  154.             $this->funnelVisitorManager->internalTrack(
  155.                 FunnelVisitor::INTERNAL_PAGE_ADD_TO_CART,
  156.                 $request,
  157.                 $product
  158.             );
  159.         }
  160.     }
  161.     private function createOrderForm(Order $order$productbool $isStepTwoRequest $request)
  162.     {
  163.         return $this->createForm(OrderType::class, $order, [
  164.             'action' => $this->generateUrlWithParams('product_page', ['urlTitle' => $product->getUrlTitle()], UrlGeneratorInterface::ABSOLUTE_PATH$request),
  165.             'method' => 'POST',
  166.             'step2' => $isStepTwo,
  167.             'product' => $product,
  168.             'endUser' => $order->getEndUser(),
  169.         ]);
  170.     }
  171.     private function handleFormSubmission(FormInterface $formRequest $requeststring $url_title$product$productVariant$upsellsbool $isStepTwo)
  172.     {
  173.         $order $form->getData();
  174.         $vouchers $form->has('endUserVouchers') ? $form->get('endUserVouchers')->getData() : [];
  175.         if (!$isStepTwo) {
  176.             $this->session->set('order', [$url_title => $order]);
  177.             $this->session->set('variantId'$form->get('variantId')->getData());
  178.             $this->eventProviderManager->sendEvent(
  179.                 EventProvider::EVENT_INITIATE_CHECKOUT,
  180.                 $this->productManager->getProductVariant($product$this->session->get('variantId')),
  181.                 $this->endUserManager->findUserByEmail($order->getEndUser()->getEmail()) ?? $order->getEndUser(),
  182.                 null,
  183.                 $order->getEndUser()->isSubscribed()
  184.             );
  185.             return $this->json(['redirectUrl' => $this->generateUrlWithParams(
  186.                 'product_page', ['urlTitle' => $product->getUrlTitle()], UrlGeneratorInterface::ABSOLUTE_PATH$request)
  187.             ]);
  188.         }
  189.         $trackingParams json_decode($request->cookies->get('tracking'''), true);
  190.         if ($trackingParams) {
  191.             if (isset($trackingParams[Tracker::TRACKER_PARAM])) {
  192.                 $tracker $this->trackerManager->findTracker($trackingParams[Tracker::TRACKER_PARAM]);
  193.                 $order->setTracker($tracker);
  194.             }
  195.             $order->setTrackingParams($trackingParams);
  196.         }
  197.         $order->setFunnel($this->funnelVisitorManager->detectCheckoutFunnel($request$product));
  198.         $order->setIp($request->getClientIp());
  199. //        $this->funnelVisitorManager->assignTrackerInfoFromFunnelFirstStep($order, $product, $request->server->get('REMOTE_ADDR'));
  200.         if ($this->orderManager->saveOrder($order$product$productVariant$upsells$vouchers)) {
  201.             $orderReminder $this->session->get('orderReminder');
  202.             $this->orderReminderManager->update($orderReminder, ['orderSaved' => true]);
  203.             $this->session->remove('orderReminder');
  204.             $this->session->remove(OrderHelper::cartKey($productApiCheckoutController::SESSION_UPSELL_KEY));
  205.             $this->session->remove('order');
  206.             $this->orderSubscriptionManager->isSubscriptionRequired($order);
  207.             return $this->processPayment($order$product$request);
  208.         }
  209.         return $this->json(['error' => 'Unable to save order']);
  210.     }
  211.     private function processPayment(Order $order$productRequest $request)
  212.     {
  213.         $response $this->orderManager->processPayment($order);
  214.         if (isset($response['redirectUrl'])) {
  215.             $this->eventProviderManager->sendEvent(
  216.                 EventProvider::EVENT_ADD_PAYMENT_INFO,
  217.                 $this->orderManager->getMainProductVariant($order),
  218.                 $order->getUserSnapshot(),
  219.                 $order
  220.             );
  221.             $this->orderManager->updateOrderPaymentWithResponse($order$response);
  222.             return $this->json(['redirectUrl' => $response['redirectUrl']]);
  223.         } elseif (isset($response['client_token'])) {
  224.             return $this->json(['redirectUrl' => $this->generateUrl('klarna_checkout', [
  225.                 '_locale' => $request->getLocale(),
  226.                 'url_title' => $product->getUrlTitle(),
  227.                 'order_number' => $order->getOrderNumber(),
  228.                 'client_token' => $response['client_token']
  229.             ])]);
  230.         } else {
  231.             $this->session->remove('order');
  232.             $this->session->set('orderFailed'true);
  233.             $this->orderManager->updateOrderPaymentWithResponse($order, ['status' => Order::STATUS_FAILED]);
  234.             return $this->json(['redirectUrl' => $this->generateUrlWithParams('product_page', [
  235.                 '_locale' => $request->getLocale(),
  236.                 'urlTitle' => $product->getUrlTitle()
  237.             ],UrlGeneratorInterface::ABSOLUTE_PATH$request)]);
  238.         }
  239.     }
  240.     private function renderCheckoutPage(Request $requestbool $isStepTwo$product$productVariant$form$upsells)
  241.     {
  242.         $locale substr($request->headers->get('accept-language''en'), 02);
  243.         $orderFailed $this->session->has('orderFailed') ? $this->session->get('orderFailed') : false;
  244.         $this->session->remove('orderFailed');
  245.         foreach ($product->getUpsells() as $upsell) {
  246.             $upsell->setDescription($this->replacerTextManager->replaceText(
  247.                 ['product' => $upsell],
  248.                 $upsell->getDescription())
  249.             );
  250.         }
  251.         return $this->render(sprintf('App/checkout/step%s.html.twig', ($isStepTwo '2' '1')), [
  252.             'product' => $product,
  253.             'productVariant' => $productVariant,
  254.             'form' => $form->createView(),
  255.             'shippingCosts' => $this->orderManager->getProductShippingCosts($product$productVariant->getId(), $productVariant->getTotalPrice()),
  256.             'orderFailed' => $orderFailed,
  257.             'upsells' => $upsells,
  258.             'browserLocale' => $locale,
  259.             'hasVoucher' => $this->hasVoucher($product$upsells),
  260.             'isMobile' => (new MobileDetect())->isMobile()
  261.         ]);
  262.     }
  263.     private function hasVoucher(Product $product, ?array $upsells = []): bool
  264.     {
  265.         $hasVoucher false;
  266.         if ($product->getProductDetail()->isVoucher()) {
  267.             $hasVoucher true;
  268.         }
  269.         foreach ($upsells as $upsell) {
  270.             $productUpsell $this->productManager->findProductById($upsell['productId']);
  271.             if ($productUpsell && $productUpsell->getProductDetail()->isVoucher()) {
  272.                 $hasVoucher true;
  273.             }
  274.         }
  275.         return $hasVoucher;
  276.     }
  277. //    /**
  278. //     * @Route("/{_locale}/checkout/{url_title}", name="checkout_step3")
  279. //     */
  280. //    public function checkoutPageStepThree(Request $request, $url_title): Response
  281. //    {
  282. //        $product = $this->productManager->getProduct($url_title, $request->server->get('HTTP_HOST'));
  283. //
  284. //        return $this->render('App/checkout/step3.html.twig', [
  285. //            'product' => $product
  286. //        ]);
  287. //    }
  288.     /**
  289.      * @Route("/{_locale}/thank-you/{order_id}", name="thank_you_page")
  290.      * @param Request $request
  291.      * @param $order_id
  292.      * @return Response
  293.      */
  294.     public function thankYou(Request $request$order_id): Response
  295.     {
  296.         $order $this->orderManager->getOrderById(base64_decode($order_id));
  297.         if (!$order) {
  298.             throw new NotFoundHttpException('Order not found');
  299.         }
  300.         $product $order->getFirstProduct();
  301.         $product->setActiveDomain($order->getDomain());
  302.         $defaultResponse $this->render('App/checkout/pending_page.html.twig', [
  303.             'product' => $product,
  304.             'order' => $order
  305.         ]);
  306.         if ($request->query->has('status')) {
  307.             $this->session->set('refreshEventID'true);
  308.             switch ($request->query->get('status')) {
  309.                 case Order::STATUS_PENDING:
  310.                     if ($order->getPaymentStatus() !== Order::STATUS_PENDING ) {
  311.                         break;
  312.                     }
  313.                     $response $this->renderSuccessPage($request$order$product);
  314.                     break;
  315.                 case OrderHelper::isSuccessfulOrder($order):
  316.                     if ($order->getPaymentStatus() !== Order::STATUS_PAID && $order->getPaymentStatus() !== Order::STATUS_IN_PROCESS) {
  317.                         break;
  318.                     }
  319.                     $response $this->renderSuccessPage($request$order$product);
  320.                     break;
  321.                 case Order::STATUS_FAILED:
  322.                     if ($order->getParent()) {
  323.                         $order $order->getParent();
  324.                         $product $this->orderManager->getMainProduct($order);
  325.                         $product->setActiveDomain($order->getDomain());
  326.                     }
  327.                     $product->setErrorPage($this->replacerTextManager->replaceText(
  328.                         ['order' => $order],
  329.                         $product->getErrorPage()
  330.                     ));
  331.                     $response $this->render('App/checkout/error_page.html.twig', [
  332.                         'order' => $order,
  333.                         'product' => $product
  334.                     ]);
  335.                     break;
  336.                 default:
  337.                     $response $defaultResponse;
  338.                     break;
  339.             }
  340.         }
  341.         return $response ?? $defaultResponse;
  342.     }
  343.     private function renderSuccessPage($requestOrder $orderProduct $product)
  344.     {
  345.         if ($this->upsellCheckoutManager->isNeedRenderCheckout($request$order)) {
  346.             return $this->redirectToRouteWithParams('upsell_checkout_page',
  347.                 [
  348.                     '_locale' => $order->getUserSnapshot()->getLocale(),
  349.                     'url_title' => $product->getUrlTitle(),
  350.                     'order_id' => base64_encode($order->getId())
  351.                 ],
  352.             );
  353.         }
  354.         $postUpsellCheckoutUrl $this->productPostUpsellManager->processPostUpsellCheckout($order);
  355.         if ($postUpsellCheckoutUrl && !$request->query->has('skip')) {
  356.             return $this->redirect($postUpsellCheckoutUrl);
  357.         } else {
  358.             if ($order->getParent()) {
  359.                 $order $order->getParent();
  360.                 $product $this->orderManager->getMainProduct($order);
  361.                 $product->setActiveDomain($order->getDomain());
  362.             }
  363.         }
  364.         $product->setImagePath($this->productManager->getMainProductImageByOrder($order));
  365.         $product->setThanksPage($this->replacerTextManager->replaceText(
  366.             [
  367.                 'order' => $order,
  368.                 'product' => $product
  369.             ],
  370.             $product->getThanksPage())
  371.         );
  372.         $this->funnelVisitorManager->internalTrack(
  373.             FunnelVisitor::INTERNAL_PAGE_THANK_YOU,
  374.             $request,
  375.             $product,
  376.             true
  377.         );
  378.         return $this->render('App/checkout/success_page.html.twig', [
  379.             'order' => $order,
  380.             'product' => $product,
  381.             'custom_code' => $this->showTrackerCustomerCode($request$order),
  382.             'lastPaidOrder' => $this->orderManager->getLastPaidOrderByUser($order->getEndUser())
  383.         ]);
  384.     }
  385.     /**
  386.      * @Route("/{_locale}/cart/add", name="add_cart", condition="request.isXmlHttpRequest()")
  387.      * @param Request $request
  388.      * @return Response
  389.      */
  390.     public function addToCart(Request $request): Response
  391.     {
  392.         $productId $request->get('productId');
  393.         $quantity $request->get('quantity');
  394.         $product $this->productManager->findProductById($productId);
  395.         return $this->render('App/checkout/partials/cart_add.html.twig', [
  396.             'product' => $product,
  397.             'quantity' => $quantity
  398.         ]);
  399.     }
  400.     /**
  401.      * @Route("{_locale}/cart/shipping", name="calculate_shipping", condition="request.isXmlHttpRequest()")
  402.      * @param Request $request
  403.      * @return Response
  404.      */
  405.     public function ajaxCalculateShipping(Request $request): Response
  406.     {
  407.         $productId $request->get('productId');
  408.         $price $request->get('price');
  409.         $variantId $request->get('variantId');
  410.         $product $this->productManager->findProductById($productId);
  411.         return $this->render('App/checkout/partials/shipping_cost.html.twig', [
  412.             'product' => $product,
  413.             'shippingCosts' => $this->orderManager->getProductShippingCosts($product$variantId$price),
  414.             'variantId' => $variantId
  415.         ]);
  416.     }
  417.     public function checkOrderReminder(Request $requestOrder $orderstring $urlTitle): void
  418.     {
  419.         if (!$request->query->has('order')) {
  420.             return;
  421.         }
  422.         $hash $request->query->get('order');
  423.         $orderReminder $this->orderReminderManager->findByHash($hash);
  424.         if ($orderReminder) {
  425.             $endUser $this->endUserManager->findUserByEmail($orderReminder->getEmail());
  426.             if (!$endUser) {
  427.                 $endUser = new EndUser();
  428.                 $endUser->setEmail($orderReminder->getEmail());
  429.                 $endUser->setFirstName($orderReminder->getFirstName());
  430.             }
  431.             $order->setEndUser($endUser);
  432.             $order->setTermsAndConditions(true);
  433.             if ($orderReminder->getProductVariant()) {
  434.                 $this->session->set('variantId'$orderReminder->getProductVariant()->getId());
  435.             }
  436.             $this->session->set('order', [$urlTitle => $order]);
  437.             $this->session->set('orderReminder'$orderReminder);
  438.         }
  439.     }
  440.     /**
  441.      * @Route("{_locale}/cart/changeCountry", name="change_country")
  442.      * @param Request $request
  443.      * @return Response
  444.      */
  445.     public function ajaxChangeCountry(Request $request): Response
  446.     {
  447.         $productId $request->get('productId');
  448.         $countryId $request->get('countryId');
  449.         $orderType $request->get('type');
  450.         $hasVoucher = (bool)$request->get('hasVoucher');
  451.         $paymentMethods $this->orderManager->getPaymentMethodsOnStepTwo($productId$countryId$orderType$hasVoucher);
  452.         return $this->render('App/checkout/partials/payment_methods.html.twig', [
  453.             'paymentMethods' => $paymentMethods,
  454.         ]);
  455.     }
  456.     /**
  457.      * @Route("/{_locale}/product/{url_title}/{order_id}/{position}", name="post_upsell_page")
  458.      */
  459.     public function postUpsellPage(Request $request$url_title$order_id$position): Response
  460.     {
  461.         $parentOrder $this->orderManager->getOrderById(base64_decode($order_id));
  462.         $mainProduct $this->productManager->getProduct($url_title$request->server->get('HTTP_HOST'));
  463.         $postUpsell $this->productPostUpsellManager
  464.             ->getProductPostUpsellByProductAndPosition($mainProduct$position);
  465.         $orderHold $this->orderHolderManager->getByOrder($parentOrder);
  466.         if (!$postUpsell || !$parentOrder || is_null($postUpsell->getProductPostUpsell()) || ($orderHold && $orderHold->isSent())) {
  467.             return $this->redirectToRouteWithParams('product_page', [
  468.                 '_locale' => $request->getLocale(),
  469.                 'urlTitle' => $url_title
  470.             ],
  471.             302,
  472.             $request);
  473.         }
  474.         $productPostUpsell $this->productManager
  475.             ->getProduct($postUpsell->getProductPostUpsell()->getUrlTitle(), $request->server->get('HTTP_HOST'), true);
  476.         $form $this->createForm(PostUpsellOrderType::class, null, [
  477.             'action' => $this->generateUrlWithParams('post_upsell_page', [
  478.                 'url_title' => $url_title,
  479.                 'order_id' => $order_id,
  480.                 'position' => $position
  481.             ],UrlGeneratorInterface::ABSOLUTE_PATH$request),
  482.             'order' => $parentOrder,
  483.             'method' => 'POST'
  484.         ]);
  485.         $form->handleRequest($request);
  486.         $existOrder $this->orderManager
  487.             ->getOrderByOrderNumber(sprintf('%s_%s'$parentOrder->getOrderNumber(), $position));
  488.         if ($existOrder) {
  489.             return $this->redirectToRouteWithParams('thank_you_page', [
  490.                 '_locale' => $request->getLocale(),
  491.                 'order_id' => base64_encode($existOrder->getId())
  492.             ],
  493.             302,
  494.             $request
  495.             );
  496.         }
  497.         if ($form->isSubmitted() && $form->isValid()) {
  498.             $order = new Order();
  499.             $formData $form->getData();
  500.             $productVariant $this->productManager->getProductVariant($productPostUpsell$formData['variantId']);
  501.             $order
  502.                 ->setEndUser($parentOrder->getEndUser())
  503.                 ->setTermsAndConditions(true)
  504.                 ->setPaymentMethod([
  505.                     'id' => $parentOrder->getPaymentMethod(),
  506.                     'provider' => $parentOrder->getPaymentProvider()->getName()
  507.                 ])
  508.                 ->setParent($parentOrder)
  509.                 ->setType(Order::TYPE_ONE_OFF)
  510.                 ->setEventAdditionalParams($parentOrder->getEventAdditionalParams())
  511.                 ->setEventId($parentOrder->getEventId());
  512.             if ($parentOrder->getTracker()) {
  513.                 $order->setTracker($parentOrder->getTracker());
  514.                 if ($parentOrder->getTrackingParams()) {
  515.                     $order->setTrackingParams($parentOrder->getTrackingParams());
  516.                 }
  517.             }
  518.             $order->setFunnel($this->funnelVisitorManager->detectCheckoutFunnel($request$productPostUpsell));
  519.             $order->setIp($request->getClientIp());
  520.             if ($this->orderManager->saveOrder($order$productPostUpsell$productVariant)) {
  521.                 $response $this->orderManager->processPayment($order);
  522.                 if (isset($response['redirectUrl'])) {
  523.                     $this->orderManager->updateOrderPaymentWithResponse($order$response);
  524.                     return $this->json(['redirectUrl' => $response['redirectUrl']]);
  525.                 } else {
  526.                     $this->session->remove('order');
  527.                     $this->session->set('orderFailed'true);
  528.                     $this->orderManager->updateOrderPaymentWithResponse($order, ['status' => Order::STATUS_FAILED]);
  529.                     return $this->json(['redirectUrl' => $this->generateUrlWithParams('product_page', [
  530.                             '_locale' => $request->getLocale(),
  531.                             'urlTitle' => $mainProduct->getUrlTitle()
  532.                         ],UrlGeneratorInterface::ABSOLUTE_PATH$request)
  533.                     ]);
  534.                 }
  535.             }
  536.         }
  537.         $locale substr($request->headers->get('accept-language''en'), 02);
  538.         $this->funnelVisitorManager->internalTrack(
  539.             sprintf(FunnelVisitor::INTERNAL_PAGE_POST_UPSELL$position),
  540.             $request,
  541.             $productPostUpsell
  542.         );
  543.         return $this->render('App/checkout/post_upsell.html.twig', [
  544.             'product' => $productPostUpsell,
  545.             'shippingCosts' => $this->orderManager->getProductShippingCosts($productPostUpsell),
  546.             'form' => $form->createView(),
  547.             'productInfo' => $postUpsell->getProductInfo(),
  548.             'skipUrl' => $this->productPostUpsellManager->getNextPosition($parentOrder$postUpsell),
  549.             'browserLocale' => $locale,
  550.             'mainProduct' => $mainProduct,
  551.             'position' => $position,
  552.             'custom_code' => $position == 1
  553.                 $this->showTrackerCustomerCode($request$parentOrder)
  554.                 : [],
  555.             'lastPaidOrder' => $this->orderManager->getLastPaidOrderByUser($parentOrder->getEndUser())
  556.         ]);
  557.     }
  558.     /**
  559.      * @Route("/{_locale}/upsell-checkout/{url_title}/{order_id}", name="upsell_checkout_page")
  560.      */
  561.     public function upsellCheckoutPage(Request $request$url_title$order_id): Response
  562.     {
  563.         $parentOrder $this->orderManager->getOrderById(base64_decode($order_id));
  564.         $mainProduct $this->productManager->getProduct($url_title$request->server->get('HTTP_HOST'));
  565.         $upsells $this->upsellCheckoutManager->upsellsForCheckout($mainProduct$parentOrder);
  566.         $cartKey OrderHelper::cartKey($mainProductApiCheckoutController::SESSION_UPSELL_PAGE_KEY);
  567.         $choosedUpsells $this->session->has($cartKey) ? $this->session->get($cartKey) : [];
  568.         $skipUrl $this->generateUrlWithParams('thank_you_page', [
  569.             '_locale' => $request->getLocale(),
  570.             'order_id' => $order_id,
  571.             UpsellCheckoutManager::SKIP_PARAM => 'true'
  572.         ],
  573.             UrlGeneratorInterface::ABSOLUTE_PATH,
  574.             $request,
  575.         );
  576.         $form $this->createForm(PostUpsellOrderType::class, null, [
  577.             'action' => $this->generateUrlWithParams('upsell_checkout_page', [
  578.                 'url_title' => $url_title,
  579.                 'order_id' => $order_id,
  580.             ],UrlGeneratorInterface::ABSOLUTE_PATH$request),
  581.             'order' => $parentOrder,
  582.             'method' => 'POST'
  583.         ]);
  584.         $form->handleRequest($request);
  585.         $existOrder $this->orderManager
  586.             ->getOrderByOrderNumber(sprintf('%s_%s'$parentOrder->getOrderNumber(), 0));
  587.         if ($existOrder) {
  588.             return $this->redirectToRouteWithParams('thank_you_page', [
  589.                 '_locale' => $request->getLocale(),
  590.                 'order_id' => base64_encode($existOrder->getId())
  591.             ],
  592.                 302,
  593.                 $request
  594.             );
  595.         }
  596.         if ($form->isSubmitted() && $form->isValid()) {
  597.             $order = new Order();
  598.             $formData $form->getData();
  599.             $order
  600.                 ->setEndUser($parentOrder->getEndUser())
  601.                 ->setTermsAndConditions(true)
  602.                 ->setPaymentMethod([
  603.                     'id' => $parentOrder->getPaymentMethod(),
  604.                     'provider' => $parentOrder->getPaymentProvider()->getName()
  605.                 ])
  606.                 ->setParent($parentOrder)
  607.                 ->setType(Order::TYPE_ONE_OFF)
  608.                 ->setIp($request->getClientIp())
  609.                 ->setEventAdditionalParams($parentOrder->getEventAdditionalParams())
  610.                 ->setEventId($parentOrder->getEventId());
  611.             if ($parentOrder->getTracker()) {
  612.                 $order->setTracker($parentOrder->getTracker());
  613.                 if ($parentOrder->getTrackingParams()) {
  614.                     $order->setTrackingParams($parentOrder->getTrackingParams());
  615.                 }
  616.             }
  617.             $order->setFunnel($parentOrder->getFunnel())
  618.                 ->setDomainVat($parentOrder->getDomainVat())
  619.                 ->setCurrency($parentOrder->getCurrency())
  620.                 ->setDomain($parentOrder->getDomain())
  621.                 ->setWarehouse($parentOrder->getWarehouse())
  622.                 ->setShippingProvider($parentOrder->getShippingProvider());
  623.             $discountPercentage $mainProduct->getUpsellPageDiscountPercentage() && $mainProduct->getUpsellPageDiscountPercentage() > && $parentOrder->isFirstOrder()
  624.                 ? $mainProduct->getUpsellPageDiscountPercentage()
  625.                 : null;
  626.             if ($this->orderManager->saveUpsellOrder($order$choosedUpsells$discountPercentage)) {
  627.                 $response $this->orderManager->processPayment($order);
  628.                 $this->session->remove($cartKey);
  629.                 if (isset($response['redirectUrl'])) {
  630.                     $this->orderManager->updateOrderPaymentWithResponse($order$response);
  631.                     return $this->json(['redirectUrl' => $response['redirectUrl']]);
  632.                 } else {
  633.                     $this->session->remove('order');
  634.                     $this->session->set('orderFailed'true);
  635.                     $this->orderManager->updateOrderPaymentWithResponse($order, ['status' => Order::STATUS_FAILED]);
  636.                     return $this->json(['redirectUrl' => $this->generateUrlWithParams('product_page', [
  637.                         '_locale' => $request->getLocale(),
  638.                         'urlTitle' => $mainProduct->getUrlTitle()
  639.                     ],UrlGeneratorInterface::ABSOLUTE_PATH$request)
  640.                     ]);
  641.                 }
  642.             }
  643.         }
  644. //
  645.         $locale substr($request->headers->get('accept-language''en'), 02);
  646.         $mainProduct->clearUpsells();
  647.         $discountPercentage $mainProduct->getUpsellPageDiscountPercentage() && $mainProduct->getUpsellPageDiscountPercentage() > 0  && $parentOrder->isFirstOrder()
  648.             ? $mainProduct->getUpsellPageDiscountPercentage()
  649.             : null;
  650.         foreach ($upsells as $upsell) {
  651.             if ($discountPercentage) {
  652.                 $productVariant $upsell->getVariants()->first();
  653.                 $totalPrice $productVariant->getTotalPrice();
  654.                 $discountAmount = ($totalPrice $discountPercentage) / 100;
  655.                 $discountedPrice round($totalPrice $discountAmount2);
  656.                 $productVariant->setTotalPrice($discountedPrice)
  657.                     ->setUnitPrice($discountedPrice);
  658.             }
  659.             $mainProduct->addUpsell($upsell);
  660.         }
  661.         return $this->render('App/checkout/upsell_checkout_page.html.twig', [
  662.             'product' => $mainProduct,
  663.             'choosedUpsells' => $choosedUpsells,
  664. //            'shippingCosts' => $this->orderManager->getProductShippingCosts($productPostUpsell),
  665.             'form' => $form->createView(),
  666. //            'productInfo' => $postUpsell->getProductInfo(),
  667.             'browserLocale' => $locale,
  668.             'mainProduct' => $mainProduct,
  669.             'skipUrl' => $skipUrl,
  670.             'lastPaidOrder' => $this->orderManager->getLastPaidOrderByUser($parentOrder->getEndUser()),
  671.             'discountPercentage' => $discountPercentage,
  672.             'isFirstOrder' => $parentOrder->isFirstOrder() ? "1" "0",
  673.         ]);
  674.     }
  675.     private function showTrackerCustomerCode($request$order)
  676.     {
  677.         $pageKey md5('purchase-' $order->getOrderNumber());
  678.         $tracker $order->getTracker();
  679.         return [
  680.             'show' => !$request->cookies->has($pageKey),
  681.             'content' => $tracker && $tracker->getThankYouPageCustomCode()
  682.                 ? $tracker->getThankYouPageCustomCode()
  683.                 : null,
  684.             'page_key' => $pageKey
  685.         ];
  686.     }
  687.     private function defineCountry(Request $request)
  688.     {
  689.         $filePath '/var/www/ADMIN/GeoIP/GeoLite2-Country.mmdb';
  690.         if (file_exists($filePath)) {
  691.             $reader = new Reader($filePath);
  692.             $ip $request->server->get('REMOTE_ADDR');
  693.             try {
  694.                 $country $reader->country($ip);
  695.                 $countryCode $country->country->isoCode;
  696.                 $this->session->set('country_code'$countryCode);
  697.             } catch (\Exception $exception) {
  698.                 $this->session->set('country_code''NL');
  699.             }
  700.         } else {
  701.             $this->session->set('country_code''NL');
  702.         }
  703.     }
  704.     private function initiateCart(Product $product$upsells): void
  705.     {
  706.         $sessionUpsells = [];
  707.         $sessionKey OrderHelper::cartKey($productApiCheckoutController::SESSION_UPSELL_KEY);
  708.         /**
  709.          * @var Product $upsell
  710.          */
  711.         if (!$this->session->has($sessionKey)) {
  712.             foreach ($upsells as $upsell) {
  713.                 if (!$upsell->getProductDetail()->isOutOfStock() && $upsell->isAutoCartAdd()) {
  714.                     $sessionUpsells[$upsell->getId()] = [
  715.                         'productId' => $upsell->getId(),
  716.                         'quantity' => 1
  717.                     ];
  718.                 }
  719.             }
  720.             if (!empty($sessionUpsells)) {
  721.                 $this->session->set($sessionKey$sessionUpsells);
  722.             }
  723.         }
  724.     }
  725. }