src/Controller/TourOperator/ProfileController.php line 544

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by Elements.at New Media Solutions GmbH
  4.  *
  5.  */
  6. namespace App\Controller\TourOperator;
  7. use App\Ecommerce\OrderManager\CancellationMethodEnum;
  8. use App\Ecommerce\OrderManager\CancellationRefundHandler;
  9. use App\Model\DataObject\TourOperatorUser;
  10. use App\Model\Shop\Cancel\Result;
  11. use App\Model\Shop\Event\EventProduct;
  12. use App\Model\Shop\Merchandise\MerchandiseProduct;
  13. use App\Model\Shop\Order;
  14. use App\Model\Shop\OrderItem;
  15. use App\Model\Shop\Ticket\TicketProduct;
  16. use App\Model\Type\TenantType;
  17. use App\Order\SalesReport\Exporter\Excel;
  18. use App\Order\SalesReport\SalesReport;
  19. use App\Service\B2B\ShopService;
  20. use App\Service\BackOffice\OrderNoteListService;
  21. use App\Service\BackOffice\SalesListService;
  22. use App\Service\CDMUserManagerService;
  23. use App\Service\Profile\ProfileOrdersService;
  24. use App\Service\Shop\MailService;
  25. use Carbon\Carbon;
  26. use Elements\Bundle\TicketShopFrameworkBundle\Service\CartService;
  27. use Knp\Component\Pager\PaginatorInterface;
  28. use Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\OrderListInterface;
  29. use Pimcore\Model\DataObject\AbstractObject;
  30. use Pimcore\Model\DataObject\Concrete;
  31. use Symfony\Component\HttpFoundation\Request;
  32. use Symfony\Component\HttpFoundation\Response;
  33. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  34. use Symfony\Component\Routing\Annotation\Route;
  35. use Symfony\Contracts\Translation\TranslatorInterface;
  36. use Twig\Environment;
  37. /**
  38.  * @Route("/{_locale}", name="tour-operator_")
  39.  *
  40.  * @package App\Controller\TourOperator
  41.  */
  42. class ProfileController extends AbstractTourOperatorController
  43. {
  44.     public function __construct(
  45.         CartService $cartService,
  46.         Environment $twig,
  47.         private MailService $mailService,
  48.         private TranslatorInterface $translator
  49.     ) {
  50.         parent::__construct($cartService$twig);
  51.     }
  52.     /**
  53.      * @Route( "/hub", name="hub")
  54.      */
  55.     public function hubAction(Request $request): Response
  56.     {
  57.         $this->denyAccessUnlessGranted('ROLE_USER');
  58.         return $this->render('tour-operator/profile/hub.html.twig');
  59.     }
  60.     /**
  61.      * @Route( "/data", name="data")
  62.      */
  63.     public function dataAction(Request $request): Response
  64.     {
  65.         $this->denyAccessUnlessGranted('ROLE_USER');
  66.         /** @var TourOperatorUser $user */
  67.         $user $this->getUser();
  68.         if ($request->getMethod() == 'POST') {
  69.             $params $request->request->all();
  70.             $user->setName($params['name']);
  71.             $user->setPhone($params['phone']);
  72.             $user->setStreet($params['street']);
  73.             $user->setCountry($params['country']);
  74.             $user->setCity($params['city']);
  75.             $user->setZip($params['zip']);
  76.             $user->setPreferredPaymentMethod($params['payment-method']);
  77.             try {
  78.                 $user->save();
  79.                 $this->addFlash('success'$this->translator->trans('tour-operator.data-save-success'));
  80.             } catch (\Exception $e) {
  81.                 $this->addFlash('error'$this->translator->trans('tour-operator.data-save-error.' $e->getMessage()));
  82.             }
  83.         }
  84.         return $this->render('tour-operator/profile/data.html.twig', [
  85.             'paymentMethods' => $user->getAllowedPaymentMethods(),
  86.         ]);
  87.     }
  88.     /**
  89.      * @Route( "/password", name="password")
  90.      */
  91.     public function passwordAction(Request $request): Response
  92.     {
  93.         $this->denyAccessUnlessGranted('ROLE_USER');
  94.         return $this->render('tour-operator/profile/password.html.twig');
  95.     }
  96.     /**
  97.      * @Route("/password-change", name="change_password")
  98.      */
  99.     public function passwordChangeAction(Request $requestCDMUserManagerService $userManagerService): Response
  100.     {
  101.         $this->denyAccessUnlessGranted('ROLE_USER');
  102.         /** @var TourOperatorUser $user */
  103.         $user $this->getUser();
  104.         if ($request->getMethod() == 'POST' && $request->get('pwold')) {
  105.             $success false;
  106.             $errors = [];
  107.             $returnData $userManagerService->handleChangePasswordPreRequest($request);
  108.             if (empty($returnData['errors'])) {
  109.                 $pwClassDef $user->getClass()->getFieldDefinition('password');
  110.                 /** @phpstan-ignore-next-line */
  111.                 if ($user->getPassword() == '' || password_verify($request->get('pwold'), $user->getPassword()) || $pwClassDef->calculateHash($request->get('pwold')) == $user->getPassword()) {
  112.                     $user->setPassword($request->get('pwnew'));
  113.                     $user->setPasswordChangeDate(Carbon::now());
  114.                     try {
  115.                         $user->save();
  116.                         $success true;
  117.                     } catch (\Exception $e) {
  118.                         $errors[] = $e->getMessage();
  119.                     }
  120.                 } else {
  121.                     $errors[] = 'old password is incorrect';
  122.                 }
  123.             } else {
  124.                 $errors $returnData['errors'];
  125.             }
  126.             if ($request->get('profileUrl')) {
  127.                 if (!empty($errors)) {
  128.                     foreach ($errors as $error) {
  129.                         $this->addFlash('error'$this->translator->trans('tour-operator.' $error));
  130.                     }
  131.                 } else {
  132.                     $this->addFlash('success'$this->translator->trans('tour-operator.password-change-success'));
  133.                 }
  134.                 return $this->redirectToRoute('tour-operator_password');
  135.             } else {
  136.                 $template $this->renderTemplate('@ElementsCDMUserManager/UserManager/partials/edit-password-box.html.twig', [
  137.                     'customer' => $user,
  138.                     'errors' => $errors,
  139.                     'success' => $success,
  140.                     'pwChangeUrl' => $this->generateUrl('tour-operator_change_password'),
  141.                 ]);
  142.                 return $this->json(['success' => true'html' => $template->getContent()]);
  143.             }
  144.         }
  145.         $template $this->renderTemplate('@ElementsCDMUserManager/Includes/overlays/edit-password-content.html.twig', [
  146.             'customer' => $user,
  147.             'editPasswordModalUrl' => $this->generateUrl('tour-operator_change_password'),
  148.         ]);
  149.         return $this->json(['success' => true'html' => $template->getContent()]);
  150.     }
  151.     /**
  152.      * @Route("/orders", name="orders")
  153.      */
  154.     public function ordersAction(
  155.         Request $request,
  156.         ProfileOrdersService $profileOrdersService,
  157.         PaginatorInterface $paginator
  158.     ): Response {
  159.         $this->denyAccessUnlessGranted('ROLE_USER');
  160.         AbstractObject::setHideUnpublished(false);
  161.         /** @var TourOperatorUser $customer */
  162.         $customer $this->getUser();
  163.         $returnArray = [];
  164.         $ordersTotalPrice 0;
  165.         $ordersCancelledTotalPrice 0;
  166.         $productOptions = [];
  167.         //orders
  168.         $orderList $profileOrdersService->getOrders($customer$request);
  169.         $orderItemList $profileOrdersService->getOrderItemsPriceList($customer$request);
  170.         $cancelledOrderItemList $profileOrdersService->getOrderItemsPriceList($customer$requesttrue);
  171.         /** @var Order $order */
  172.         foreach ($orderItemList as $order) {
  173.             $ordersTotalPrice += $order->getTotalPrice();
  174.         }
  175.         /** @var Order $cancelledOrder */
  176.         foreach ($cancelledOrderItemList as $cancelledOrder) {
  177.             $ordersCancelledTotalPrice += $cancelledOrder->getTotalPrice();
  178.         }
  179.         //min and max date
  180.         if ($minMaxOrderDates $profileOrdersService->getMinMaxDateOrders($customer->getId())) {
  181.             $returnArray array_merge($returnArray$minMaxOrderDates);
  182.         }
  183.         $orderItemDataList $profileOrdersService->getOrderProducts($customer);
  184.         //product options
  185.         if ($orderItemDataList->current()) {
  186.             $productOptions[][] = [
  187.                 'label' => $this->translator->trans('tour-operator.orders.choose-product'),
  188.                 'value' => '',
  189.                 'disabled' => false,
  190.                 'selected' => true,
  191.             ];
  192.             $catalogOptions = [];
  193.             $ticketOptions = [];
  194.             $eventOptions = [];
  195.             foreach ($orderItemDataList as $orderListItem) {
  196.                 /** @var TicketProduct|EventProduct|MerchandiseProduct $product */
  197.                 /** @phpstan-ignore-next-line  */
  198.                 $product AbstractObject::getById($orderListItem->getProductId());
  199.                 if ($product instanceof TicketProduct) {
  200.                     if ($catalog $product->getCatalogObject()) {
  201.                         $catalogOptions[] = [
  202.                             'label' => $catalog->getOSName(),
  203.                             'value' => $catalog->getId(),
  204.                             'selected' => $request->get('product') == $catalog->getId(),
  205.                         ];
  206.                     } else {
  207.                         $parentProduct $product->getReference();
  208.                         $ticketOptions[] = [
  209.                             'label' => $parentProduct->getOSName(),
  210.                             'value' => $parentProduct->getId(),
  211.                             'selected' => $request->get('product') == $parentProduct->getId(),
  212.                         ];
  213.                     }
  214.                 } else {
  215.                     /** @var EventProduct|MerchandiseProduct $parentProduct */
  216.                     $parentProduct $product->getReference();
  217.                     $eventOptions[] = [
  218.                         'label' => $parentProduct->getOSName(),
  219.                         'value' => $parentProduct->getId(),
  220.                         'selected' => $request->get('product') == $parentProduct->getId(),
  221.                     ];
  222.                 }
  223.             }
  224.             $this->sortOptions($catalogOptions);
  225.             $this->sortOptions($ticketOptions);
  226.             $this->sortOptions($eventOptions);
  227.             $productOptions['catalog'] = $catalogOptions;
  228.             $productOptions['ticket'] = $ticketOptions;
  229.             $productOptions['event'] = $eventOptions;
  230.         }
  231.         $productOptions array_filter($productOptions);
  232.         $returnArray['ordersTotalPrice'] = $ordersTotalPrice;
  233.         $returnArray['ordersCancelledTotalPrice'] = $ordersCancelledTotalPrice;
  234.         $returnArray['productOptions'] = $productOptions;
  235.         $returnArray['paginator'] = $paginator->paginate($orderList, (int)$request->get('page'1), 20);
  236.         if ($request->isMethod('POST') || $request->isXmlHttpRequest()) {
  237.             $template $this->renderTemplate('tour-operator/includes/profile/order-result.html.twig'$returnArray);
  238.             return $this->json(['success' => true'html' => $template->getContent()]);
  239.         }
  240.         return $this->render('tour-operator/profile/orders.html.twig'$returnArray);
  241.     }
  242.     /**
  243.      * @param array<mixed >$array
  244.      *
  245.      * @return void
  246.      */
  247.     private function sortOptions(array &$array): void
  248.     {
  249.         $array array_unique($arraySORT_REGULAR);
  250.         usort($array, function ($a$b) {
  251.             return $a['label'] <=> $b['label'];
  252.         });
  253.     }
  254.     /**
  255.      * @Route("/order/{id}", name="order_detail")
  256.      */
  257.     public function orderDetailAction(int $idOrderNoteListService $orderNoteService): Response
  258.     {
  259.         $this->denyAccessUnlessGranted('ROLE_USER');
  260.         AbstractObject::setHideUnpublished(false);
  261.         /** @var Order $order */
  262.         $order Order::getById($id);
  263.         $backofficeBrick $order->getOrCreateBackofficeBrick();
  264.         $notes $orderNoteService->getOrderNoteList($order, [
  265.             'order-confirmation-mail-sent',
  266.             'order-completion-mail-sent',
  267.             'order-finished',
  268.             'tour-operator-order-cancelled',
  269.         ]);
  270.         return $this->render('tour-operator/profile/order-detail.html.twig', [
  271.             'order' => $order,
  272.             'comment' => $backofficeBrick->getB2bComment(),
  273.             'notes' => $notes,
  274.         ]);
  275.     }
  276.     /**
  277.      * @Route("/order/comment/{id}", name="order_comment")
  278.      */
  279.     public function orderCommentAction(Request $requestint $id): Response
  280.     {
  281.         $this->denyAccessUnlessGranted('ROLE_USER');
  282.         $order Order::getById($id);
  283.         $backofficeBrick $order->getOrCreateBackofficeBrick();
  284.         $backofficeBrick->setB2bComment(htmlspecialchars(trim($request->get('comment'))));
  285.         $order->save(['versionNote' => 'Add tour-operator comment to order.']);
  286.         $template $this->renderTemplate('tour-operator/profile/comment-result.html.twig', [
  287.             'order' => $order,
  288.             'value' => $backofficeBrick->getB2bComment(),
  289.         ]);
  290.         return $this->json([
  291.             'success' => true,
  292.             'html' => $template->getContent(),
  293.         ]);
  294.     }
  295.     /**
  296.      * @Route( "/cancel/order/{order}", name="order_cancel" )
  297.      *
  298.      * @param Request $request
  299.      * @param Order $order
  300.      *
  301.      * @return Response
  302.      *
  303.      * @throws \Exception
  304.      */
  305.     public function cancelOrder(Request $requestOrder $order): Response
  306.     {
  307.         $this->denyAccessUnlessGranted('ROLE_USER');
  308.         // somehow the locale is overridden after the cancel
  309.         $locale $request->getLocale();
  310.         $form $this->createFormBuilder([])->getForm();
  311.         $form->handleRequest($request);
  312.         if ($form->isSubmitted()) {
  313.             $this->cancel($order$order->getCancelableItems(), true);
  314.             return $this->redirectToRoute('tour-operator_order_detail', ['id' => $order->getId(), '_locale' => $locale]);
  315.         }
  316.         $html $this->renderTemplate('shop/includes/cancel-modal.html.twig', [
  317.             'form' => $form->createView(),
  318.             'title' => 'tour-operator.cancel-full-order',
  319.             'url' => $this->generateUrl('tour-operator_order_cancel', ['order' => $order->getId()]),
  320.         ])->getContent();
  321.         return $this->json([
  322.             'success' => true,
  323.             'html' => $html,
  324.         ]);
  325.     }
  326.     /**
  327.      * @Route( "/cancel/order-item/{orderItem}", name="order_item_cancel")
  328.      *
  329.      * @param Request $request
  330.      * @param OrderItem $orderItem
  331.      *
  332.      * @return Response
  333.      *
  334.      * @throws \Exception
  335.      */
  336.     public function cancelOrderItem(Request $requestOrderItem $orderItem): Response
  337.     {
  338.         $this->denyAccessUnlessGranted('ROLE_USER');
  339.         // somehow the locale is overridden after the cancel
  340.         $locale $request->getLocale();
  341.         $form $this->createFormBuilder([])->getForm();
  342.         $form->handleRequest($request);
  343.         if ($form->isSubmitted()) {
  344.             $order $orderItem->getOrder();
  345.             $this->cancel($order, [$orderItem]);
  346.             return $this->redirectToRoute('tour-operator_order_detail', ['id' => $order->getId(), '_locale' => $locale]);
  347.         }
  348.         $html $this->renderTemplate('shop/includes/cancel-modal.html.twig', [
  349.             'form' => $form->createView(),
  350.             'title' => 'tour-operator.cancel-order-item',
  351.             'url' => $this->generateUrl('tour-operator_order_item_cancel', ['orderItem' => $orderItem->getId()]),
  352.         ])->getContent();
  353.         return $this->json([
  354.             'success' => true,
  355.             'html' => $html,
  356.         ]);
  357.     }
  358.     /**
  359.      * @param Order $order
  360.      * @param OrderItem[] $items
  361.      * @param bool $isWholeOrderCancelled
  362.      *
  363.      * @return void
  364.      *
  365.      * @throws \Exception
  366.      */
  367.     private function cancel(Order $order, array $itemsbool $isWholeOrderCancelled false): void
  368.     {
  369.         $cancelHandler = new CancellationRefundHandler($order);
  370.         $cancelHandler->setCancellationMethod(CancellationMethodEnum::REFUND);
  371.         $cancelHandler->setCancelledItemObjects($items);
  372.         $result $cancelHandler->executeCancellationAndRefund();
  373.         if ($result->getCancelStatus() == Result::SUCCESS) {
  374.             /** @var TourOperatorUser $user */
  375.             $user $this->getUser();
  376.             if ($isWholeOrderCancelled) {
  377.                 $order->addNote('tour-operator-order-cancelled''Order cancelled in profile''', [
  378.                     'tour-operator-user' => $user->getEmail(),
  379.                 ]);
  380.             } else {
  381.                 $order->addNote('tour-operator-order-cancelled''OrderItem cancelled in profile''', [
  382.                     'tour-operator-user' => $user->getEmail(),
  383.                     'oderItemId' => $items[0]->getId(),
  384.                 ]);
  385.             }
  386.             //user cancel-mail
  387.             $this->mailService->sendB2bEmails($orderMailService::B2B_MAIL_TYPE_ORDER_CANCEL$result->getCancelledItems());
  388.             $this->addFlash('success''tour-operator.cancel.success');
  389.             if ($result->getRefundStatus() == Result::SUCCESS) {
  390.                 $this->addFlash('success''tour-operator.refund.success');
  391.             } elseif ($result->getRefundStatus() == Result::FAILURE) {
  392.                 $this->addFlash('error''tour-operator.refund.error');
  393.             }
  394.         } else {
  395.             $this->addFlash('error''tour-operator.cancel.error-while-cancel');
  396.         }
  397.     }
  398.     /**
  399.      * @param Request $request
  400.      * @param SalesListService $salesListService
  401.      * @param ProfileOrdersService $profileOrdersService
  402.      *
  403.      * @return Response
  404.      *
  405.      * @Route("/export" , name="order_export")
  406.      */
  407.     public function exportAction(
  408.         Request $request,
  409.         SalesListService $salesListService,
  410.         ProfileOrdersService $profileOrdersService
  411.     ): Response {
  412.         /** @var TourOperatorUser $user */
  413.         $user $this->getUser();
  414.         $listOptions['filter_customerId'] = $user->getId();
  415.         $listOptions['filter_groups'] = ['product'];
  416.         if ($request->get('dateRangeFrom') && $request->get('dateRangeTo')) {
  417.             $from Carbon::parse($request->get('dateRangeFrom'));
  418.             $to Carbon::parse($request->get('dateRangeTo'));
  419.             $listOptions['filter_daterange'] = $from->format('d.m.Y') . ' - ' $to->format('d.m.Y');
  420.         }
  421.         if ($request->get('email')) {
  422.             $listOptions['filter_customerEmail'] = $request->get('email');
  423.         }
  424.         if ($request->get('product')) {
  425.             $product Concrete::getById((int)$request->get('product'));
  426.             $listOptions['filter_product'] = $profileOrdersService->getProductFilterIds($product);
  427.         }
  428.         if ($request->get('invoicenumber')) {
  429.             $listOptions['filter_ordernumber'] = $request->get('invoicenumber');
  430.         }
  431.         $objLists $salesListService->createSalesList(OrderListInterface::LIST_TYPE_ORDER_ITEM$listOptionsTenantType::TOUR_OPERATOR);
  432.         $report = new SalesReport($objListstrue$salesListService->getDateFrom(), $salesListService->getDateTo(), nulltrue);
  433.         $exportDir PIMCORE_PRIVATE_VAR '/tmp/export/accounting-list/';
  434.         \Pimcore\File::mkdir($exportDir);
  435.         $exportFile 'export_' $user->getId() . Carbon::now()->getTimestamp() . '.xlsx';
  436.         $exporter = new Excel($report$exportDir $exportFilenull$request->getLocale());
  437.         $exporter->export();
  438.         $response = new Response($exporter->getRawData());
  439.         $response->headers->set('Content-Type'$exporter->getMimeType());
  440.         $response->headers->set('Content-Length', (string)$exporter->getFilesize());
  441.         $response->setMaxAge(0);
  442.         $disposition $response->headers->makeDisposition(
  443.             ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  444.             sprintf('%s-sales-export.xlsx'Carbon::now()->format('YmdHis'))
  445.         );
  446.         $response->headers->set('Content-Disposition'$disposition);
  447.         $exporter->close();
  448.         return $response;
  449.     }
  450.     /**
  451.      * @Route( "/warnings", name="warnings")
  452.      */
  453.     public function warningsAction(Request $requestShopService $shopService): Response
  454.     {
  455.         $this->denyAccessUnlessGranted('ROLE_USER');
  456.         return $this->render('tour-operator/profile/warnings.html.twig');
  457.     }
  458. }