src/Controller/CourseController.php line 742

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Course;
  4. use App\Entity\Order;
  5. use App\Entity\CourseData;
  6. use App\Entity\Invoice;
  7. use App\Form\CourseType;
  8. use App\Repository\CourseFieldRepository;
  9. use App\Repository\CourseDataRepository;
  10. use App\Service\PdfService;
  11. use App\Form\CourseImagesType;
  12. use App\Service\MailerService;
  13. use App\Service\InvoiceService;
  14. use App\Service\SepaXmlService;
  15. use App\Entity\InvoicePayment;
  16. use App\Entity\CourseOccurrence;
  17. use App\Repository\CourseOccurrenceTimeRepository;
  18. use App\Repository\TagsPersonRepository;
  19. use App\Repository\PersonRepository;
  20. use App\Repository\PresenceRepository;
  21. use App\Entity\OrderItem;
  22. use App\Repository\OrderRepository;
  23. use App\Repository\CourseRepository;
  24. use App\Service\EmailHistoryService;
  25. use App\Service\ConfigurationService;
  26. use App\Repository\CartItemRepository;
  27. use Doctrine\Persistence\ManagerRegistry;
  28. use App\Entity\Presence;
  29. use Doctrine\ORM\EntityManagerInterface;
  30. use App\Repository\TextblocksRepository;
  31. use App\Repository\WaitItemRepository;
  32. use App\Repository\OrderItemRepository;
  33. use App\Service\Exception\ServiceException;
  34. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  35. use App\Repository\CourseOccurrenceRepository;
  36. use App\Repository\InvoiceItemRepository;
  37. use App\Service\OrderService;
  38. use Symfony\Component\HttpFoundation\Response;
  39. use Symfony\Component\HttpFoundation\Request;
  40. use Symfony\Component\Routing\Annotation\Route;
  41. use Doctrine\Common\Collections\ArrayCollection;
  42. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  43. use Menke\UserBundle\Controller\AbstractClientableController;
  44. /**
  45.  * @Route("/course")
  46.  * @IsGranted("ROLE_SPEAKER")
  47.  */
  48. class CourseController extends AbstractClientableController
  49. {
  50.     const LISTING_LIMIT 20;
  51.     /**
  52.      *
  53.      */
  54.     private function getListingLimit(): int
  55.     {
  56.         return !empty($_ENV['COURSES_LISTINGLIMIT']) ? (int) $_ENV['COURSES_LISTINGLIMIT'] : 4;
  57.     }
  58.     /**
  59.      * @Route("/", name="course_index", methods="GET")
  60.      */
  61.     public function index(
  62.         Request $request,
  63.         \App\Service\UiService $uiService,
  64.         CourseRepository $courseRepository,
  65.         EntityManagerInterface $manager,
  66.     ): Response {
  67.         $this->denyAccessUnlessGranted('ROLE_MANAGER');
  68.         $order $uiService->getSortOrder('course-index-listing');
  69.         $archive = !empty($request->get('archive'));
  70.         $courses $courseRepository->getCoursesByClientPaged(
  71.             $this->getCurrentClient(),
  72.             $this->getListingLimit(),
  73.             $order['orderDirection'] ?? 'ASC',
  74.             $order['orderBy'] ?? 'title',
  75.             1,
  76.             $archive,
  77.         );
  78.         // die Anzahl der Kurse mit den gebuchten überprüfen und die bookedSlots bei den CourseOccurreces aktualisieren
  79.         $this->manager $manager;
  80.         foreach ($courses as $course
  81.         {
  82.             foreach ($course->getOccurrences() as $occurrence
  83.                         {
  84.                             $occurrence->setBookedSlots($occurrence->getBookedSlots());
  85.                             $this->manager->persist($occurrence);
  86.                         }
  87.          }
  88.          $this->manager->flush();
  89.          ///////////////////////////////////////////
  90.         return $this->render('course/index.html.twig', [
  91.             'uiService' => $uiService,
  92.             'courses' =>  $courses,
  93.             'total' => $courses->count(),
  94.             'pages' => ceil($courses->count() / $this->getListingLimit()),
  95.             'page' => 1,
  96.             'archive' => $archive,
  97.             'env' => $_ENV,
  98.         ]);
  99.     }
  100.     /**
  101.      * @Route("/{page}/{orderby}/{order}", name="course_index_listing", methods="GET", requirements={"page"="\d+","order"="asc|desc"})
  102.      */
  103.     public function indexListing(
  104.         Request $request,
  105.         CourseRepository $courseRepository,
  106.         \App\Service\UiService $uiService,
  107.         $page,
  108.         $orderby,
  109.         $order
  110.     ): Response {
  111.         $uiService->storeSortOrder('course-index-listing'$orderby$order);
  112.         $archive = !empty($request->get('archive'));
  113.         $courses $courseRepository->getCoursesByClientPaged($this->getCurrentClient(), $this->getListingLimit(), $order$orderby$page$archive);
  114.         return $this->render('course/_index_listing.html.twig', [
  115.             'courses' => $courses,
  116.             'total' => $courses->count(),
  117.             'pages' => ceil($courses->count() / $this->getListingLimit()),
  118.             'page' => $page,
  119.             'archive' => $archive,
  120.             'env' => $_ENV,
  121.         ]);
  122.     }
  123.     /**
  124.      * @Route("/new", name="course_new", methods="GET|POST")
  125.      */
  126.     public function new(Request $requestConfigurationService $configService): Response
  127.     {
  128.         $course = new Course();
  129.         if (!empty($courseNature $request->get('courseNature'))) {
  130.             $course->setCourseNature($courseNature);
  131.         }
  132.         $form $this->createForm(CourseType::class, $course, [
  133.             'client' => $this->getCurrentClient(),
  134.             'taxes' => $configService->getTaxConfigbyClient($this->getCurrentClient()),
  135.         ]);
  136.         $form->handleRequest($request);
  137.         if ($form->isSubmitted() && $form->isValid()) {
  138.             $course->setClient($this->getCurrentClient());
  139.             $course->setNumber($configService->getNewCourseNumberByClient($this->getCurrentClient()));
  140.             foreach ($course->getTexts() as $key => $text) {
  141.                 $text->setCreated(new \DateTime());
  142.                 if (empty($text->getOrderId())) {
  143.                     $text->setOrderId($key 1000);
  144.                 }
  145.             }
  146.             $em $this->getDoctrine()->getManager();
  147.             $course->setCreated(new \DateTime());
  148.             $em->persist($course);
  149.             $em->flush();
  150.             $this->addFlash('success''Kurs angelegt');
  151.             return $this->redirectToRoute('course-occurrence_new', ['courseId' => $course->getId()]);
  152.         }
  153.         return $this->render('course/new.html.twig', [
  154.             'course' => $course,
  155.             'fields' => null,
  156.             'form' => $form->createView(),
  157.         ]);
  158.     }
  159.     /**
  160.      * @Route("/{id}/edit", name="course_edit", methods="GET|POST", requirements={"id"="\d+"})
  161.      */
  162.     public function edit(
  163.         Request $request,
  164.         Course $course,
  165.         ConfigurationService $configService,
  166.         CourseFieldRepository $courseFieldRepository,
  167.         CourseDataRepository $courseDataRepository
  168.     ): Response {
  169.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  170.         $courseTexts = new ArrayCollection();
  171.         foreach ($course->getTexts() as $text) {
  172.             $courseTexts->add($text);
  173.         }
  174.         $form $this->createForm(CourseType::class, $course, [
  175.             'client' => $this->getCurrentClient(),
  176.             'taxes' => $configService->getTaxConfigbyClient($this->getCurrentClient()),
  177.         ]);
  178.         $form->handleRequest($request);
  179.         if ($form->isSubmitted() && $form->isValid()) {
  180.             $manager $this->getDoctrine()->getManager();
  181.             foreach ($courseTexts as $text) {
  182.                 if (false === $course->getTexts()->contains($text)) {
  183.                     $text->setCourse(null);
  184.                     $manager->remove($text);
  185.                 }
  186.             }
  187.             foreach ($course->getTexts() as $key => $text) {
  188.                 if (empty($text->getOrderId())) {
  189.                     $text->setCreated(new \DateTime());
  190.                     $text->setOrderId($key 1000);
  191.                 }
  192.                 $text->setModified(new \DateTime());
  193.             }
  194.             $fields $request->request->get('fields');
  195.             if (!is_null($fields)) {
  196.                 foreach ($fields as $fieldId => $value) {
  197.                     $field $courseFieldRepository->find($fieldId);
  198.                     $data $courseDataRepository->findBy([
  199.                         'course' => $course,
  200.                         'field' => $field,
  201.                     ]);
  202.                     if (count($data) == 0) {
  203.                         $data = new CourseData();
  204.                         $data->setClient($this->getCurrentClient());
  205.                         $data->setCourse($course);
  206.                         $data->setField($field);
  207.                         $data->setCreated(new \datetime());
  208.                         $manager->persist($data);
  209.                     } else {
  210.                         $data $data[0];
  211.                     }
  212.                     $data->setValueText($value);
  213.                     $data->setModified(new \datetime());
  214.                 }
  215.             } else {
  216.                 $fields = [];
  217.             }
  218.             $course->setModified(new \datetime());
  219.             $manager->flush();
  220.             $this->addFlash('notice''Kurs gespeichert');
  221.             return $this->redirectToRoute('course_edit', ['id' => $course->getId()]);
  222.         }
  223.         // Fetch course fields
  224.         $sql 'SELECT
  225.             f.*,
  226.             d.value_text,
  227.             d.value_integer,
  228.             d.value_date
  229.         FROM
  230.             course_field f
  231.         LEFT JOIN
  232.             course_data d
  233.         ON 
  234.             d.field_id = f.id AND
  235.             d.course_id = ' $course->getId();
  236.         $em $this->getDoctrine()->getManager();
  237.         $stmt $em->getConnection()->prepare($sql);
  238.         $stmt->execute();
  239.         $result $stmt->fetchAll();
  240.         $fields = [];
  241.         $isset false;
  242.         foreach ($result as $field) {
  243.             $isset false;
  244.             if (!empty($field['category'])) {
  245.                 if (!$course->getCategory()) {
  246.                     continue;
  247.                 }
  248.                 if (!in_array($course->getCategory()->getId(), json_decode($field['category'], true))) {
  249.                     continue;
  250.                 } else {
  251.                     $field $this->createDescription($field'course');
  252.                     $isset true;
  253.                 }
  254.             }
  255.             if (!empty($field['course_type'])) {
  256.                 if (!$course->getType()) {
  257.                     continue;
  258.                 }
  259.                 if (!in_array($course->getType()->getId(), json_decode($field['course_type'], true))) {
  260.                     continue;
  261.                 } else {
  262.                     if (!$isset) {
  263.                         $field $this->createDescription($field'course');
  264.                         $isset true;
  265.                     }
  266.                 }
  267.             }
  268.             if (empty($field['category']) && empty($field['course_type']) && !empty($field['certificate'])) {
  269.                 if (!$isset$field $this->createDescription($field'certificate');
  270.             }
  271.             if (
  272.                 !empty($field['category']) ||
  273.                 !empty($field['course_type']) ||
  274.                 $field['certificate']
  275.             ) {
  276.                 $fields[] = $field;
  277.             }
  278.         }
  279.         return $this->render('course/edit.html.twig', [
  280.             'course' => $course,
  281.             'form' => $form->createView(),
  282.             'fields' => $fields,
  283.             'env' => $_ENV,
  284.         ]);
  285.     }
  286.     /**
  287.      * @Route("/{id}", name="course_delete", methods="DELETE", requirements={"id"="\d+"})
  288.      */
  289.     public function delete(Request $requestCourse $course): Response
  290.     {
  291.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  292.         if ($this->isCsrfTokenValid('delete' $course->getId(), $request->request->get('_token'))) {
  293.             $em $this->getDoctrine()->getManager();
  294.             $em->remove($course);
  295.             try {
  296.                 $em->flush();
  297.             } 
  298.             catch (\Exception $e
  299.             {
  300.                 $errorMessage $e->getMessage();
  301.                 if (str_contains($errorMessage'Integrity constraint violation'))
  302.                 {
  303.                 $this->addFlash('error''Der Kurs kann nicht gelöscht werden, weil er an anderer Stelle gebraucht wird.');
  304.        //         $this->addFlash('error', $errorMessage); 
  305.                 
  306.                 else 
  307.                 {
  308.                 $this->addFlash('error''Der Kurs kann nicht gelöscht werden, weil er an anderer Stelle gebraucht wird.'); 
  309.                 }
  310.                return $this->redirectToRoute('course_index');
  311.             }
  312.         $this->addFlash('notice''Kurs gelöscht');
  313.         }
  314.         return $this->redirectToRoute('course_index');
  315.     }
  316.     /**
  317.      * @Route("/multiple", name="course_delete-multiple", methods="DELETE")
  318.      */
  319.     public function deleteMultiple(
  320.         Request $request,
  321.         CourseRepository $courseRepo,
  322.         CartItemRepository $cartItemRepo,
  323.         WaitItemRepository $waitItemRepo,
  324.         OrderItemRepository $orderItemRepo
  325.     ): Response {
  326.         if ($this->isCsrfTokenValid('delete_courses'$request->request->get('_token'))) {
  327.             $em $this->getDoctrine()->getManager();
  328.             $deleteIds $request->request->get('delete');
  329.             foreach ($deleteIds as $id => $value) {
  330.                 if ($value) {
  331.                     $course $courseRepo->find($id);
  332.                     $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  333.                     $waitItems $waitItemRepo->findBy(['course' => $course]);
  334.                     foreach ($waitItems as $waitItem) {
  335.                         $em->remove($waitItem);
  336.                     }
  337.                     $cartItems $cartItemRepo->findBy(['course' => $course]);
  338.                     foreach ($cartItems as $cartItem) {
  339.                         $em->remove($cartItem);
  340.                     }
  341.                     $orderItems $orderItemRepo->findBy(['course' => $course]);
  342.                     foreach ($orderItems as $orderItem) {
  343.                         $orderItem->setCourseOccurrence(null);
  344.                     }
  345.                     $em->remove($course);
  346.                 }
  347.             }
  348.             try {
  349.                 $em->flush();
  350.             } catch (\Exception $e) {
  351.                 $errorMessage $e->getMessage();
  352.                 if (str_contains($errorMessage'Integrity constraint violation')){
  353.                 $this->addFlash('error''Der Kurs kann nicht gelöscht werden, weil er an anderer Stelle gebraucht wird.');
  354.        //         $this->addFlash('error', $errorMessage); 
  355.                 } else {
  356.                 $this->addFlash('error''Der Kurs kann nicht gelöscht werden, weil er an anderer Stelle gebraucht wird.'); 
  357.                 }
  358.                return $this->redirectToRoute('course_index');
  359.                
  360.             }
  361.             
  362.             $this->addFlash('notice'count($deleteIds) > 'Kurse gelöscht' 'Kurs gelöscht');
  363.         }
  364.         return $this->redirectToRoute('course_index');
  365.     }
  366.     /**
  367.      * @Route("/{id}/occurrences", name="course_occurrences", methods="GET", requirements={"id"="\d+"})
  368.      */
  369.     public function courseOccurrences(
  370.         Request $request,
  371.         Course $course,
  372.         CourseOccurrenceRepository $repo,
  373.         \App\Service\UiService $uiService
  374.     ): Response {
  375.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  376.         $order $uiService->getSortOrder('course-occurrences-listing');
  377.         $archive = !empty($request->get('archive'));
  378.         $occurrences $repo->findByCoursePaged(
  379.             $course,
  380.             self::LISTING_LIMIT,
  381.             $order['orderDirection'] ?? 'ASC',
  382.             $order['orderBy'] ?? 'title'
  383.         );
  384.         return $this->render('course/occurrences.html.twig', [
  385.             'uiService' => $uiService,
  386.             'course' => $course,
  387.             'occurrences' => $occurrences->getIterator(),
  388.             'total' => $occurrences->count(),
  389.             'pages' => ceil($occurrences->count() / self::LISTING_LIMIT),
  390.             'page' => 1,
  391.             'env' => $_ENV,
  392.             'archive' => $archive,
  393.         ]);
  394.     }
  395.     /**
  396.      * @Route("/{id}/occurrences/{page}/{orderby}/{order}/{search}", name="course_occurrences_listing", methods="GET", defaults={"search"="", "order"="desc", "orderby"="start"}, requirements={"id"="\d+"})
  397.      */
  398.     public function courseOccurrencesListing(
  399.         Request $request,
  400.         Course $course,
  401.         $page,
  402.         $orderby,
  403.         $order,
  404.         $search,
  405.         CourseOccurrenceRepository $repo,
  406.         \App\Service\UiService $uiService
  407.     ): Response {
  408.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  409.         $uiService->storeSortOrder('course-occurrences-listing'$orderby$order);
  410.         $occurrences $repo->findByCoursePaged($courseself::LISTING_LIMIT$order$orderby$page$search);
  411.         return $this->render('course/tabs/_occurrences_listing.html.twig', [
  412.             'course' => $course,
  413.             'occurrences' => $occurrences->getIterator(),
  414.             'total' => $occurrences->count(),
  415.             'pages' => ceil($occurrences->count() / self::LISTING_LIMIT),
  416.             'page' => $page,
  417.             'env' => $_ENV,
  418.         ]);
  419.     }
  420.     /**
  421.      * @Route("/{id}/images", name="course_images", methods="GET|POST", requirements={"id"="\d+"})
  422.      */
  423.     public function courseImages(Request $requestCourse $course)
  424.     {
  425.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  426.         $courseImages = new ArrayCollection();
  427.         foreach ($course->getImages() as $image) {
  428.             $courseImages->add($image);
  429.         }
  430.         $form $this->createForm(CourseImagesType::class, $course);
  431.         $form->handleRequest($request);
  432.         if ($form->isSubmitted() && $form->isValid()) {
  433.             $manager $this->getDoctrine()->getManager();
  434.             foreach ($courseImages as $image) {
  435.                 if (false === $course->getImages()->contains($image)) {
  436.                     $image->setCourse(null);
  437.                     $manager->remove($image);
  438.                 }
  439.             }
  440.             foreach ($course->getImages() as $key => $image) {
  441.                 if (empty($image->getOrderId())) {
  442.                     $image->setOrderId($key 1000);
  443.                 }
  444.             }
  445.             $image->setCreated(new \Datetime());
  446.             $manager->flush();
  447.             $this->addFlash('notice''Kursbilder gespeichert');
  448.             return $this->redirectToRoute('course_images', ['id' => $course->getId()]);
  449.         }
  450.         return $this->render('course/images.html.twig', [
  451.             'course' => $course,
  452.             'form' => $form->createView(),
  453.             'env' => $_ENV,
  454.         ]);
  455.     }
  456.     /**
  457.      * @Route("/{id}/invoices", name="course_invoices", methods="GET", requirements={"id"="\d+"})
  458.      */
  459.     public function courseInvoices(
  460.         Request $request,
  461.         Course $course,
  462.         OrderItemRepository $repo,
  463.         OrderService $orderService,
  464.         TagsPersonRepository  $tagsPersonRepository,
  465.     ) {
  466.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  467.         $orderItems $repo->findByCoursePaged($course);
  468.         /**
  469.          * The display logic of subscription courses is different, as there only one order exists per
  470.          * customer/participant, but they should appear in every following course occurrence until they cancel.
  471.          */
  472.         // if ($course->getCourseNature() === 'CourseSubscription') {
  473.         //     return $this->render('course/invoices-subscription.html.twig', [
  474.         //         'course' => $course,
  475.         //         'orderItems' => $orderItems->getIterator(),
  476.         //     ]);
  477.         // } else {
  478.         $archive = !empty($request->get('archive'));
  479.         if ($course->getCourseNature() === 'CourseSubscription') {
  480.             foreach ($orderItems as $orderItem) {
  481.                 $orderItem->isAfterCancelDate $orderService->isOrderItemOccurrenceAfterCancelDateByParticipant($this->getCurrentClient(), $orderItem);
  482.             }
  483.         }
  484.         return $this->render('course/invoices.html.twig', [
  485.             'tagsPerson' => $tagsPersonRepository->findAll(),
  486.             'course' => $course,
  487.             'orderItems' => $orderItems->getIterator(),
  488.             'archive' => $archive,
  489.         ]);
  490.         // }
  491.     }
  492.     /**
  493.      * @Route("/{id}/invoices/create", name="course_create_invoices", methods="POST", requirements={"id"="\d+"})
  494.      */
  495.     public function courseCreateInvoices(
  496.         Request $request,
  497.         Course $course,
  498.         OrderItemRepository $itemRepo,
  499.         InvoiceService $invoiceService
  500.     ) {
  501.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  502.         if ($this->isCsrfTokenValid('create_invoices'$request->request->get('_token'))) {
  503.             $em $this->getDoctrine()->getManager();
  504.             $createIds $request->request->get('create');
  505.             $count 0;
  506.             if (!empty($createIds)) {
  507.                 foreach ($createIds as $id => $value) {
  508.                     if ($value) {
  509.                         $orderItem $itemRepo->find($id);
  510.                         $results $invoiceService->createInvoiceFromOrderItem($orderItem);
  511.                         foreach ($results['attendees'] as $attendee) {
  512.                             $em->persist($attendee);
  513.                         }
  514.                         $em->persist($results['invoice']);
  515.                         $em->flush();
  516.                         $count++;
  517.                     }
  518.                 }
  519.                 $em->flush();
  520.             }
  521.             $this->addFlash('notice'$count . ($count === ' Rechnung' ' Rechnungen') . ' erstellt');
  522.         }
  523.         return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  524.     }
  525.     /**
  526.      * @Route("/{id}/invoices/merge-pdf", name="course_invoices_merge-pdf", methods="POST", requirements={"id"="\d+"})
  527.      */
  528.     public function courseMergePdf(
  529.         Request $request,
  530.         Course $course,
  531.         OrderItemRepository $repo,
  532.         PdfService $pdfService
  533.     ) {
  534.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  535.         if ($this->isCsrfTokenValid('create_invoices'$request->request->get('_token'))) {
  536.             $em $this->getDoctrine()->getManager();
  537.             $mergeIds $request->request->get('close');
  538.             if (!empty($mergeIds)) {
  539.                 $mergeInvoices = new ArrayCollection();
  540.                 foreach ($mergeIds as $id => $value) {
  541.                     if ($value) {
  542.                         $orderItem $repo->find($id);
  543.                         $order $orderItem->getOrder();
  544.                         foreach ($order->getInvoices() as $invoice) {
  545.                             if (!$mergeInvoices->contains($invoice)) {
  546.                                 $mergeInvoices->add($invoice);
  547.                             }
  548.                         }
  549.                     }
  550.                 }
  551.                 $pdf $pdfService->getMergedInvoicePdf($this->getCurrentClient(), $mergeInvoices->toArray());
  552.                 $pdf->Output('D''Rechnungen_' date('Y-m-d_H-i') . '.pdf');
  553.                 die;
  554.             } else {
  555.                 $this->addFlash('notice''Keine Rechnungen ausgewählt.');
  556.             }
  557.         }
  558.         return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  559.     }
  560.     /**
  561.      * @Route("/{id}/invoices/close", name="course_close_invoices", methods="POST", requirements={"id"="\d+"})
  562.      */
  563.     public function courseCloseInvoices(
  564.         Request $request,
  565.         Course $course,
  566.         InvoiceItemRepository $repo,
  567.         ConfigurationService $configService,
  568.         MailerService $mailer,
  569.         PdfService $pdfService,
  570.         EmailHistoryService $emailHistoryService
  571.     ) {
  572.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  573.         if ($this->isCsrfTokenValid('create_invoices'$request->request->get('_token'))) {
  574.             $em $this->getDoctrine()->getManager();
  575.             $closeIds $request->request->get('close');
  576.             $count 0;
  577.             if (!empty($closeIds)) {
  578.                 foreach ($closeIds as $id => $value) {
  579.                     if ($value) {
  580.                         $invoiceItem $repo->findOneBy(['orderItem' => $id]);
  581.                         $invoice $invoiceItem->getInvoice();
  582.                         if ($invoice->getStatus() == Invoice::STATUS_DRAFT) {
  583.                             $pdf $pdfService->getInvoicePdf($this->getCurrentClient(), $invoice);
  584.                             $sentMessage $mailer->sendInvoiceEmail(
  585.                                 $invoice,
  586.                                 'Rechnung-' $invoice->getNumber() . '.pdf',
  587.                                 $pdf->Output('S''Rechnung-' $invoice->getNumber() . '.pdf')
  588.                             );
  589.                             $outputfile $this->generateUniqueFileName() . '.pdf';
  590.                             $outputpath $this->getParameter('attachment_directory') . '/' $outputfile;
  591.                             $pdf->Output('F'$outputpath);
  592.                             $emailHistoryService->saveProtocolEntryFromInvoiceMessage(
  593.                                 $invoice,
  594.                                 $sentMessage['sender'],
  595.                                 $sentMessage['subject'],
  596.                                 $sentMessage['message'],
  597.                                 $outputfile,
  598.                                 'Rechnung-' $invoice->getNumber() . '.pdf'
  599.                             );
  600.                             if ($invoice->getStatus() != Invoice::STATUS_CLOSED) {
  601.                                 if ($invoice->isPaymentDebit()) {
  602.                                     $invoice->setStatus(Invoice::STATUS_DEBIT_PENDING);
  603.                                 } else {
  604.                                     $invoice->setStatus(Invoice::STATUS_CLOSED);
  605.                                 }
  606.                             }
  607.                             $count++;
  608.                         } else {
  609.                             // Send invoice again
  610.                             $pdf $pdfService->getInvoicePdf($this->getCurrentClient(), $invoice);
  611.                             $sentMessage $mailer->sendInvoiceEmail(
  612.                                 $invoice,
  613.                                 'Rechnung-' $invoice->getNumber() . '.pdf',
  614.                                 $pdf->Output('S''Rechnung-' $invoice->getNumber() . '.pdf')
  615.                             );
  616.                             $count++;
  617.                         }
  618.                         //Update the order status
  619.                         $newOrderState $invoice->getOrder()->setStatus(Order::STATUS_DONE);
  620.                         $em->persist($newOrderState);
  621.                         $em->flush();
  622.                     }
  623.                 }
  624.             }
  625.             $this->addFlash('notice'$count . ($count === ' Rechnung' ' Rechnungen') . ' versendet');
  626.         }
  627.         return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  628.     }
  629.     /**
  630.      * @Route("/{id}/invoices/close-sepa/{all}", name="course_close_sepa-invoices", defaults={"all"="false"},methods="POST", requirements={"id"="\d+"})
  631.      */
  632.     public function courseCloseSepaInvoices(
  633.         Request $request,
  634.         Course $course,
  635.         $all false,
  636.         OrderRepository $repo,
  637.         OrderItemRepository $itemRepo,
  638.         ConfigurationService $configService,
  639.         SepaXmlService $sepaXmlService
  640.     ) {
  641.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  642.         if ($this->isCsrfTokenValid('create_invoices'$request->request->get('_token'))) {
  643.             $em $this->getDoctrine()->getManager();
  644.             $closeIds $request->request->get('close');
  645.             $invoicesToExport = new ArrayCollection();
  646.             if ($all) {
  647.                 $orderItems $itemRepo->findByCoursePaged($course);
  648.                 foreach ($orderItems as $orderItem) {
  649.                     $order $orderItem->getOrder();
  650.                     foreach ($order->getInvoices() as $invoice) {
  651.                         if (
  652.                             $invoice->containsCourse($course) &&
  653.                             !$invoicesToExport->contains($invoice) &&
  654.                             $invoice->isPaymentDebit()
  655.                         ) {
  656.                             $invoicesToExport->add($invoice);
  657.                             $invoice->setStatus(Invoice::STATUS_CLOSED);
  658.                             if (!$order->getCustomer()->getDebitActive()) {
  659.                                 $order->getCustomer()->setDebitActive(true);
  660.                                 $invoice->setIsNewSepaMandate(true);
  661.                             }
  662.                         }
  663.                         if (!empty($_ENV['SEPAEXPORT_PAYED'])) {
  664.                             $restsumme $invoice->getMissingSum();
  665.                             if ($restsumme != 0) {
  666.                                 $invoicePayment = new InvoicePayment();
  667.                                 $invoicePayment->setInvoice($invoice);
  668.                                 $invoicePayment->setPayedDate(new \DateTime());
  669.                                 $invoicePayment->setSum($invoice->getMissingSum());
  670.                                 $invoice->setPaymentStatus(Invoice::FULLY_PAID);
  671.                                 $invoice->setExportStatus(Invoice::EXPORTED);
  672.                                 $em $this->getDoctrine()->getManager();
  673.                                 $em->persist($invoicePayment);
  674.                             }
  675.                             $invoice->setPaymentStatus(Invoice::FULLY_PAID);
  676.                             $invoice->setExportStatus(Invoice::EXPORTED);
  677.                             $em->persist($invoice);
  678.                             $em->flush();
  679.                         }
  680.                     }
  681.                 }
  682.             } elseif (!empty($closeIds)) {
  683.                 foreach ($closeIds as $id => $value) {
  684.                     if ($value) {
  685.                         $orderItem $itemRepo->find($id);
  686.                         $order $orderItem->getOrder();
  687.                         foreach ($order->getInvoices() as $invoice) {
  688.                             if (
  689.                                 $invoice->containsCourse($course) &&
  690.                                 !$invoicesToExport->contains($invoice) &&
  691.                                 $invoice->isPaymentDebit()
  692.                             ) {
  693.                                 $invoicesToExport->add($invoice);
  694.                                 $invoice->setStatus(Invoice::STATUS_CLOSED);
  695.                                 if (!$order->getCustomer()->getDebitActive()) {
  696.                                     $order->getCustomer()->setDebitActive(true);
  697.                                     $invoice->setIsNewSepaMandate(true);
  698.                                 }
  699.                             }
  700.                         }
  701.                         if (!empty($_ENV['SEPAEXPORT_PAYED'])) {
  702.                             $restsumme $invoice->getMissingSum();
  703.                             if ($restsumme != 0) {
  704.                                 $invoicePayment = new InvoicePayment();
  705.                                 $invoicePayment->setInvoice($invoice);
  706.                                 $invoicePayment->setPayedDate(new \DateTime());
  707.                                 $invoicePayment->setSum($invoice->getMissingSum());
  708.                                 $invoice->setExportStatus(Invoice::EXPORTED);
  709.                                 $em $this->getDoctrine()->getManager();
  710.                                 $em->persist($invoicePayment);
  711.                             }
  712.                             $invoice->setPaymentStatus(Invoice::FULLY_PAID);
  713.                             $invoice->setExportStatus(Invoice::EXPORTED);
  714.                             $em->persist($invoice);
  715.                             $em->flush();
  716.                         }
  717.                     }
  718.                 }
  719.             } else {
  720.                 $this->addFlash('warning''Es wurden keine Rechnungen zum Export ausgewählt.');
  721.                 return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  722.             }
  723.             // Check invoices for past due dates
  724.             foreach ($invoicesToExport as $invoice) {
  725.                 if (new \DateTime() > $invoice->getDueDate()) {
  726.                     $this->addFlash('warning''Mindestens eine Rechnung enthält ein Zahlungsziel in der Vergangenheit.');
  727.                     // return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  728.                 }
  729.             }
  730.             if (count($invoicesToExport) > 0) {
  731.                 $config $configService->getSepaXmlConfigByClient($this->getCurrentClient());
  732.                 try {
  733.                     $xml $sepaXmlService->getSepaXmlMultiple($this->getCurrentClient(), $config$invoicesToExport);
  734.                 } catch (ServiceException $e) {
  735.                     $this->addFlash('error'$e->getMessage());
  736.                     return $this->redirectToRoute('invoice_index');
  737.                 }
  738.                 $em->flush();
  739.                 $response = new Response($xml);
  740.                 $response->headers->set('Content-Type''text/xml');
  741.                 $response->headers->set('Content-disposition''attachment; filename="SEPA-' date('Ymd-His') . '.xml"');
  742.                 return $response;
  743.             }
  744.             $this->addFlash('error''Mindestens eine Rechnung enthält Fehler.');
  745.             return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  746.         }
  747.         $this->addFlash('error''Der Sicherheits-Token ist ungültig. Bitte versuchen Sie es noch einmal.');
  748.         return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  749.     }
  750.     /**
  751.      * @Route("/{id}/invoices/close-sepa/", name="course_close_sepa-invoice_selected", methods="POST", requirements={"id"="\d+"})
  752.      */
  753.     public function courseCloseSepaInvoiceSelected(
  754.         Request $request,
  755.         Course $course,
  756.         OrderItemRepository $itemRepo,
  757.         ConfigurationService $configService,
  758.         SepaXmlService $sepaXmlService
  759.     ) {
  760.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  761.         if ($this->isCsrfTokenValid('create_invoices'$request->request->get('_token'))) {
  762.             $em $this->getDoctrine()->getManager();
  763.             $closeIds $request->request->get('close');
  764.             $invoicesToExport = new ArrayCollection();
  765.         if (!empty($closeIds)) {
  766.                 foreach ($closeIds as $id => $value) {
  767.                     if ($value) {
  768.                         $orderItem $itemRepo->find($id);
  769.                         $order $orderItem->getOrder();
  770.                         foreach ($order->getInvoices() as $invoice) {
  771.                             if (
  772.                                 $invoice->containsCourse($course) &&
  773.                                 !$invoicesToExport->contains($invoice) &&
  774.                                 $invoice->isPaymentDebit()
  775.                             ) {
  776.                                 $invoicesToExport->add($invoice);
  777.                                 $invoice->setStatus(Invoice::STATUS_CLOSED);
  778.                                 if (!$order->getCustomer()->getDebitActive()) {
  779.                                     $order->getCustomer()->setDebitActive(true);
  780.                                     $invoice->setIsNewSepaMandate(true);
  781.                                 }
  782.                             }
  783.                         }
  784.                         if (!empty($_ENV['SEPAEXPORT_PAYED'])) {
  785.                             $restsumme $invoice->getMissingSum();
  786.                             if ($restsumme != 0) {
  787.                                 $invoicePayment = new InvoicePayment();
  788.                                 $invoicePayment->setInvoice($invoice);
  789.                                 $invoicePayment->setPayedDate(new \DateTime());
  790.                                 $invoicePayment->setSum($invoice->getMissingSum());
  791.                                 $invoice->setExportStatus(Invoice::EXPORTED);
  792.                                 $em $this->getDoctrine()->getManager();
  793.                                 $em->persist($invoicePayment);
  794.                             }
  795.                             $invoice->setPaymentStatus(Invoice::FULLY_PAID);
  796.                             $invoice->setExportStatus(Invoice::EXPORTED);
  797.                             $em->persist($invoice);
  798.                             $em->flush();
  799.                         }
  800.                     }
  801.                 }
  802.             } else {
  803.                 $this->addFlash('warning''Es wurden keine Rechnungen zum Export ausgewählt.');
  804.                 return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  805.             }
  806.             // Check invoices for past due dates
  807.             foreach ($invoicesToExport as $invoice) {
  808.                 if (new \DateTime() > $invoice->getDueDate()) {
  809.                    
  810.                     $this->addFlash('warning''Mindestens eine Rechnung enthält ein Zahlungsziel in der Vergangenheit.');
  811.                     // return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  812.                 }
  813.             }
  814.             if (count($invoicesToExport) > 0) {
  815.                 $config $configService->getSepaXmlConfigByClient($this->getCurrentClient());
  816.                 try {
  817.                     $xml $sepaXmlService->getSepaXmlMultiple($this->getCurrentClient(), $config$invoicesToExport);
  818.                 } catch (ServiceException $e) {
  819.                     $this->addFlash('error'$e->getMessage());
  820.                     return $this->redirectToRoute('invoice_index');
  821.                 }
  822.                 $em->flush();
  823.                 $response = new Response($xml);
  824.                 $response->headers->set('Content-Type''text/xml');
  825.                 $response->headers->set('Content-disposition''attachment; filename="SEPA-' date('Ymd-His') . '.xml"');
  826.                 return $response;
  827.             }
  828.             $this->addFlash('error''Mindestens eine Rechnung enthält Fehler.');
  829.             return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  830.         }
  831.         $this->addFlash('error''Der Sicherheits-Token ist ungültig. Bitte versuchen Sie es noch einmal.');
  832.         return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
  833.     }
  834.     /**
  835.      * @Route("/{id}/participants", name="course_participants", methods="GET", requirements={"id"="\d+"})
  836.      */
  837.     public function courseParticipants(
  838.         Request $request,
  839.         Course $course,
  840.         OrderItemRepository $repo,
  841.         OrderService $orderService,
  842.         TagsPersonRepository  $tagsPersonRepository,
  843.     ) {
  844.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  845.         $orderItems $repo->findByCoursePaged($course);
  846.       
  847.         $archive = !empty($request->get('archive'));
  848.         if ($course->getCourseNature() === 'CourseSubscription') {
  849.             foreach ($orderItems as $orderItem) {
  850.                 foreach ($orderItem->getParticipants() as $participant) {
  851.                     $participant->isAfterCancelDate $orderService->isOrderItemOccurrenceAfterCancelDateByParticipant($this->getCurrentClient(), $orderItem$participant->getId());
  852.                     $participant->cancelDate $orderService->getCancelDateForParticipantInCourse($this->getCurrentClient(), $participant);
  853.                 }
  854.             }
  855.         }
  856.         return $this->render('course/participants.html.twig', [
  857.             'tagsPerson' => $tagsPersonRepository->findAll(),
  858.             'env' => $_ENV,
  859.             'course' => $course,
  860.             'orderItems' => $orderItems->getIterator(),
  861.             'showCertificatesLink' => !empty($_ENV['CERTIFICATES_ENABLED']),
  862.             'archive' => $archive,
  863.         ]);
  864.       
  865.     }
  866.     /**
  867.      * @Route("/{id}/participants-pdf/{page}/{orderby}/{order}", name="course_participants_pdf", methods="GET", requirements={"id"="\d+"})
  868.      * @IsGranted("ROLE_SPEAKER")
  869.      */
  870.     public function courseParticipantsPdf(
  871.         Request $request,
  872.         CourseOccurrence $courseOccurrence,
  873.         OrderItemRepository $repo,
  874.         PdfService $pdfService,
  875.         OrderService $orderService,
  876.         $page 1,
  877.         $orderby 'customerLastname',
  878.         $order 'asc'
  879.     ) {
  880.         //    $this->denyAccessUnlessGranted('client_allowed', $courseOccurrence);
  881.         $this->denyAccessUnlessGranted('ROLE_SPEAKER'$courseOccurrence);
  882.         $orderItems $repo->findByCourseOccurrence($courseOccurrence$orderby$order);
  883.         if ($courseOccurrence->getCourse()->getCourseNature() === 'CourseSubscription') {
  884.             foreach ($orderItems as $orderItem) {
  885.                 foreach ($orderItem->getParticipants() as $participant) {
  886.                     $participant->isAfterCancelDate $orderService->isOrderItemOccurrenceAfterCancelDateByParticipant($this->getCurrentClient(), $orderItem$participant->getId());
  887.                 }
  888.             }
  889.         }
  890.         $pdf $pdfService->getParticipantsPdf($this->getCurrentClient(), $courseOccurrence$orderItems);
  891.         $pdf->Output('D''Teilnehmerliste-' $courseOccurrence->getStart()->format('Y-m-d') . '.pdf');
  892.         exit();
  893.     }
  894.     /**
  895.      * @Route("/participant/{id}/certificateemail", name="course_participants_certificate_email", methods="GET", requirements={"id"="\d+","downlaod"="\d+"})
  896.      */
  897.     public function courseParticipantsCertificateEmail(
  898.         Request $request,
  899.         $id,
  900.         ConfigurationService $configService,
  901.         \App\Entity\OrderItemPerson $orderItemPerson,
  902.         TextblocksRepository $textblocksRepository,
  903.         ParameterBagInterface $params,
  904.         CourseDataRepository $courseDataRepository,
  905.         MailerService $mailer,
  906.         \Doctrine\DBAL\Driver\Connection $connection,
  907.         EmailHistoryService $emailHistoryService,
  908.         OrderItemRepository $repo
  909.     ): Response {
  910.         $participantId $id;
  911.         $download $_GET['download'];
  912.         $viewTemplate $_ENV['ZERTIFIKAT'] ?? 'Default';
  913.         $viewFolder '/templates/course/certificates/';
  914.         $viewFile $viewTemplate '/Certificate.html.twig';
  915.       
  916.         if (file_exists($params->get('kernel.project_dir') . $viewFolder dirname($viewFile) . '/data.xml')) {
  917.             $xml simplexml_load_file($params->get('kernel.project_dir') . $viewFolder dirname($viewFile) . '/data.xml''SimpleXMLElement'LIBXML_NOCDATA);
  918.             $json json_encode($xml);
  919.             $data json_decode($jsontrue);
  920.         }
  921.         try {
  922.             $course $orderItemPerson->getOrderItem()->getCourseOccurrence()->getCourse();
  923.             $person $orderItemPerson->getPerson();
  924.             $customer $orderItemPerson->getOrderItem()->getOrder()->getCustomer();
  925.             $courseFields $courseDataRepository->findBy([
  926.                 'course' => $course,
  927.                 'client' => $this->getCurrentClient()
  928.             ]);
  929.             $orderItems $repo->findByCoursePaged($course);
  930.             //proof if an certificate isset
  931.             $certificateIsset false;
  932.             foreach ($courseFields as $field) {
  933.                 if (!empty($field->getValueText())
  934.                 && $field->getCourseField()->getCertificate()
  935.                 ) {
  936.                     $certificateIsset true;
  937.                    if ($field->getCourseField()->getName() == 'Certificate_Template')
  938.                    {
  939.                     if ($field->getValueText()){
  940.                     $viewTemplate strip_tags($field->getValueText());
  941.                     }
  942.                 }
  943.                 }
  944.             }
  945.             $textBlocks $textblocksRepository->findALL();
  946.             $fields $courseDataRepository->getFieldsWithCourseId($course->getId());
  947. $speakers $orderItemPerson->getOrderItem()->getCourseOccurrence()->getSpeakers();
  948.             $response $this->render('course/certificates/' $viewTemplate '/Certificate.html.twig', [
  949.                 'participantId' => $participantId,
  950.                 'fields' => $fields ?? [],
  951.                 'textblocks' => $textBlocks ?? [],
  952.                 'data' => $data ?? [],
  953.                 'folder' => '..' $viewFolder dirname($viewFile) . '/',
  954.                 'person' => $person,
  955.                 'speakers' => $speakers ?? [],
  956.                 'course' => $course,
  957.                 'courseFields' => $courseFields,
  958.                 'orderItems' => $orderItems,
  959.                 'certificateIsset' => $certificateIsset,
  960.                 'occurence' => $orderItemPerson->getOrderItem()->getCourseOccurrence(),
  961.             ]);
  962.         } catch (\Twig\Error\LoaderError $exception) {
  963.             $this->addFlash('error''Das Zertifikat konnte nicht erstellt werden (Ordner: ' $viewFolder ').');
  964.             return $this->redirectToRoute('course_participants', ['id' => $orderItemPerson->getOrderItem()->getCourseOccurrence()->getCourse()->getId()]);
  965.         } catch (\InvalidArgumentException $exception) {
  966.             $this->addFlash('error''Das Zertifikat konnte nicht erstellt werden (Template: ' $viewFile ').');
  967.             return $this->redirectToRoute('course_participants', ['id' => $orderItemPerson->getOrderItem()->getCourseOccurrence()->getCourse()->getId()]);
  968.         }
  969.         $source $response->getContent();
  970.         // Generate filename
  971.         $filename $course->getNumber() . '-' $person->getLastname() . '-' $person->getFirstname();
  972.         $filename mb_strtolower($filename);
  973.         $tr = [
  974.             'ä' => 'ae',
  975.             'ü' => 'ue',
  976.             'ö' => 'oe',
  977.             'ß' => 'ss',
  978.         ];
  979.         $filename strtr($filename$tr);
  980.         $filename preg_replace('#\s#''-'$filename);
  981.         $filename preg_replace('#[^a-z0-9\-]#'''$filename);
  982.         $filename preg_replace('#[\-]{2,}#i''-'$filename);
  983.         $filename .= '.pdf';
  984.         // Generate pdf
  985.         $html2pdf = new \Spipu\Html2Pdf\Html2Pdf('P''A4''de'true'UTF-8', [251000]);
  986.         $html2pdf->setDefaultFont('DejaVuSans');
  987.         $html2pdf->writeHTML($source);
  988.         if ($download == 'ja') {
  989.             $html2pdf->output($filename'D');
  990.         }
  991.         $outputpath $this->getParameter('attachment_directory') . '/' $filename;
  992.         if ($download == 'nein') {
  993.             $html2pdf->output($outputpath'F');
  994.         }
  995.         $client $this->getCurrentClient();
  996.         $sender $client->getEmail();
  997.         $recipient $person->getContactEmail() ? $person->getContactEmail() :  $orderItemPerson->getEmail();
  998.         // Fetch subject und message from textblocks
  999.         $sql 'SELECT * FROM textblocks WHERE position = "certificate" ';
  1000.         $result $connection->fetchAll($sql);
  1001.         
  1002.         $zertifikat = !empty($_ENV['ZERTIFIKAT']) ? $_ENV['ZERTIFIKAT'] : 'Zertifikat';
  1003.         $subject 'Ihr '$zertifikat ' wurde erstellt';
  1004.         $message 'Lieber Teilnehmer<p>Für Sie wurde das '$zertifikat ' erstellt.</p><p>Ihr Team';
  1005.         $historyTitle $zertifikat 'erstellt';
  1006.         if ($download == 'nein') {
  1007.             foreach ($result as $value) {
  1008.                 if ($value['position'] = 'cetrificate') {
  1009.                     $subject $value['subject'];
  1010.                     $message $value['message'];
  1011.                 }
  1012.             }
  1013.             $mailer->sendCertificateMessage(
  1014.                 $client,
  1015.                 $sender,
  1016.                 $subject ' ' $course->getTitle(),
  1017.                 $message '<p>Anhang: ' $filename,
  1018.                 $recipient,
  1019.                 $html2pdf->output($filename'S'),
  1020.                 $filename
  1021.             );
  1022.         }
  1023.         //$client, $recipient, $sender, $subject, $message, $filename
  1024.         $emailHistoryService->saveProtocolEntriesFromEmailCertificate(
  1025.             $this->getCurrentClient(),
  1026.             $recipient,
  1027.             $sender,
  1028.             $subject  ' ' $course->getTitle(),
  1029.             $message,
  1030.             $filename,
  1031.             $historyTitle,
  1032.             $customer,
  1033.             $download
  1034.         );
  1035.         
  1036.         
  1037.         if ($download == 'nein') {
  1038.             $this->addFlash('notice''Das '$zertifikat ' wurde an ' $recipient ' versendet. ');
  1039.         }
  1040.         if ($download == 'ja') {
  1041.             $this->addFlash('notice''Das '$zertifikat ' wurde erstellt. ');
  1042.         }
  1043.         return $this->redirectToRoute('course_participants', ['id' => $course->getId()]);
  1044.     }
  1045. /**
  1046.      * @Route("/{id}/presences", name="course_presences", methods="GET", requirements={"id"="\d+"})
  1047.      */
  1048.     public function coursePresences(
  1049.         Request $request,
  1050.         Course $course,
  1051.         OrderItemRepository $repo,
  1052.         OrderService $orderService,
  1053.         CourseOccurrenceRepository $occurrencesrepo,
  1054.         TagsPersonRepository  $tagsPersonRepository,
  1055.         \App\Service\UiService $uiService,
  1056.         PresenceRepository $presenceRepository,
  1057.     ) {
  1058.         $this->denyAccessUnlessGranted('ROLE_SPEAKER'$course);
  1059.         $orderItems $repo->findByCoursePaged($course);
  1060.         $order $uiService->getSortOrder('course-occurrences-listing');
  1061.       
  1062.         $archive = !empty($request->get('archive'));
  1063.         if ($course->getCourseNature() === 'CourseSubscription') {
  1064.             foreach ($orderItems as $orderItem) {
  1065.                 foreach ($orderItem->getParticipants() as $participant) {
  1066.                     $participant->isAfterCancelDate $orderService->isOrderItemOccurrenceAfterCancelDateByParticipant($this->getCurrentClient(), $orderItem$participant->getId());
  1067.                     $participant->cancelDate $orderService->getCancelDateForParticipantInCourse($this->getCurrentClient(), $participant);
  1068.                 }
  1069.             }
  1070.         }
  1071.         $occurrences $occurrencesrepo->findByCoursePaged(
  1072.             $course,
  1073.             self::LISTING_LIMIT,
  1074.             $order['orderDirection'] ?? 'ASC',
  1075.             $order['orderBy'] ?? 'title'
  1076.         );
  1077.         return $this->render('course/presences.html.twig', [
  1078.             'presences' => $presenceRepository->findAll(),
  1079.             'uiService' => $uiService,
  1080.             'tagsPerson' => $tagsPersonRepository->findAll(),
  1081.             'env' => $_ENV,
  1082.             'course' => $course,
  1083.             'occurrences' => $occurrences->getIterator(), 
  1084.             'total' => $occurrences->count(),
  1085.             'pages' => ceil($occurrences->count() / self::LISTING_LIMIT),
  1086.             'page' => 1,
  1087.             'orderItems' => $orderItems->getIterator(),
  1088.             'showCertificatesLink' => !empty($_ENV['CERTIFICATES_ENABLED']),
  1089.             'archive' => $archive,
  1090.         ]);
  1091.         
  1092.     }
  1093.     private $managerRegistry;
  1094.     public function __construct(ManagerRegistry $managerRegistry)
  1095.     {
  1096.         $this->managerRegistry $managerRegistry->getManager();
  1097.     }
  1098.     /**
  1099.      * @Route("/coursepresence/{id}/add/{courseOccurrence}/{participant}", name="course_presence_add", methods="GET|POST")
  1100.      */
  1101.                         
  1102.      public function savePresenseNew(
  1103.         $id,
  1104.         $courseOccurrence,
  1105.         $participant,
  1106.         CourseOccurrenceTimeRepository $occurrenceTimeRepository,
  1107.         CourseOccurrenceRepository  $occurrenceRepository,
  1108.         PersonRepository $personRepository,
  1109.          )
  1110.        {
  1111.         $occurrenceTime $occurrenceTimeRepository->find($id);
  1112.         $occurrence $occurrenceRepository->find($courseOccurrence);
  1113.         $user $this->getCurrentUser();
  1114.         $person $personRepository->find($participant);
  1115.            $newpresence = new Presence();
  1116.            
  1117.            $newpresence->setOccurrence($occurrence);
  1118.            $newpresence->setOccurrenceTime($occurrenceTime);
  1119.            $newpresence->setUser($user);
  1120.            $newpresence->setPerson($person);
  1121.            $newpresence->setPresence('1');
  1122.            $newpresence->setCreated(new \Datetime());
  1123.            $newpresence->setClient($this->getCurrentClient());
  1124.            $this->managerRegistry->persist($newpresence);
  1125.             $this->managerRegistry->flush();
  1126.            
  1127.             return $this->json([
  1128.                 'success' => "Die Anwesenheit wurde eingetragen.",
  1129.                 'presence' => true,
  1130.             ]);
  1131.        }
  1132.      /**
  1133.      * @Route("/coursepresence/{id}/delete", name="course_presence_delete", methods="GET|POST")
  1134.      */
  1135.                         
  1136.      public function deletePresense(
  1137.         $id,
  1138.         PresenceRepository $presenceRepository,
  1139.         
  1140.                ): Response
  1141.        {
  1142.         $presence $presenceRepository->find($id);  
  1143.       // $presenceRepository->remove($presenceremove);
  1144.         $presence->setPresence('0');
  1145.         $presence->setModified(new \Datetime());
  1146.          $this->managerRegistry->persist($presence);
  1147.          $this->managerRegistry->flush();
  1148.            
  1149.             return $this->json([
  1150.                 'success' => "Die Anwesenheit wurde ausgetragen.",
  1151.                 'presence' => true,
  1152.             ]);
  1153.        }
  1154.      /**
  1155.      * @Route("/coursepresence/{id}/participantspresenceexport", name="course_participants_presences_export", methods="GET", requirements={"id"="\d+"})
  1156.      * @IsGranted("ROLE_SPEAKER")
  1157.      */
  1158.     public function courseParticipantsPresencesExport(
  1159.         Request $request,
  1160.              
  1161.         CourseOccurrence $courseOccurrence,
  1162.         OrderItemRepository $repo,
  1163.         PresenceRepository $presenceRepository,
  1164.         CourseOccurrenceTimeRepository $occurrenceTimeRepository,
  1165.         CourseOccurrenceRepository  $occurrenceRepository,
  1166.        
  1167.         $orderby 'customerLastname',
  1168.         $order 'asc'
  1169.     ) {
  1170.        $this->denyAccessUnlessGranted('ROLE_SPEAKER'$courseOccurrence);
  1171.         $orderItems $repo->findByCourseOccurrence($courseOccurrence$orderby$order);
  1172.          $course $courseOccurrence->getCourse()->getId();
  1173.          $orderItems $repo->findByCourseOccurrence($courseOccurrence$orderby$order);
  1174.  
  1175.          $response $this->render('person/export-participants-presences.csv.twig', [
  1176.             'presences' => $presenceRepository->findByOccurrence($courseOccurrence),
  1177.             'course' => $course,
  1178.              'occurrence' => $courseOccurrence
  1179.             'orderItems' => $orderItems,
  1180.           
  1181.         ]);
  1182.         $response->setStatusCode(200);
  1183.         $response->headers->set('Content-Type''text/csv; charset=utf-8');
  1184.        
  1185.         $response->headers->set('Content-Disposition''attachment; filename="Anwesenheit_Kurs.csv"');
  1186.         
  1187.         return $response;
  1188.         
  1189.     }
  1190.      /**
  1191.      * @Route("/coursepresence/{id}/exportcourseparticipants", name="export_course_participants", methods="GET", requirements={"id"="\d+"})
  1192.      * @IsGranted("ROLE_SPEAKER")
  1193.      */
  1194.     public function courseParticipantsExport(
  1195.         Request $request,
  1196.         CourseOccurrence $courseOccurrence,
  1197.         OrderItemRepository $repo,
  1198.         $orderby 'customerLastname',
  1199.         $order 'asc'
  1200.     ) {
  1201.        $this->denyAccessUnlessGranted('ROLE_SPEAKER'$courseOccurrence);
  1202.        
  1203.        $header $request->get('header'false); // Holen Sie den Wert von 'header'
  1204.     // Wenn 'header' true ist, setzen Sie ihn auf 1
  1205.     if ($header) {
  1206.         $header '1';
  1207.     } else
  1208.     { $header '0';}
  1209.          $course $courseOccurrence->getCourse()->getId();
  1210.          $orderItems $repo->findByCourseOccurrence($courseOccurrence$orderby$order);
  1211.     
  1212.          
  1213.          // Rendern des CSV-Inhalts als String (UTF-8)
  1214.            $csvContent $this->renderView('person/export-course-participants.csv.twig', [
  1215.            
  1216.             'header' => $header,
  1217.             'course' => $course,
  1218.             'occurrence' => $courseOccurrence
  1219.             'orderItems' => $orderItems,
  1220.             ]);
  1221.           // Konvertiere den CSV-Inhalt in ISO-8859-1
  1222.           $encodedCsvContent mb_convert_encoding($csvContent'ISO-8859-1''UTF-8');
  1223.              // Erstelle eine Antwort mit dem konvertierten Inhalt
  1224.              $response = new Response($encodedCsvContent); 
  1225.             $response->setStatusCode(200);
  1226.             $response->headers->set('Content-Type''text/csv; charset=ISO-8859-1');
  1227.     //        $response->headers->set('Content-Type', 'text/csv; charset=utf-8');
  1228.         $startDate $courseOccurrence->getStart();
  1229.         $formattedDate $startDate->format('d.m.y');
  1230.         // Konstruktion des Dateinamens
  1231.         $courseTitle $courseOccurrence->getCourse()->getTitle();
  1232.         $fileName 'Kurs-Teilnehmer-' $courseTitle '-' $formattedDate '.csv';
  1233.         // Setzen des Content-Disposition-Headers
  1234.         $response->headers->set('Content-Disposition''attachment; filename="' $fileName '"');
  1235.         return $response;
  1236.         
  1237.         
  1238.     }
  1239.     /**
  1240.      * @Route("/{id}/reservations", name="course_reservations", methods="GET", requirements={"id"="\d+"})
  1241.      */
  1242.     public function courseReservations(
  1243.         Request $request,
  1244.         Course $course,
  1245.         WaitItemRepository $repo,
  1246.         TagsPersonRepository  $tagsPersonRepository,
  1247.     ) {
  1248.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  1249.         $waitItems $repo->findByCoursePaged($course);
  1250.         return $this->render('course/reservations.html.twig', [
  1251.             'course' => $course,
  1252.             'waitItems' => $waitItems->getIterator(),
  1253.             'tagsPerson' => $tagsPersonRepository->findAll(),
  1254.         ]);
  1255.     }
  1256.     /**
  1257.      * @Route("/waititem/{id}/delete", name="waititem_delete", methods="GET|POST")
  1258.      */
  1259.     public function deleteWaitItem($id,  
  1260.    
  1261.     WaitItemRepository $waitItemRepository,
  1262.     TagsPersonRepository  $tagsPersonRepository,
  1263.     EntityManagerInterface $entityManager): Response
  1264.     {
  1265.         $waitItem $waitItemRepository->find($id);
  1266.         
  1267.         $course $waitItem->getCourseOccurrence()->getCourse();
  1268.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  1269.         $waitItems $waitItemRepository->findByCoursePaged($course);
  1270.         if (!$waitItem) {
  1271.             throw $this->createNotFoundException('WaitItem not found');
  1272.         }
  1273.         $entityManager->remove($waitItem);
  1274.         $entityManager->flush();
  1275.         $this->addFlash('success''WaitItem deleted successfully');
  1276.         return $this->render('course/reservations.html.twig', [
  1277.             'course' => $course,
  1278.             'waitItems' => $waitItems->getIterator(),
  1279.             'tagsPerson' => $tagsPersonRepository->findAll(),
  1280.         ]);
  1281.     }
  1282.     /**
  1283.      * @Route("/{id}/reservations/move", name="course_reservations_move", methods="POST", requirements={"id"="\d+"})
  1284.      */
  1285.     public function moveCourseReservations(
  1286.         Request $request,
  1287.         Course $course,
  1288.         WaitItemRepository $repo
  1289.     ): Response {
  1290.         $this->denyAccessUnlessGranted('ROLE_MANAGER'$course);
  1291.         $em $this->getDoctrine()->getManager();
  1292.         $moveIds $request->request->get('item');
  1293.         foreach ($moveIds as $id => $value) {
  1294.             if ($value) {
  1295.                 $waitItem $repo->find($value);
  1296.                 $orderItem OrderItem::createFromWaitItem($waitItem);
  1297.                 $participants $waitItem->getParticipants();
  1298.                 foreach ($participants as $participant) {
  1299.                     if ($participant->getPerson()->getId() === $id) {
  1300.                         $participant->setWaitItem(null);
  1301.                         $participant->setOrderItem($orderItem);
  1302.                         $orderItem->setQuantity($orderItem->getQuantity() + 1);
  1303.                         $waitItem->setQuantity($waitItem->getQuantity() - 1);
  1304.                         break;
  1305.                     }
  1306.                 }
  1307.                 $waitItem->getCourseOccurrence()->bookSlots($orderItem->getQuantity());
  1308.                 $order $waitItem->getOrder();
  1309.                 $order->addOrderItem($orderItem);
  1310.                 if ($waitItem->getQuantity() === 0) {
  1311.                     $order->removeWaitItem($waitItem);
  1312.                 }
  1313.                 $em->persist($order);
  1314.             }
  1315.         }
  1316.         $this->addFlash('notice'count($moveIds) . (count($moveIds) > ' Wartelistenplätze verschoben' ' Wartelistenplatz verschoben'));
  1317.         $em->flush();
  1318.         return $this->redirectToRoute('course_reservations',  ['id' => $course->getId()]);
  1319.     }
  1320.     private function generateUniqueFileName()
  1321.     {
  1322.         return md5(uniqid());
  1323.     }
  1324.     private function createDescription($field$option)
  1325.     {
  1326.         switch ($option) {
  1327.             case 'course':
  1328.                 if (!empty($field['certificate'])) {
  1329.                     $field['name'] = $this->generateHTMLForDescription(
  1330.                         $field['name'],
  1331.                         'für den Kurs und das Zertifikat'
  1332.                     );
  1333.                 } else {
  1334.                     $field['name'] = $this->generateHTMLForDescription(
  1335.                         $field['name'],
  1336.                         'für den Kurs'
  1337.                     );
  1338.                 }
  1339.                 break;
  1340.             case 'certificate':
  1341.                 $field['name'] = $this->generateHTMLForDescription(
  1342.                     $field['name'],
  1343.                     'für das Zertifikat'
  1344.                 );
  1345.                 break;
  1346.             default:
  1347.                 break;
  1348.         }
  1349.         return $field;
  1350.     }
  1351.     private function generateHTMLForDescription($name$text)
  1352.     {
  1353.         return '<strong>' $name '</strong>' .  '<span style="font-size: 0.7rem"> (' $text ')</span>';
  1354.     }
  1355. }