src/Controller/OrderController.php line 879

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Order;
  4. use App\Entity\Person;
  5. use App\Entity\Invoice;
  6. use App\Form\OrderType;
  7. use App\Entity\WaitItem;
  8. use App\Entity\OrderItem;
  9. use App\Service\UiService;
  10. use App\Form\OrderStatusType;
  11. use App\Service\OrderService;
  12. use Doctrine\DBAL\Connection;
  13. use App\Service\MailerService;
  14. use App\Entity\OrderItemPerson;
  15. use App\Service\InvoiceService;
  16. use App\Service\ZoomService;
  17. use App\Service\IbanService;
  18. use App\Entity\CourseOccurrence;
  19. use App\Form\OrderItemPersonCopy;
  20. use App\Repository\OrderRepository;
  21. use App\Repository\WaitItemRepository;
  22. use App\Service\EmailHistoryService;
  23. use App\Repository\PersonRepository;
  24. use App\Repository\InvoiceRepository;
  25. use App\Service\ConfigurationService;
  26. use App\Form\OrderItemPersonCancelDate;
  27. use App\Entity\CourseSubscriptionBooking;
  28. use Doctrine\Persistence\ManagerRegistry;
  29. use Doctrine\Common\Collections\Collection;
  30. use Psr\Log\LoggerInterface;
  31. use Symfony\Component\HttpFoundation\Request;
  32. use App\Repository\OrderItemPersonRepository;
  33. use App\Repository\CourseOccurrenceRepository;
  34. use Symfony\Component\HttpFoundation\Response;
  35. use Symfony\Component\Routing\Annotation\Route;
  36. use App\Repository\CourseOccurrenceTimeRepository;
  37. use Symfony\Component\HttpFoundation\RequestStack;
  38. use Menke\UserBundle\Controller\AbstractClientableController;
  39. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  40. use Menke\UserBundle\Entity\Client;
  41. use Symfony\Component\Validator\Constraints\Iban;
  42. /**
  43.  * @Route("/order")
  44.  * @IsGranted("ROLE_MANAGER")
  45.  */
  46. class OrderController extends AbstractClientableController
  47. {
  48.     const LISTING_LIMIT 25;
  49.     /**
  50.      * @Route("/", name="order_index", methods="GET")
  51.      */
  52.     public function index(
  53.         UiService $uiService,
  54.         OrderRepository $orderRepo,
  55.         OrderItemPersonRepository $orderItemPersonRepository,
  56.         Request $request,
  57.         RequestStack $requestStack
  58.     ): Response {
  59.         $order $uiService->getSortOrder('order-index-listing');
  60.         $em $this->getDoctrine()->getManager();
  61.         $filterOrders $request->get('orderAction');
  62.         if ($filterOrders) {
  63.             $requestStack->getSession()->set('orderFilter'$filterOrders);
  64.         } else {
  65.             $requestStack->getSession()->set('orderFilter''pending');
  66.         }
  67.         $dateareas $request->get('datearea');
  68.         if ($dateareas) {
  69.             $requestStack->getSession()->set('datearea'$dateareas);
  70.         }
  71. /*  Alle Member in den Orders und order item persons abgleichen und aktualisieren
  72.         $orderstest = $orderRepo->findAll();
  73.         foreach ($orderstest as $ordertest) {
  74.             if($ordertest->getCustomer() && $ordertest->getCustomer()->getMember()){
  75.             $ordertest->setCustomerMember($ordertest->getCustomer()->getMember());
  76.             $em->persist($ordertest);}
  77.         }
  78.         $entries = $orderItemPersonRepository->findAll();
  79.         foreach ($entries as $entry) {
  80.             // Hier wird der aktualisierte Member-Wert gesetzt
  81.             if($entry->getPerson() && $entry->getPerson()->getMember()){
  82.             $entry->setMember($entry->getPerson()->getMember());
  83.             $em->persist($entry);}
  84.         }
  85.   */     
  86.         $orders $orderRepo->getByClientPaged(
  87.             $this->getCurrentClient(),
  88.             self::LISTING_LIMIT,
  89.             $order['orderDirection'] ?? 'desc',
  90.             $order['orderBy'] ?? 'id',
  91.             1,
  92.             ($filterOrders) ? $filterOrders 'pending',
  93.             ($dateareas) ? $dateareas null,
  94.         );
  95.         return $this->render('order/index.html.twig', [
  96.             'uiService' => $uiService,
  97.             'orders' => $orders->getIterator(),
  98.             'total' => $orders->count(),
  99.             'pages' => ceil($orders->count() / self::LISTING_LIMIT),
  100.             'page' => 1,
  101.             'orderAction' => $request->get('orderAction'),
  102.             'datearea' => $request->get('datearea'),
  103.         ]);
  104.     }
  105.     /**
  106.      * @Route("/fast", name="order_index_fast", methods="GET")
  107.      */
  108.     public function indexfast(
  109.         UiService $uiService,
  110.         OrderRepository $orderRepo,
  111.         Request $request,
  112.         RequestStack $requestStack
  113.     ): Response {
  114.         $order $uiService->getSortOrder('order-index-listing');
  115.         $filterOrders $request->get('orderAction');
  116.         if ($filterOrders) {
  117.             $requestStack->getSession()->set('orderFilter'$filterOrders);
  118.         } else {
  119.             $requestStack->getSession()->set('orderFilter''pending');
  120.         }
  121.         $orders $orderRepo->getByClientPaged(
  122.             $this->getCurrentClient(),
  123.             self::LISTING_LIMIT,
  124.             $order['orderDirection'] ?? 'desc',
  125.             $order['orderBy'] ?? 'date',
  126.             1,
  127.             ($filterOrders) ? $filterOrders ''
  128.         );
  129.         return $this->render('order/fastindex.html.twig', [
  130.             'uiService' => $uiService,
  131.             'orders' => $orders->getIterator(),
  132.             'total' => $orders->count(),
  133.             'pages' => ceil($orders->count() / self::LISTING_LIMIT),
  134.             'page' => 1,
  135.             'orderAction' => $request->get('orderAction'),
  136.         ]);
  137.     }
  138.     /**
  139.      * @Route("/{page}/{orderby}/{order}", name="order_index_listing", methods="GET", requirements={"page"="\d+","order"="asc|desc"})
  140.      */
  141.     public function indexListing(
  142.         OrderRepository $orderRepo,
  143.         UiService $uiService,
  144.         $page,
  145.         $orderby,
  146.         $order,
  147.         Request $request,
  148.         RequestStack $requestStack,
  149.     ): Response {
  150.         $uiService->storeSortOrder('order-index-listing'$orderby$order);
  151.         $orders $orderRepo->getByClientPaged(
  152.             $this->getCurrentClient(),
  153.             self::LISTING_LIMIT,
  154.             $order,
  155.             $orderby,
  156.             $page,
  157.             $requestStack->getSession()->get('orderFilter')
  158.         );
  159.         return $this->render('order/_index_listing.html.twig', [
  160.             'uiService' => $uiService,
  161.             'orders' => $orders->getIterator(),
  162.             'total' => $orders->count(),
  163.             'pages' => ceil($orders->count() / self::LISTING_LIMIT),
  164.             'page' => $page,
  165.         ]);
  166.     }
  167.     /**
  168.      * @Route("/new/{return}", name="order_new", methods="GET|POST")
  169.      */
  170.     public function new(
  171.         Request $request,
  172.         $return null,
  173.         PersonRepository $personRepo,
  174.         ConfigurationService $configService,
  175.         OrderService $orderService,
  176.         ZoomService $zoomService,
  177.         IbanService $ibanService,
  178.     ): Response {
  179.         $customer null;
  180.         $invoiceRecipient null;
  181.         $isEmptyParticipants false;
  182.         if ($return) {
  183.             $customer $personRepo->find($return);
  184.             $invoiceRecipient $personRepo->getInvoiceReciepientMembers($return);
  185.             $invoiceRecipient $this->createInvoiceRecipientValues($invoiceRecipient$customer);
  186.             $customerChildrens $personRepo->getMembersByClient($customer);
  187.             $isEmptyParticipants = (empty($customerChildrens)) ? true false;
  188.         }
  189.         $em $this->getDoctrine()->getManager();
  190.         $order = new Order();
  191.         $order->setDate(new \DateTime());
  192.         $order->setStatus(Order::STATUS_PENDING);
  193.         $order->setNumber($configService->getNewOrderNumberByClient($this->getCurrentClient()));
  194.         $order->setClient($this->getCurrentClient());
  195.         $order->setCustomer($customer);
  196.     
  197.         $order->setCustomerData($customer);
  198.         $order->setCreated(new \DateTime());
  199.         $order->setPerson($customer);
  200.         $form $this->createForm(OrderType::class, $order, [
  201.             'client' => $this->getCurrentClient(),
  202.             'taxes' => $configService->getTaxConfigbyClient($this->getCurrentClient()),
  203.             'customer' => $customer,
  204.             'invoiceRecipient' => $invoiceRecipient,
  205.             'form_type' => OrderType::TYPE_CREATE_FOR_CUSTOMER
  206.         ]);
  207.         $form->handleRequest($request);
  208.         //   $em->persist($order);
  209.         // Check if creation is possible
  210.         if ($form->isSubmitted() && $form->isValid()) {
  211.             if (!$order->checkCustomerData($customer)) {
  212.                 $this->addFlash('error''Die Kundendaten sind unvollständig. Es kann keine neue Bestellung angelegt werden.');
  213.                 if ($return) {
  214.                     return $this->redirectToRoute('customer_orders', ['id' => $return]);
  215.                 } else {
  216.                     return $this->redirectToRoute('order_index');
  217.                 }
  218.             }
  219.             foreach ($order->getOrderItems() as $orderItem) {
  220.                 if ($orderItem->getCourseOccurrence()) {
  221.                     $orderItem->setCourseOccurrence($orderItem->getCourseOccurrence());
  222.                     if ($orderItem->getCourseOccurrence()->getCourse()->getMaterialCost() > || $orderItem->getCourseOccurrence()->getMaterialCost() > 0) {
  223.                         $item = new OrderItem();
  224.                         $item->setCourseOccurrence($orderItem->getCourseOccurrence());
  225.                         $item->setPrice($orderItem->getCourseOccurrence()->getMaterialCost() ?? $orderItem->getCourseOccurrence()->getCourse()->getMaterialCost());
  226.                         $item->setTaxRate($orderItem->getCourseOccurrence()->getTaxRate() ?? $orderItem->getCourseOccurrence()->getCourse()->getTaxRate());
  227.                         $item->setName('Materialkosten');
  228.                         $item->setQuantity($orderItem->getQuantity());
  229.                         // $item->setCourseItem($orderItem->getCourseOccurrence()->getCourse());
  230.                          $item->setCourseItem($orderItem);
  231.                         $item->setIsFree(false);
  232.                         $item->setOrder($order);
  233.                         $item->setCreated(new \Datetime());
  234.                         // $item->setCourseItem($orderItem);
  235.                         $em->persist($item);
  236.                     }
  237.                     $em->persist($orderItem);
  238.                 }
  239.                 // Skip participants check for free items
  240.                 if ($orderItem->getCourseOccurrence() === null) {
  241.                     continue;
  242.                 }
  243.                 // Check if order item has at least one participant
  244.                 if (count($orderItem->getParticipants()) == 0) {
  245.                     $this->addFlash('error''Der Kurs enthält keine Teilnehmer.');
  246.                     return $this->redirectToRoute('order_new', ['return' => $return]);
  247.                 }
  248.             }
  249.             $allItemsBookable true;
  250.             // $em->flush();
  251.             foreach ($order->getOrderItems() as $orderItem) {
  252.                 $orderItem->setCourseOccurrence($orderItem->getCourseOccurrence());
  253.                 
  254.              
  255.                 $orderItem->setCreated(new \DateTime());
  256.                 if ($orderItem->getCourse()) {
  257.                     $orderItem->setName($orderItem->getCourse()->getTitle());
  258.                     $orderItem->setDescription($orderItem->getCourse()->getSubtitle());
  259.                 } else {
  260.                     $orderItem->setName($orderItem->getName());
  261.                     $orderItem->setDescription($orderItem->getDescription());
  262.                 }
  263.                 //    $em->persist($orderItem);
  264.                 //    $em->flush($orderItem);
  265.                 if ($orderItem->getCourseOccurrence()) {
  266.                     $occurrence $orderItem->getCourseOccurrence();
  267.                     ///// testen und abgleichen was in der Datenbank steht und wie viele Buchungen es wirklich gibt ////
  268.                     //  $occurrence->setBookedSlots($occurrence->getBookedSlots());
  269.                     //    $em->persist($occurrence);
  270.                     //    $em->flush($occurrence);
  271.                     if (($occurrence->getSlots() < ($orderItem->getQuantity() + $occurrence->getBookedSlots())) && $occurrence->getReservationAllowed()) {
  272.                         $waitItem WaitItem::fromOrderItem($orderItem);
  273.                         $waitItem->setCreated(new \DateTime());
  274.                         $em->persist($waitItem);
  275.                         foreach ($orderItem->getParticipants() as $participant) {
  276.                             $participant->setOrderItem(null);
  277.                             $participant->setTitle($participant->getPerson()->getTitle());
  278.                             $participant->setSalutation($participant->getPerson()->getSalutation());
  279.                             $participant->setMember($participant->getPerson()->getMember());
  280.                             $participant->setFirstname($participant->getPerson()->getFirstname());
  281.                             $participant->setLastname($participant->getPerson()->getLastname());
  282.                             $participant->setDateOfBirth($participant->getPerson()->getDateOfBirth());
  283.                             $participant->setComment($participant->getPerson()->getComment());
  284.                             $participant->setOrderItem($orderItem);
  285.                             $participant->setCreated(new \DateTime());
  286.                             // $orderItem->removeParticipant($participant);
  287.                             //$orderItem->setQuantity($orderItem->getQuantity() - 1);
  288.                             $em->persist($participant);
  289.                         }
  290.                         $order->addWaitItem($waitItem);
  291.                         $this->addFlash('error''Im Kurs "' $occurrence->getTitle() . '" sind nicht mehr genug Plätze verfügbar. Es fehlen "' . ($orderItem->getQuantity() + $occurrence->getBookedSlots()) - $occurrence->getSlots() . '" Plätze. Die komplette Buchung wurde stattdessen zur Warteliste hinzugefügt.');
  292.                         $em->flush();
  293.                         // $order->removeOrderItem($orderItem);
  294.                         $orderItem->setOrder(null);
  295.                         $orderItem->setStatus('wait_item');
  296.                         //$orderItem->setCancelledQuantity($orderItem->getQuantity());
  297.                         //   $orderItem->setQuantity($orderItem->getQuantity());
  298.                         $em->persist($orderItem);
  299.                         $em->persist($order);
  300.                         //$em->remove($orderItem);
  301.                         $em->flush();
  302.                         //  var_dump($orderItem->getOrder());
  303.                         return $this->redirectToRoute('customer_orders', ['id' => $return]);
  304.                     } elseif (($occurrence->getSlots() < ($orderItem->getQuantity() + $occurrence->getBookedSlots())) && !$occurrence->getReservationAllowed()) {
  305.                         //  $occurrence->setBookedSlots($occurrence->getBookedSlots());
  306.                         $em->persist($occurrence);
  307.                         $em->remove($order);
  308.                         $em->flush();
  309.                         $allItemsBookable false;
  310.                         $this->addFlash('error''Im Kurs "' $occurrence->getTitle() . '" sind nicht mehr genug Plätze verfügbar. Es fehlen "' . ($orderItem->getQuantity() + $occurrence->getBookedSlots()) - $occurrence->getSlots() . '" Plätze.');
  311.                         return $this->redirectToRoute('customer_orders', ['id' => $return]);
  312.                     } else {
  313.                         if ($orderItem->getCourseOccurrence()->getCourse()->getCourseNature() == 'CourseSubscription') {
  314.                             $this->addFlash('warning''courseSubsciption');
  315.                             //    $courseSubscriptionBooking = new CourseSubscriptionBooking($orderItem, $orderItem->getCourse());
  316.                             //    $courseSubscriptionBooking->setOrderItem($orderItem);
  317.                             //    $courseSubscriptionBooking->setCourse($orderItem->getCourseOccurrence()->getCourse());
  318.                             //    $courseSubscriptionBooking->setCourseSubscription($orderItem->getCourseOccurrence()->getCourse()->getSubscription());
  319.                             //    $orderItem->setCourseSubscriptionBooking($courseSubscriptionBooking);
  320.                             //    $em->persist($courseSubscriptionBooking);
  321.                         }
  322.                         /*
  323.                         foreach ($orderItem->getParticipants() as $participant) 
  324.                         { 
  325.                             $occurrence->setBookedSlots($occurrence->getBookedSlots() + 1);
  326.                         }
  327.                         $em->persist($occurrence);
  328.                         */
  329.                         // $em->persist($occurrence);
  330.                         //            $occurrence = $orderItem->getCourseOccurrence();
  331.                         //  $occurrence->setBookedSlots($occurrence->getBookedSlotsDirectly() + $orderItem->getQuantity());
  332.                         //  $occurrence->setBookedSlots($occurrence->getBookedSlots() + $orderItem->getQuantity());
  333.                         //            $em->persist($occurrence);
  334.                         //     $em->flush();
  335.                         //   $occurrences[] = $occurrence;
  336.                     }
  337.                 }
  338.                 //  $em->flush();
  339.             }
  340.             $this->updateParticipantsOfOrder($order);
  341.             if ($orderItem->getCourse()) {
  342.                 $occurrence->setBookedSlots($occurrence->getBookedSlots() + $orderItem->getQuantity());
  343.             }
  344.             //  $em->flush();
  345.             if ($allItemsBookable) {
  346.                 if (count($order->getOrderItems()) > ||  count($order->getWaitItems()) > 0) {
  347.                     $order->setClient($this->getCurrentClient());
  348.                     $order->setCustomer($customer);
  349.                     $order->setCustomerData($customer);
  350.                     if ($customer->getIban()) {
  351.                         $order->setPaymentType(Order::PAYMENT_DEBIT);
  352.                         $order->setIban(
  353.                             strtoupper(
  354.                             preg_replace('/\s+/'''$customer->getIban())
  355.                                        )
  356.                                );
  357.                         $order->setBic($customer->getBic());
  358.                         $order->setBank($customer->getBank());
  359.                     }
  360.                     $orderItem->setOrder($order);
  361.                     $orderItem->getCourseOccurrence();
  362.                     // Ggf. nachfolgende Bestellungen fuer Abokurse generieren und speichern
  363.                     $flashs = [];
  364.                     $followingOrders $orderService->generateOrdersForSubscriptionCoursesAllFollowingOccurrences($this->getCurrentClient(), $order$flashs);
  365.                     foreach ($followingOrders as $orderToSave) {
  366.                         $em->persist($orderToSave);
  367.                     }
  368.                     foreach ($flashs as $flashToShow) {
  369.                         foreach ($flashToShow as $key => $value) {
  370.                             $this->addFlash($key$value);
  371.                         }
  372.                     }
  373.                 }
  374.                 /*
  375.                 foreach ($order->getOrderItems() as $orderItem) {
  376.                     if ($orderItem->getMaterialCosts()) {
  377.                                    $item = new OrderItem();
  378.                                    $item->setCourseOccurrence($orderItem->getCourseOccurrence());
  379.                                    $item->setPrice($orderItem->getCourseOccurrence()->getCourse()->getMaterialCost());
  380.                                    $item->setTaxRate($orderItem->getCourseOccurrence()->getCourse()->getTaxRate());
  381.                                    $item->setQuantity(1);
  382.                                    $item->setIsFree(false);
  383.                                    $item->setOrder($order);
  384.                                    $item->setCourseItem($orderItem);
  385.                                    $item->setCreated(new \Datetime());
  386.                        }
  387.                        $em->persist($item);
  388.                    }
  389.                    */
  390. ###################################### ZOOM MEETING ########################################
  391.     if (isset($_ENV['ZOOM_WEBINAR']) && $_ENV['ZOOM_WEBINAR'] === 1){
  392.         foreach ($order->getOrderItems() as $orderItem) {
  393.             foreach ($orderItem->getParticipants() as $participant) {
  394.                 $registrant $zoomService->addRegistrantToWebinar(
  395.                     $orderItem->getCourseOccurrence()->getCode(),
  396.                     $participant->getPerson()->getContactEmail(),
  397.                     $participant->getPerson()->getFirstname(),
  398.                     $participant->getPerson()->getLastname()
  399.                 );
  400.             }
  401.         }
  402.     }
  403. ###################################### ZOOM MEETING ########################################
  404.                 $em->persist($order);
  405.                 $em->flush();
  406.                 if ($return) {
  407.                     if ($orderItem->getCourse()) {
  408.                         $this->addFlash('warning''Der Kurs "' $occurrence->getTitle() . '" wurde mit ' $orderItem->getQuantity() . ' Plätzen bebucht');
  409.                     }
  410.                     return $this->redirectToRoute('customer_orders', ['id' => $return]);
  411.                 } else {
  412.                     return $this->redirectToRoute('order_index');
  413.                 }
  414.             }
  415.             $em->remove($orderItem);
  416.             $em->remove($order);
  417.             $em->flush();
  418.             $this->addFlash('warning''LETZTE MÖGLICHKEIT "' $occurrence->getTitle() . '" ' $occurrence->getSlots() . ' | ' $occurrence->getBookedSlots() . '|' . ($occurrence->getSlots() - $occurrence->getBookedSlots()) . ' | ' $orderItem->getQuantity());
  419.         }
  420.         return $this->render('order/new.html.twig', [
  421.             'order' => $order,
  422.             'form' => $form->createView(),
  423.             'customer' => $customer,
  424.             'invoiceRecipient' => $invoiceRecipient,
  425.             'invalidCustomerData' => !$order->checkCustomerData($customer),
  426.             'isEmptyParticipants' => $isEmptyParticipants,
  427.             'isInvoiceClosed' => false
  428.         ]);
  429.     }
  430.     /**
  431.      * @Route("/{id}", name="order_show", methods="GET|POST", requirements={"id"="\d+"})
  432.      */
  433.     public function show(
  434.         Request $request,
  435.         Order $order,
  436.         InvoiceRepository $invoiceRepo
  437.     ): Response {
  438.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$order);
  439.         $form $this->createForm(OrderStatusType::class, $order);
  440.         $form->handleRequest($request);
  441.         if ($form->isSubmitted() && $form->isValid()) {
  442.             $this->getDoctrine()->getManager()->flush();
  443.             return $this->redirectToRoute('order_show', ['id' => $order->getId()]);
  444.         }
  445.       
  446.         $orderedInvoices $invoiceRepo->getOrderedInvoices($order->getId());
  447.         $isInvoiceWithCancillation $this->isInvoiceWithCancillation($order->getInvoices());
  448.         return $this->render('order/show.html.twig', [
  449.             'order' => $order,
  450.             'form' => $form->createView(),
  451.             'isInvoiceWithCancillation' => $isInvoiceWithCancillation,
  452.             'orderedInvoices' => $orderedInvoices
  453.         ]);
  454.     }
  455.     /**
  456.      * @Route("/search/{occurrenceId}/{timeId}", name="order_search", methods="GET|POST", requirements={"id"="\d+"})
  457.      */
  458.     public function search(
  459.         Request $request,
  460.         Connection $connection,
  461.         CourseOccurrenceTimeRepository $timeRepository
  462.     ): Response {
  463.         $time $timeRepository->find($request->get('timeId'));
  464.         $sql 'SELECT
  465.             oi.*
  466.         FROM
  467.             customer_order_item oi,
  468.             course_occurrence o
  469.         WHERE
  470.             o.id = oi.course_occurrence_id AND
  471.             o.start = "' $time->getStart()->format('Y-m-d H:i:s') . '"
  472.         GROUP BY
  473.             oi._order_id';
  474.         $result $connection->fetchAssoc($sql);
  475.         if (empty($result)) {
  476.             $sql 'SELECT
  477.                 oi.*
  478.             FROM
  479.                 wait_item oi,
  480.                 course_occurrence o
  481.             WHERE
  482.                 o.id = oi.course_occurrence_id AND
  483.                 o.start = "' $time->getStart()->format('Y-m-d H:i:s') . '"
  484.             GROUP BY
  485.                 oi._order_id';
  486.             $result $connection->fetchAssoc($sql);
  487.         }
  488.         return $this->redirectToRoute('order_show', ['id' => $result['_order_id']]);
  489.     }
  490.     /**
  491.      * @Route("/{id}/edit/{return}", name="order_edit", methods="GET|POST", requirements={"id"="\d+","return"="\d+"})
  492.      */
  493.     public function edit(
  494.         Request $request,
  495.         Order $order,
  496.         $return '',
  497.         ConfigurationService $configService,
  498.         PersonRepository $personRepo
  499.     ): Response {
  500.         $isEmptyParticipants false;
  501.         $invoiceRecipient null;
  502.         $isInvoiceClosed false;
  503.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$order);
  504.         $order->setModified(new \DateTime());
  505.         $customer null;
  506.         if ($order->getCustomer()) {
  507.             $customer $order->getCustomer();
  508.         }
  509.         if (
  510.             $order->getInvoices()->first() &&
  511.             $order->getInvoices()->first()->getStatus() == Invoice::STATUS_CLOSED
  512.         ) {
  513.             $isInvoiceClosed true;
  514.         }
  515.         if ($return) {
  516.             $customer $personRepo->find($return);
  517.             $invoiceRecipient $personRepo->getInvoiceReciepientMembers($return);
  518.             $invoiceRecipient $this->createInvoiceRecipientValues($invoiceRecipient$customer);
  519.             $customerChildrens $personRepo->getMembersByClient($customer);
  520.             $isEmptyParticipants = (empty($customerChildrens)) ? true false;
  521.         }
  522.         if ($order->getStatus() != Order::STATUS_PENDING) {
  523.             $this->addFlash('notice''Die Bestellung kann nur bearbeitet werden wenn Sie in Wartestellung ist.');
  524.             if ($return) {
  525.                 return $this->redirectToRoute('customer_orders', ['id' => $return]);
  526.             } else {
  527.                 return $this->redirectToRoute('order_index');
  528.             }
  529.         }
  530.         $form $this->createForm(OrderType::class, $order, [
  531.             'client' => $this->getCurrentClient(),
  532.             'taxes' => $configService->getTaxConfigbyClient($this->getCurrentClient()),
  533.             'invoiceRecipient' => $invoiceRecipient,
  534.             'customer' => $customer,
  535.             'form_type' => OrderType::TYPE_CREATE_FOR_CUSTOMER
  536.         ]);
  537.         $form->handleRequest($request);
  538.         if ($form->isSubmitted() && $form->isValid()) {
  539.            // $this->updateParticipantsOfOrder($order);
  540.             $em $this->getDoctrine()->getManager();
  541.             foreach ($order->getOrderItems() as $item) {
  542.                 $item->setModified(new \DateTime());
  543.                 if (!$item->isFree() && $item->getCourseOccurrence()) {
  544.                     $item->setName($item->getCourseOccurrence()->getTitle());
  545.                     $em->persist($item);
  546.                 } else {
  547.                    // $item->setCourseOccurrence(null);
  548.                     $em->persist($item);
  549.                 }
  550.             }
  551.             $em->flush();
  552.             $this->addFlash('notice''Die Bestellung wurde bearbeitet.');
  553.             return $this->redirectToRoute('order_index');
  554.             // }
  555.         }
  556.         return $this->render('order/edit.html.twig', [
  557.             'order' => $order,
  558.             'form' => $form->createView(),
  559.             'customer' => $customer,
  560.             'isEmptyParticipants' => $isEmptyParticipants,
  561.             'invoiceRecipient' => $invoiceRecipient,
  562.             'isInvoiceClosed' => $isInvoiceClosed
  563.         ]);
  564.     }
  565.     /**
  566.      * @Route("/{id}/cancel", name="order_cancel", methods="POST")
  567.      */
  568.     public function cancel(
  569.         Request $request,
  570.         Order $order,
  571.         ConfigurationService $configService,
  572.         OrderService $orderService
  573.     ): Response {
  574.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$order);
  575.         if ($this->isCsrfTokenValid('cancel' $order->getId(), $request->request->get('_token'))) {
  576.             $em $this->getDoctrine()->getManager();
  577.             foreach ($order->getOrderItems() as $orderItem) {
  578.                 // If order item is connected to time slot mark it bookable again
  579.                 if ($time $orderItem->getCourseOccurrenceTime()) {
  580.                     $time->setAvailability('Bookable');
  581.                     $time->setOrderItem(null);
  582.                 }
  583.                 if ($orderItem) {
  584.                     $orderItem->setStatus('cancelled');
  585.                     foreach ($orderItem->getParticipants() as $person) {
  586.                         $person->setStatus('cancelled');
  587.                         $person->setCancelled(new \DateTime());
  588.                         $person->setModified(new \DateTime());
  589.                         $em->persist($person);
  590.                     }
  591.                     $orderItem->setCancelledQuantity($orderItem->getCancelledQuantity() + 1);
  592.                     $orderItem->setQuantity($orderItem->getQuantity() - 1);
  593.                     $orderItem->setModified(new \DateTime());
  594.                     //$orderItem->setQuantity('0');
  595.                 }
  596.             }
  597.             foreach ($order->getWaitItems() as $waitItem) {
  598.                 if ($time $waitItem->getCourseOccurrenceTime()) {
  599.                     $time->setAvailability('Requestable');
  600.                     $time->setWaitItem(null);
  601.                 }
  602.             }
  603.             foreach ($order->getInvoices() as $invoice) {
  604.                 if (!$invoice->isCancelled() && !$invoice->isCancellation()) {
  605.                     $cancellation $orderService->createCancellation($invoice);
  606.                     $cancellation->setSignedBy($this->getCurrentUser());
  607.                     $invoice->setCancelled(true);
  608.                     $em->persist($cancellation);
  609.                 }
  610.             }
  611.             $order->setStatus(Order::STATUS_CANCELLED);
  612.             $order->setModified(new \DateTime());
  613.             $orderService->calculateCancelOrderItems($order);
  614.             $em->flush();
  615.             $this->addFlash('notice''Bestellung storniert');
  616.         }
  617.         return $this->redirectToRoute('order_show', ['id' => $order->getId()]);
  618.     }
  619.     /**
  620.      * @Route("/set-cancel-date/{id}", name="participant_set-cancel-date")
  621.      */
  622.     public function setCancelDateForParticicpant(
  623.         Request $request,
  624.         OrderItemPerson $participant,
  625.         OrderService $orderService,
  626.         RequestStack $requestStack,
  627.         ManagerRegistry $managerRegistry,
  628.         //  LoggerInterface $logger
  629.     ): Response {
  630.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$participant->getOrderItem()->getOrder());
  631.         $form $this->createForm(OrderItemPersonCancelDate::class, null, [
  632.             'action' => $this->generateUrl('participant_set-cancel-date', ['id' => $participant->getId()])
  633.         ]);
  634.         $form->handleRequest($request);
  635.         $participant->setCancelled($orderService->getCancelDateForParticipantInCourse($this->getCurrentClient(), $participant));
  636.         if ($form->isSubmitted() && $form->isValid()) {
  637.             /**
  638.              * @var \DateTimeInterface $cancelDate
  639.              */
  640.             $cancelDate $form->getData()['cancelDate'];
  641.             // Kuendigungsdatum in entsprechenden Teilnehmereintrag im Kurs schreiben
  642.             $participant->setCancelled($cancelDate);
  643.             $em $managerRegistry->getManager();
  644.             $booking $participant->getOrderItem()->getCourseSubscriptionBooking();
  645.             if (!empty($booking)) {
  646.                 $terminationPeriod $booking->getCourseSubscription()->getTerminationPeriod();
  647.                 $cancelDate->modify('+' $terminationPeriod ' months');
  648.             }
  649.             $result $orderService->setCancelDateForParticipantInCourse(
  650.                 $this->getCurrentClient(),
  651.                 $participant,
  652.                 $cancelDate
  653.             );
  654.             $em->flush();
  655.             // Aktive Eintraege/Bestellpositionen/Bestellungen fuer Kurstermine nach dem Kuendigungsdatum erhalten
  656.             $oipsToCancel $orderService->getAllActiveParticipationsAfterCancelDateByParticipant(
  657.                 $this->getCurrentClient(),
  658.                 $participant
  659.             );
  660.             // Diese Eintraege einzeln durchlaufen und stornieren
  661.             foreach ($oipsToCancel as $oipToCancel) {
  662.                 // Bei schon vorhandenen Rechnungen ggf. Storno-Rechnungen erstellen
  663.                 foreach ($oipToCancel->getOrderItem()->getOrder()->getInvoices() as $invoice) {
  664.                     if (!$invoice->isCancelled() && !$invoice->isCancellation() && $invoice->containsOrderItem($oipToCancel->getOrderItem())) {
  665.                         $cancellation $orderService->createCancellation($invoice$oipToCancel->getOrderItem(), $oipToCancel->getId());
  666.                         $cancellation->setSignedBy($this->getCurrentUser());
  667.                         $em->persist($cancellation);
  668.                     }
  669.                 }
  670.                 // Eintrag stornieren
  671.                 $orderService->cancelOrderItemParticipant($oipToCancel->getOrderItem(), $oipToCancel->getId());
  672.                 // Ggf. Bestellposition stornieren
  673.                 if (!$oipToCancel->getOrderItem()->hasUncancelledParticipants()) {
  674.                     $oipToCancel->getOrderItem()->setStatus(OrderItem::STATUS_CANCELLED);
  675.                     foreach ($oipToCancel->getOrderItem()->getMaterialCosts() as $materialCost) {
  676.                         $materialCost->setStatus(OrderItem::STATUS_CANCELLED);
  677.                     }
  678.                 }
  679.                 // Ggf. Bestellung stornieren
  680.                 if (!$oipToCancel->getOrderItem()->getOrder()->hasUncancelledItems()) {
  681.                     $oipToCancel->getOrderItem()->getOrder()->setStatus(Order::STATUS_CANCELLED);
  682.                 }
  683.                 $orderService->calculateCancelOrderItem($oipToCancel->getOrderItem());
  684.             }
  685.             // Aenderungen in Datenbank speichern
  686.             $em->flush();
  687.             $flashExists false;
  688.             foreach ($requestStack->getSession()->all() as $flashType => $flashTitle) {
  689.                 if ($flashType == 'notice' && $flashTitle == 'Kündigungsdatum eingetragen'$flashExists true;
  690.             }
  691.             if (!$flashExists$this->addFlash('notice''Kündigungsdatum eingetragen');
  692.             $route $request->headers->get('referer');
  693.             return $this->redirect($route);
  694.         }
  695.         return $this->render('course/_set-cancel-date.html.twig', [
  696.             'person' => $participant->getPerson(),
  697.             'form' => $form->createView(),
  698.             'cancelDate' => $participant->getCancelled(),
  699.             'today' => new \DateTime()
  700.         ]);
  701.     }
  702.     /**
  703.      * @Route("/{id}/cancel-item/{participantId}/{return}", name="order-item_cancel", methods="GET")
  704.      */
  705.     public function cancelItem(
  706.         Request $request,
  707.         OrderItem $orderItem,
  708.         int $participantId 0,
  709.         string $return '',
  710.         ConfigurationService $configService,
  711.         OrderService $orderService
  712.     ): Response {
  713.         $order $orderItem->getOrder();
  714.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$order);
  715.         $em $this->getDoctrine()->getManager();
  716.         foreach ($order->getInvoices() as $invoice) {
  717.             if (!$invoice->isCancelled() && !$invoice->isCancellation() && $invoice->containsOrderItem($orderItem)) {
  718.                 $cancellation $orderService->createCancellation($invoice$orderItem$participantId);
  719.                 $cancellation->setSignedBy($this->getCurrentUser());
  720.                 $em->persist($cancellation);
  721.             }
  722.         }
  723.         if ($participantId 0) {
  724.             $orderService->cancelOrderItemParticipant($orderItem$participantId);
  725.         } else {
  726.             $orderItem->cancelAllParticipants();
  727.         }
  728.         if (!$orderItem->hasUncancelledParticipants()) {
  729.             $orderItem->setStatus(OrderItem::STATUS_CANCELLED);
  730.             foreach ($orderItem->getMaterialCosts() as $materialCost) {
  731.                 $materialCost->setStatus(OrderItem::STATUS_CANCELLED);
  732.             }
  733.         }
  734.         if (!$order->hasUncancelledItems()) {
  735.             $order->setStatus(Order::STATUS_CANCELLED);
  736.         }
  737.         $orderService->calculateCancelOrderItem($orderItem);
  738.         $orderItem->setModified(new \DateTime());
  739.         $order->setModified(new \DateTime());
  740.         $em->flush();
  741.         $this->addFlash('notice''Kurs storniert');
  742.         // return $this->redirect(urldecode($return));
  743.         return $this->redirectToRoute('course_invoices', ['id' => $request->get('course_id')]);
  744.     }
  745.     /**
  746.      * @Route("/copy-participant/{id}", name="participant_copy-to-other-occurrence")
  747.      */
  748.     public function copyParticipantToOtherOccurrence(
  749.         Request $request,
  750.         OrderItemPerson $participant,
  751.         OrderService $orderService,
  752.         CourseOccurrenceRepository $coRepo,
  753.         RequestStack $requestStack
  754.     ): Response {
  755.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$participant->getOrderItem()->getOrder());
  756.         $selectableOccurrences $orderService->getAllOccurrencesOfCourseAParticipantIsNotInBeforeCancelDate($this->getCurrentClient(), $participant);
  757.         $selectableOccurrencesArray = [];
  758.         foreach ($selectableOccurrences as $selectableOccurrence) {
  759.             $selectableOccurrencesArray[$selectableOccurrence->getStart()->format('d.m.Y') . ' - ' $selectableOccurrence->getEnd()->format('d.m.Y')] = $selectableOccurrence->getId();
  760.         }
  761.         $form $this->createForm(OrderItemPersonCopy::class, null, [
  762.             'occurrences' => $selectableOccurrencesArray,
  763.             'action' => $this->generateUrl('participant_copy-to-other-occurrence', ['id' => $participant->getId()])
  764.         ]);
  765.         $form->handleRequest($request);
  766.         if ($form->isSubmitted() && $form->isValid()) {
  767.             $em $this->getDoctrine()->getManager();
  768.             $flashs = [];
  769.             $orders = [];
  770.             foreach ($form->getData()['occurrences'] as $occurrenceId) {
  771.                 $flash = [];
  772.                 $occurrence $coRepo->find($occurrenceId);
  773.                 $newOrder $orderService->generateOrderForCourseOccurrenceFromOrderItemPerson(
  774.                     $this->getCurrentClient(),
  775.                     $participant,
  776.                     $occurrence,
  777.                     $flash,
  778.                     false
  779.                 );
  780.                 if ($newOrder !== null) {
  781.                     $orders[] = $newOrder;
  782.                 }
  783.                 if (count($flash) > 0) {
  784.                     $flashs[] = $flash;
  785.                 }
  786.             }
  787.             foreach ($orders as $orderToSave) {
  788.                 $em->persist($orderToSave);
  789.             }
  790.             foreach ($flashs as $flashToShow) {
  791.                 foreach ($flashToShow as $key => $value) {
  792.                     $this->addFlash($key$value);
  793.                 }
  794.             }
  795.             // Aenderungen in Datenbank speichern
  796.             $em->flush();
  797.             $flashExists false;
  798.             foreach ($requestStack->getSession()->all() as $flashType => $flashTitle) {
  799.                 if ($flashType == 'notice' && $flashTitle == 'Teilnehmer in ' count($orders) . ' weitere Termine übernommen'$flashExists true;
  800.             }
  801.             if (!$flashExists$this->addFlash('notice''Teilnehmer in ' count($orders) . ' weitere Termine übernommen');
  802.             return $this->redirectToRoute('course_participants', ['id' => $participant->getOrderItem()->getCourseOccurrence()->getCourse()->getId()]);
  803.         }
  804.         return $this->render('course/_copy-to-occurrence.html.twig', [
  805.             'person' => $participant->getPerson(),
  806.             'form' => $form->createView(),
  807.         ]);
  808.     }
  809.     /**
  810.      * @Route("/{id}/create-invoice", name="order_invoice_create", methods="GET")
  811.      */
  812.     public function createInvoice(
  813.         Request $request,
  814.         Order $order,
  815.         InvoiceService $invoiceService
  816.     ): Response {
  817.         $results $invoiceService->createInvoiceFromOrder($order);
  818.         $em $this->getDoctrine()->getManager();
  819.         //Update the order status
  820.         $newOrderState $order->setStatus(Order::STATUS_PROCESSING);
  821.         $em->persist($newOrderState);
  822.         foreach ($results['attendees'] as $attendee) {
  823.             $em->persist($attendee);
  824.         }
  825.         $em->persist($results['invoice']);
  826.         $em->flush();
  827.         $this->addFlash('notice'' Rechnung erstellt');
  828.         return $this->redirectToRoute('order_show', ['id' => $order->getId()]);
  829.     }
  830.     /**
  831.      * @Route("/{id}", name="order_delete", methods="DELETE")
  832.      */
  833.     public function delete(Request $requestOrder $order): Response
  834.     {
  835.         if ($this->isCsrfTokenValid('delete' $order->getId(), $request->request->get('_token'))) {
  836.             $em $this->getDoctrine()->getManager();
  837.             $em->remove($order);
  838.             $em->flush();
  839.         }
  840.         return $this->redirectToRoute('order_index');
  841.     }
  842.     protected function updateParticipantsOfOrder(Order $order)
  843.     {
  844.         if (count($order->getOrderItems()) > 0) {
  845.             foreach ($order->getOrderItems() as $orderItem) {
  846.                 if (count($orderItem->getParticipants()) > 0) {
  847.                     foreach ($orderItem->getParticipants() as $participant) {
  848.                         $participant->updateFieldsFromPerson();
  849.                     }
  850.                 }
  851.             }
  852.         }
  853.     }
  854.     private function createInvoiceRecipientValues($persons$customer)
  855.     {
  856.         $res[] = $customer;
  857.         foreach ($persons as $person) {
  858.             $res[] = $person;
  859.         }
  860.         return $res;
  861.     }
  862.     /**
  863.      * isInvoiceWithCancillation
  864.      *
  865.      * Checks whether one of the invoices is a cancellation invoice
  866.      *
  867.      * @param  Collection $invoices
  868.      * @return boolean
  869.      */
  870.     private function isInvoiceWithCancillation(Collection $invoices)
  871.     {
  872.         $cancelation false;
  873.         if (empty($invoices)) return $cancelation;
  874.         $counter count($invoices);
  875.         if ($counter || !($invoices[$counter 1]->isCancellation())) return $cancelation;
  876.         foreach ($invoices as $invoice) {
  877.             if ($invoice->isCancellation()) {
  878.                 $cancelation true;
  879.                 break;
  880.             }
  881.         }
  882.         return $cancelation;
  883.     }
  884.     /**
  885.      * @Route("/changestatus/{id}/{status}", name="change_status")
  886.      */
  887.     public function changeStatus(Order $order$status): Response
  888.     {
  889.         $em $this->getDoctrine()->getManager();
  890.         $newstatus $order->setStatus($status);
  891.         $em->persist($newstatus);
  892.         $em->flush();
  893.         return $this->json([
  894.             'success' => 'Der Status wurde geändert.'
  895.         ]);
  896.     }
  897.     /**
  898.      * @Route("/sendordermail/{id}", name="send_order_mail")
  899.      */
  900.      public function sendordermail(Order $orderPersonRepository $personRepoEmailHistoryService $emailHistoryServiceMailerService $mailerServiceConnection $connection): Response
  901.     {
  902.         $orderItems $order->getOrderItems() ? $order->getOrderItems()->toArray() : [];
  903. $waitItems $order->getWaitItems() ? $order->getWaitItems()->toArray() : [];
  904. $allItems array_merge($orderItems$waitItems);
  905.         foreach ($allItems as $item) {
  906.             /////////////////////////////////// FIELDS Start //////////////////////////////////////
  907.             // Fetch course fields
  908.             $sql 'SELECT
  909.             f.*,
  910.             d.value_text,
  911.             d.value_integer
  912.         FROM
  913.             course_field f
  914.         LEFT JOIN
  915.             course_data d
  916.             ON 
  917.             d.field_id = f.id AND
  918.             d.course_id = :courseId
  919.         WHERE f.certificate = 0';
  920.             $stmt $connection->prepare($sql);
  921.             $stmt->bindValue(
  922.                 'courseId',
  923.                 $item->getCourseOccurrence()->getCourse()->getId()
  924.             );
  925.             $stmt->executeQuery();
  926.             $result $stmt->fetchAll();
  927.             $fields = [];
  928.             foreach ($result as $index => $field) {
  929.                 if (!empty($field['category'])) {
  930.                     if (!$item->getCourseOccurrence()->getCourse()->getCategory()) {
  931.                         continue;
  932.                     }
  933.                     if (!in_array($item->getCourseOccurrence()->getCourse()->getCategory()->getId(), json_decode($field['category'], true))) {
  934.                         continue;
  935.                     }
  936.                 }
  937.                 if (!empty($field['course_type'])) {
  938.                     if (!$item->getCourseOccurrence()->getCourse()->getType()) {
  939.                         continue;
  940.                     }
  941.                     if (!in_array($item->getCourseOccurrence()->getCourse()->getType()->getId(), json_decode($field['course_type'], true))) {
  942.                         continue;
  943.                     }
  944.                 }
  945.                 $fields[] = [
  946.                     'id' => $field['id'],
  947.                     'name' => $field['name'],
  948.                     'value' => !empty($field['value_integer']) ? $field['value_integer'] : $field['value_text'],
  949.                 ];
  950.             }
  951.             $order->setFields($fields);
  952.             $sentMessage $mailerService->sendCheckoutConfirmMessage($order);
  953.             $customer $order->getCustomer();
  954.             $emailHistoryService->saveProtocolEntryFromOrder(
  955.                 $order,
  956.                 $this->getCurrentClient(),
  957.                 $customer,
  958.                 'versandt',
  959.                 $sentMessage['subject'],
  960.                 $sentMessage['message'],
  961.                 'Bestellbestätigung gesendet',
  962.                 $sentMessage['email']
  963.             );
  964.             $message "Bestellbestätigung ist versendet" ;
  965.             $this->addFlash('notice'$message);
  966.             return $this->redirectToRoute('order_index');
  967.         }
  968.         // Ensure a return value if there are no order items
  969.         $this->addFlash('error''Keine Bestellpositionen gefunden.');
  970.         return $this->redirectToRoute('order_index');
  971.     }
  972. }