<?php
namespace App\Controller;
use App\Entity\Course;
use App\Entity\Order;
use App\Entity\CourseData;
use App\Entity\Invoice;
use App\Form\CourseType;
use App\Entity\OrderItemPerson;
use App\Repository\CourseFieldRepository;
use App\Repository\CourseDataRepository;
use App\Service\PdfService;
use App\Form\CourseImagesType;
use App\Service\MailerService;
use App\Service\InvoiceService;
use App\Service\SepaXmlService;
use App\Entity\InvoicePayment;
use App\Entity\CourseOccurrence;
use App\Repository\CourseOccurrenceTimeRepository;
use App\Repository\TagsPersonRepository;
use App\Repository\PersonRepository;
use App\Repository\SpeakerRepository;
use App\Repository\PresenceRepository;
use App\Entity\OrderItem;
use App\Service\CertificateService;
use App\Repository\OrderRepository;
use App\Repository\CourseRepository;
use App\Service\EmailHistoryService;
use App\Service\ConfigurationService;
use App\Repository\CartItemRepository;
use Doctrine\Persistence\ManagerRegistry;
use App\Entity\Presence;
use Doctrine\ORM\EntityManagerInterface;
use App\Repository\TextblocksRepository;
use App\Repository\WaitItemRepository;
use App\Repository\OrderItemRepository;
use App\Service\Exception\ServiceException;
use App\Repository\CourseOccurrenceRepository;
use App\Repository\InvoiceItemRepository;
use App\Service\OrderService;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\Common\Collections\ArrayCollection;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Menke\UserBundle\Controller\AbstractClientableController;
/**
* @Route("/course")
* @IsGranted("ROLE_SPEAKER")
*/
class CourseController extends AbstractClientableController
{
private $managerRegistry;
private $certificateService;
public function __construct(ManagerRegistry $managerRegistry, CertificateService $certificateService)
{
$this->managerRegistry = $managerRegistry->getManager();
$this->certificateService = $certificateService;
}
const LISTING_LIMIT = 20;
/**
*
*/
private function getListingLimit(): int
{
return !empty($_ENV['COURSES_LISTINGLIMIT']) ? (int) $_ENV['COURSES_LISTINGLIMIT'] : 4;
}
/**
* @Route("/", name="course_index", methods="GET")
*/
public function index(
Request $request,
\App\Service\UiService $uiService,
CourseRepository $courseRepository,
EntityManagerInterface $manager,
SpeakerRepository $speakerRepository
): Response {
// $this->denyAccessUnlessGranted('ROLE_MANAGER');
$order = $uiService->getSortOrder('course-index-listing');
$archive = !empty($request->get('archive'));
///////////////////////////////////////////////////////////
$user = $this->getCurrentUser();
$speaker = $speakerRepository->getByUser($user);
/*
if ($speaker == null) {
$this->addFlash('error', 'Sie sind kein Speaker');
return $this->redirectToRoute('dashboard');
}else{
$this->addFlash('notice', 'Speaker ID: ' . $speaker->getId().' Person ID'.$user->getId());
}*/
$courses = $courseRepository->getCoursesByClientPaged(
$this->getCurrentClient(),
$this->getListingLimit(),
$order['orderDirection'] ?? 'ASC',
$order['orderBy'] ?? 'title',
1,
$archive,
$speaker,
);
// die Anzahl der Kurse mit den gebuchten überprüfen und die bookedSlots bei den CourseOccurreces aktualisieren
$this->manager = $manager;
foreach ($courses as $course)
{
foreach ($course->getOccurrences() as $occurrence)
{
$occurrence->setBookedSlots($occurrence->getBookedSlots());
$this->manager->persist($occurrence);
}
}
$this->manager->flush();
if ($speaker == null) {
$render = 'course/index.html.twig';
}else{
$render = 'course/index_speaker.html.twig';
}
///////////////////////////////////////////
return $this->render($render, [
'uiService' => $uiService,
'courses' => $courses,
'total' => $courses->count(),
'pages' => ceil($courses->count() / $this->getListingLimit()),
'page' => 1,
'archive' => $archive,
'env' => $_ENV,
'user' => $user,
]);
}
/**
* @Route("/{page}/{orderby}/{order}", name="course_index_listing", methods="GET", requirements={"page"="\d+","order"="asc|desc"})
*/
public function indexListing(
Request $request,
CourseRepository $courseRepository,
\App\Service\UiService $uiService,
$page,
$orderby,
$order
): Response {
$uiService->storeSortOrder('course-index-listing', $orderby, $order);
$archive = !empty($request->get('archive'));
$courses = $courseRepository->getCoursesByClientPaged($this->getCurrentClient(), $this->getListingLimit(), $order, $orderby, $page, $archive);
return $this->render('course/_index_listing.html.twig', [
'courses' => $courses,
'total' => $courses->count(),
'pages' => ceil($courses->count() / $this->getListingLimit()),
'page' => $page,
'archive' => $archive,
'env' => $_ENV,
]);
}
/**
* @Route("/new", name="course_new", methods="GET|POST")
*/
public function new(Request $request, ConfigurationService $configService): Response
{
$course = new Course();
if (!empty($courseNature = $request->get('courseNature'))) {
$course->setCourseNature($courseNature);
}
$form = $this->createForm(CourseType::class, $course, [
'client' => $this->getCurrentClient(),
'taxes' => $configService->getTaxConfigbyClient($this->getCurrentClient()),
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$course->setClient($this->getCurrentClient());
$course->setNumber($configService->getNewCourseNumberByClient($this->getCurrentClient()));
foreach ($course->getTexts() as $key => $text) {
$text->setCreated(new \DateTime());
if (empty($text->getOrderId())) {
$text->setOrderId($key + 1000);
}
}
$em = $this->getDoctrine()->getManager();
$course->setCreated(new \DateTime());
$em->persist($course);
$em->flush();
$this->addFlash('success', 'Kurs angelegt');
return $this->redirectToRoute('course-occurrence_new', ['courseId' => $course->getId()]);
}
return $this->render('course/new.html.twig', [
'course' => $course,
'fields' => null,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}/edit", name="course_edit", methods="GET|POST", requirements={"id"="\d+"})
*/
public function edit(
Request $request,
Course $course,
ConfigurationService $configService,
CourseFieldRepository $courseFieldRepository,
CourseDataRepository $courseDataRepository
): Response {
// $this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$courseTexts = new ArrayCollection();
foreach ($course->getTexts() as $text) {
$courseTexts->add($text);
}
$form = $this->createForm(CourseType::class, $course, [
'client' => $this->getCurrentClient(),
'taxes' => $configService->getTaxConfigbyClient($this->getCurrentClient()),
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$manager = $this->getDoctrine()->getManager();
foreach ($courseTexts as $text) {
if (false === $course->getTexts()->contains($text)) {
$text->setCourse(null);
$manager->remove($text);
}
}
foreach ($course->getTexts() as $key => $text) {
if (empty($text->getOrderId())) {
$text->setCreated(new \DateTime());
$text->setOrderId($key + 1000);
}
$text->setModified(new \DateTime());
}
$fields = $request->request->get('fields');
if (!is_null($fields)) {
foreach ($fields as $fieldId => $value) {
$field = $courseFieldRepository->find($fieldId);
$data = $courseDataRepository->findBy([
'course' => $course,
'field' => $field,
]);
if (count($data) == 0) {
$data = new CourseData();
$data->setClient($this->getCurrentClient());
$data->setCourse($course);
$data->setField($field);
$data->setCreated(new \datetime());
$manager->persist($data);
} else {
$data = $data[0];
}
$data->setValueText($value);
$data->setModified(new \datetime());
}
} else {
$fields = [];
}
$course->setModified(new \datetime());
$manager->flush();
$this->addFlash('notice', 'Kurs gespeichert');
return $this->redirectToRoute('course_edit', ['id' => $course->getId()]);
}
// Fetch course fields
$sql = 'SELECT
f.*,
d.value_text,
d.value_integer,
d.value_date
FROM
course_field f
LEFT JOIN
course_data d
ON
d.field_id = f.id AND
d.course_id = ' . $course->getId();
$em = $this->getDoctrine()->getManager();
$stmt = $em->getConnection()->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll();
$fields = [];
$isset = false;
foreach ($result as $field) {
$isset = false;
if (!empty($field['category'])) {
if (!$course->getCategory()) {
continue;
}
if (!in_array($course->getCategory()->getId(), json_decode($field['category'], true))) {
continue;
} else {
$field = $this->createDescription($field, 'course');
$isset = true;
}
}
if (!empty($field['course_type'])) {
if (!$course->getType()) {
continue;
}
if (!in_array($course->getType()->getId(), json_decode($field['course_type'], true))) {
continue;
} else {
if (!$isset) {
$field = $this->createDescription($field, 'course');
$isset = true;
}
}
}
if (empty($field['category']) && empty($field['course_type']) && !empty($field['certificate'])) {
if (!$isset) $field = $this->createDescription($field, 'certificate');
}
if (
!empty($field['category']) ||
!empty($field['course_type']) ||
$field['certificate']
) {
$fields[] = $field;
}
}
return $this->render('course/edit.html.twig', [
'course' => $course,
'form' => $form->createView(),
'fields' => $fields,
'env' => $_ENV,
]);
}
/**
* @Route("/{id}", name="course_delete", methods="DELETE", requirements={"id"="\d+"})
*/
public function delete(Request $request, Course $course): Response
{
// $this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
if ($this->isCsrfTokenValid('delete' . $course->getId(), $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$em->remove($course);
try {
$em->flush();
}
catch (\Exception $e)
{
$errorMessage = $e->getMessage();
if (str_contains($errorMessage, 'Integrity constraint violation'))
{
$this->addFlash('error', 'Der Kurs kann nicht gelöscht werden, weil er an anderer Stelle gebraucht wird.');
// $this->addFlash('error', $errorMessage);
}
else
{
$this->addFlash('error', 'Der Kurs kann nicht gelöscht werden, weil er an anderer Stelle gebraucht wird.');
}
return $this->redirectToRoute('course_index');
}
$this->addFlash('notice', 'Kurs gelöscht');
}
return $this->redirectToRoute('course_index');
}
/**
* @Route("/multiple", name="course_delete-multiple", methods="DELETE")
*/
public function deleteMultiple(
Request $request,
CourseRepository $courseRepo,
CartItemRepository $cartItemRepo,
WaitItemRepository $waitItemRepo,
OrderItemRepository $orderItemRepo
): Response {
if ($this->isCsrfTokenValid('delete_courses', $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$deleteIds = $request->request->get('delete');
foreach ($deleteIds as $id => $value) {
if ($value) {
$course = $courseRepo->find($id);
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$waitItems = $waitItemRepo->findBy(['course' => $course]);
foreach ($waitItems as $waitItem) {
$em->remove($waitItem);
}
$cartItems = $cartItemRepo->findBy(['course' => $course]);
foreach ($cartItems as $cartItem) {
$em->remove($cartItem);
}
$orderItems = $orderItemRepo->findBy(['course' => $course]);
foreach ($orderItems as $orderItem) {
$orderItem->setCourseOccurrence(null);
}
$em->remove($course);
}
}
try {
$em->flush();
} catch (\Exception $e) {
$errorMessage = $e->getMessage();
if (str_contains($errorMessage, 'Integrity constraint violation')){
$this->addFlash('error', 'Der Kurs kann nicht gelöscht werden, weil er an anderer Stelle gebraucht wird.');
// $this->addFlash('error', $errorMessage);
} else {
$this->addFlash('error', 'Der Kurs kann nicht gelöscht werden, weil er an anderer Stelle gebraucht wird.');
}
return $this->redirectToRoute('course_index');
}
$this->addFlash('notice', count($deleteIds) > 1 ? 'Kurse gelöscht' : 'Kurs gelöscht');
}
return $this->redirectToRoute('course_index');
}
/**
* @Route("/{id}/occurrences", name="course_occurrences", methods="GET", requirements={"id"="\d+"})
*/
public function courseOccurrences(
Request $request,
Course $course,
CourseOccurrenceRepository $repo,
\App\Service\UiService $uiService
): Response {
// $this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$order = $uiService->getSortOrder('course-occurrences-listing');
$archive = !empty($request->get('archive'));
$occurrences = $repo->findByCoursePaged(
$course,
self::LISTING_LIMIT,
$order['orderDirection'] ?? 'ASC',
$order['orderBy'] ?? 'title'
);
return $this->render('course/occurrences.html.twig', [
'uiService' => $uiService,
'course' => $course,
'occurrences' => $occurrences->getIterator(),
'total' => $occurrences->count(),
'pages' => ceil($occurrences->count() / self::LISTING_LIMIT),
'page' => 1,
'env' => $_ENV,
'archive' => $archive,
]);
}
/**
* @Route("/{id}/occurrences/{page}/{orderby}/{order}/{search}", name="course_occurrences_listing", methods="GET", defaults={"search"="", "order"="desc", "orderby"="start"}, requirements={"id"="\d+"})
*/
public function courseOccurrencesListing(
Request $request,
Course $course,
$page,
$orderby,
$order,
$search,
CourseOccurrenceRepository $repo,
\App\Service\UiService $uiService
): Response {
// $this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$uiService->storeSortOrder('course-occurrences-listing', $orderby, $order);
$occurrences = $repo->findByCoursePaged($course, self::LISTING_LIMIT, $order, $orderby, $page, $search);
return $this->render('course/tabs/_occurrences_listing.html.twig', [
'course' => $course,
'occurrences' => $occurrences->getIterator(),
'total' => $occurrences->count(),
'pages' => ceil($occurrences->count() / self::LISTING_LIMIT),
'page' => $page,
'env' => $_ENV,
]);
}
/**
* @Route("/{id}/images", name="course_images", methods="GET|POST", requirements={"id"="\d+"})
*/
public function courseImages(Request $request, Course $course)
{
// $this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$courseImages = new ArrayCollection();
foreach ($course->getImages() as $image) {
$courseImages->add($image);
}
$form = $this->createForm(CourseImagesType::class, $course);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$manager = $this->getDoctrine()->getManager();
foreach ($courseImages as $image) {
$image->setCreated(new \Datetime());
if (false === $course->getImages()->contains($image)) {
$image->setCourse(null);
$manager->remove($image);
}
}
foreach ($course->getImages() as $key => $image) {
// Setze das `created`-Datum, falls es nicht gesetzt wurde
if (null === $image->getCreated()) {
$image->setCreated(new \DateTime());
}
// Setze die Reihenfolge, falls `orderId` leer ist
if (empty($image->getOrderId())) {
$image->setOrderId($key + 1000);
}
}
$manager->flush();
$this->addFlash('notice', 'Kursbilder gespeichert');
return $this->redirectToRoute('course_images', ['id' => $course->getId()]);
}
return $this->render('course/images.html.twig', [
'course' => $course,
'form' => $form->createView(),
'env' => $_ENV,
]);
}
/**
* @Route("/{id}/invoices", name="course_invoices", methods="GET", requirements={"id"="\d+"})
*/
public function courseInvoices(
Request $request,
Course $course,
OrderItemRepository $repo,
OrderService $orderService,
TagsPersonRepository $tagsPersonRepository,
) {
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$orderItems = $repo->findByCoursePaged($course);
/**
* The display logic of subscription courses is different, as there only one order exists per
* customer/participant, but they should appear in every following course occurrence until they cancel.
*/
// if ($course->getCourseNature() === 'CourseSubscription') {
// return $this->render('course/invoices-subscription.html.twig', [
// 'course' => $course,
// 'orderItems' => $orderItems->getIterator(),
// ]);
// } else {
$archive = !empty($request->get('archive'));
if ($course->getCourseNature() === 'CourseSubscription') {
foreach ($orderItems as $orderItem) {
$orderItem->isAfterCancelDate = $orderService->isOrderItemOccurrenceAfterCancelDateByParticipant($this->getCurrentClient(), $orderItem);
}
}
return $this->render('course/invoices.html.twig', [
'tagsPerson' => $tagsPersonRepository->findAll(),
'course' => $course,
'orderItems' => $orderItems->getIterator(),
'archive' => $archive,
]);
// }
}
/**
* @Route("/{id}/invoices/create", name="course_create_invoices", methods="POST", requirements={"id"="\d+"})
*/
public function courseCreateInvoices(
Request $request,
Course $course,
OrderItemRepository $itemRepo,
InvoiceService $invoiceService
) {
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
if ($this->isCsrfTokenValid('create_invoices', $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$createIds = $request->request->get('create');
$count = 0;
if (!empty($createIds)) {
foreach ($createIds as $id => $value) {
if ($value) {
$orderItem = $itemRepo->find($id);
$results = $invoiceService->createInvoiceFromOrderItem($orderItem);
foreach ($results['attendees'] as $attendee) {
$em->persist($attendee);
}
$em->persist($results['invoice']);
$em->flush();
$count++;
}
}
$em->flush();
}
$this->addFlash('notice', $count . ($count === 1 ? ' Rechnung' : ' Rechnungen') . ' erstellt');
}
return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
/**
* @Route("/{id}/invoices/merge-pdf", name="course_invoices_merge-pdf", methods="POST", requirements={"id"="\d+"})
*/
public function courseMergePdf(
Request $request,
Course $course,
OrderItemRepository $repo,
PdfService $pdfService
) {
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
if ($this->isCsrfTokenValid('create_invoices', $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$mergeIds = $request->request->get('close');
if (!empty($mergeIds)) {
$mergeInvoices = new ArrayCollection();
foreach ($mergeIds as $id => $value) {
if ($value) {
$orderItem = $repo->find($id);
$order = $orderItem->getOrder();
foreach ($order->getInvoices() as $invoice) {
if (!$mergeInvoices->contains($invoice)) {
$mergeInvoices->add($invoice);
}
}
}
}
$pdf = $pdfService->getMergedInvoicePdf($this->getCurrentClient(), $mergeInvoices->toArray());
$pdf->Output('D', 'Rechnungen_' . date('Y-m-d_H-i') . '.pdf');
die;
} else {
$this->addFlash('notice', 'Keine Rechnungen ausgewählt.');
}
}
return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
/**
* @Route("/{id}/invoices/close", name="course_close_invoices", methods="POST", requirements={"id"="\d+"})
*/
public function courseCloseInvoices(
Request $request,
Course $course,
InvoiceItemRepository $repo,
ConfigurationService $configService,
MailerService $mailer,
PdfService $pdfService,
EmailHistoryService $emailHistoryService
) {
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
if ($this->isCsrfTokenValid('create_invoices', $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$closeIds = $request->request->get('close');
$count = 0;
if (!empty($closeIds)) {
foreach ($closeIds as $id => $value) {
if ($value) {
$invoiceItem = $repo->findOneBy(['orderItem' => $id]);
$invoice = $invoiceItem->getInvoice();
if ($invoice->getStatus() == Invoice::STATUS_DRAFT) {
$pdf = $pdfService->getInvoicePdf($this->getCurrentClient(), $invoice);
$sentMessage = $mailer->sendInvoiceEmail(
$invoice,
'Rechnung-' . $invoice->getNumber() . '.pdf',
$pdf->Output('S', 'Rechnung-' . $invoice->getNumber() . '.pdf')
);
$outputfile = $this->generateUniqueFileName() . '.pdf';
$outputpath = $this->getParameter('attachment_directory') . '/' . $outputfile;
$pdf->Output('F', $outputpath);
$emailHistoryService->saveProtocolEntryFromInvoiceMessage(
$invoice,
$sentMessage['sender'],
$sentMessage['subject'],
$sentMessage['message'],
$outputfile,
'Rechnung-' . $invoice->getNumber() . '.pdf'
);
if ($invoice->getStatus() != Invoice::STATUS_CLOSED) {
if ($invoice->isPaymentDebit()) {
$invoice->setStatus(Invoice::STATUS_DEBIT_PENDING);
} else {
$invoice->setStatus(Invoice::STATUS_CLOSED);
}
}
$count++;
} else {
// Send invoice again
$pdf = $pdfService->getInvoicePdf($this->getCurrentClient(), $invoice);
$sentMessage = $mailer->sendInvoiceEmail(
$invoice,
'Rechnung-' . $invoice->getNumber() . '.pdf',
$pdf->Output('S', 'Rechnung-' . $invoice->getNumber() . '.pdf')
);
$count++;
}
//Update the order status
$newOrderState = $invoice->getOrder()->setStatus(Order::STATUS_DONE);
$em->persist($newOrderState);
$em->flush();
}
}
}
$this->addFlash('notice', $count . ($count === 1 ? ' Rechnung' : ' Rechnungen') . ' versendet');
}
return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
/**
* @Route("/{id}/invoices/close-sepa/{all}", name="course_close_sepa-invoices", defaults={"all"="false"},methods="POST", requirements={"id"="\d+"})
*/
public function courseCloseSepaInvoices(
Request $request,
Course $course,
$all = false,
OrderRepository $repo,
OrderItemRepository $itemRepo,
ConfigurationService $configService,
SepaXmlService $sepaXmlService
) {
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
if ($this->isCsrfTokenValid('create_invoices', $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$closeIds = $request->request->get('close');
$invoicesToExport = new ArrayCollection();
if ($all) {
$orderItems = $itemRepo->findByCoursePaged($course);
foreach ($orderItems as $orderItem) {
$order = $orderItem->getOrder();
foreach ($order->getInvoices() as $invoice) {
if (
$invoice->containsCourse($course) &&
!$invoicesToExport->contains($invoice) &&
$invoice->isPaymentDebit()
) {
$invoicesToExport->add($invoice);
$invoice->setStatus(Invoice::STATUS_CLOSED);
if (!$order->getCustomer()->getDebitActive()) {
$order->getCustomer()->setDebitActive(true);
$invoice->setIsNewSepaMandate(true);
}
}
if (!empty($_ENV['SEPAEXPORT_PAYED'])) {
$restsumme = $invoice->getMissingSum();
if ($restsumme != 0) {
$invoicePayment = new InvoicePayment();
$invoicePayment->setInvoice($invoice);
$invoicePayment->setPayedDate(new \DateTime());
$invoicePayment->setSum($invoice->getMissingSum());
$invoice->setPaymentStatus(Invoice::FULLY_PAID);
$invoice->setExportStatus(Invoice::EXPORTED);
$em = $this->getDoctrine()->getManager();
$em->persist($invoicePayment);
}
$invoice->setPaymentStatus(Invoice::FULLY_PAID);
$invoice->setExportStatus(Invoice::EXPORTED);
$em->persist($invoice);
$em->flush();
}
}
}
} elseif (!empty($closeIds)) {
foreach ($closeIds as $id => $value) {
if ($value) {
$orderItem = $itemRepo->find($id);
$order = $orderItem->getOrder();
foreach ($order->getInvoices() as $invoice) {
if (
$invoice->containsCourse($course) &&
!$invoicesToExport->contains($invoice) &&
$invoice->isPaymentDebit()
) {
$invoicesToExport->add($invoice);
$invoice->setStatus(Invoice::STATUS_CLOSED);
if (!$order->getCustomer()->getDebitActive()) {
$order->getCustomer()->setDebitActive(true);
$invoice->setIsNewSepaMandate(true);
}
}
}
if (!empty($_ENV['SEPAEXPORT_PAYED'])) {
$restsumme = $invoice->getMissingSum();
if ($restsumme != 0) {
$invoicePayment = new InvoicePayment();
$invoicePayment->setInvoice($invoice);
$invoicePayment->setPayedDate(new \DateTime());
$invoicePayment->setSum($invoice->getMissingSum());
$invoice->setExportStatus(Invoice::EXPORTED);
$em = $this->getDoctrine()->getManager();
$em->persist($invoicePayment);
}
$invoice->setPaymentStatus(Invoice::FULLY_PAID);
$invoice->setExportStatus(Invoice::EXPORTED);
$em->persist($invoice);
$em->flush();
}
}
}
} else {
$this->addFlash('warning', 'Es wurden keine Rechnungen zum Export ausgewählt.');
return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
// Check invoices for past due dates
foreach ($invoicesToExport as $invoice) {
if (new \DateTime() > $invoice->getDueDate()) {
$this->addFlash('warning', 'Mindestens eine Rechnung enthält ein Zahlungsziel in der Vergangenheit.');
// return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
}
if (count($invoicesToExport) > 0) {
$config = $configService->getSepaXmlConfigByClient($this->getCurrentClient());
try {
$xml = $sepaXmlService->getSepaXmlMultiple($this->getCurrentClient(), $config, $invoicesToExport);
} catch (ServiceException $e) {
$this->addFlash('error', $e->getMessage());
return $this->redirectToRoute('invoice_index');
}
$em->flush();
$response = new Response($xml);
$response->headers->set('Content-Type', 'text/xml');
$response->headers->set('Content-disposition', 'attachment; filename="SEPA-' . date('Ymd-His') . '.xml"');
return $response;
}
$this->addFlash('error', 'Mindestens eine Rechnung enthält Fehler.');
return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
$this->addFlash('error', 'Der Sicherheits-Token ist ungültig. Bitte versuchen Sie es noch einmal.');
return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
/**
* @Route("/{id}/invoices/close-sepa/", name="course_close_sepa-invoice_selected", methods="POST", requirements={"id"="\d+"})
*/
public function courseCloseSepaInvoiceSelected(
Request $request,
Course $course,
OrderItemRepository $itemRepo,
ConfigurationService $configService,
SepaXmlService $sepaXmlService
) {
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
if ($this->isCsrfTokenValid('create_invoices', $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$closeIds = $request->request->get('close');
$invoicesToExport = new ArrayCollection();
if (!empty($closeIds)) {
foreach ($closeIds as $id => $value) {
if ($value) {
$orderItem = $itemRepo->find($id);
$order = $orderItem->getOrder();
foreach ($order->getInvoices() as $invoice) {
if (
$invoice->containsCourse($course) &&
!$invoicesToExport->contains($invoice) &&
$invoice->isPaymentDebit()
) {
$invoicesToExport->add($invoice);
$invoice->setStatus(Invoice::STATUS_CLOSED);
if (!$order->getCustomer()->getDebitActive()) {
$order->getCustomer()->setDebitActive(true);
$invoice->setIsNewSepaMandate(true);
}
}
}
if (!empty($_ENV['SEPAEXPORT_PAYED'])) {
$restsumme = $invoice->getMissingSum();
if ($restsumme != 0) {
$invoicePayment = new InvoicePayment();
$invoicePayment->setInvoice($invoice);
$invoicePayment->setPayedDate(new \DateTime());
$invoicePayment->setSum($invoice->getMissingSum());
$invoice->setExportStatus(Invoice::EXPORTED);
$em = $this->getDoctrine()->getManager();
$em->persist($invoicePayment);
}
$invoice->setPaymentStatus(Invoice::FULLY_PAID);
$invoice->setExportStatus(Invoice::EXPORTED);
$em->persist($invoice);
$em->flush();
}
}
}
} else {
$this->addFlash('warning', 'Es wurden keine Rechnungen zum Export ausgewählt.');
return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
// Check invoices for past due dates
foreach ($invoicesToExport as $invoice) {
if (new \DateTime() > $invoice->getDueDate()) {
$this->addFlash('warning', 'Mindestens eine Rechnung enthält ein Zahlungsziel in der Vergangenheit.');
// return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
}
if (count($invoicesToExport) > 0) {
$config = $configService->getSepaXmlConfigByClient($this->getCurrentClient());
try {
$xml = $sepaXmlService->getSepaXmlMultiple($this->getCurrentClient(), $config, $invoicesToExport);
} catch (ServiceException $e) {
$this->addFlash('error', $e->getMessage());
return $this->redirectToRoute('invoice_index');
}
$em->flush();
$response = new Response($xml);
$response->headers->set('Content-Type', 'text/xml');
$response->headers->set('Content-disposition', 'attachment; filename="SEPA-' . date('Ymd-His') . '.xml"');
return $response;
}
$this->addFlash('error', 'Mindestens eine Rechnung enthält Fehler.');
return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
$this->addFlash('error', 'Der Sicherheits-Token ist ungültig. Bitte versuchen Sie es noch einmal.');
return $this->redirectToRoute('course_invoices', ['id' => $course->getId()]);
}
/**
* @Route("/{id}/participants", name="course_participants", methods="GET", requirements={"id"="\d+"})
*/
public function courseParticipants(
Request $request,
Course $course,
OrderItemRepository $repo,
OrderService $orderService,
TagsPersonRepository $tagsPersonRepository,
) {
// $this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$orderItems = $repo->findByCoursePaged($course);
$archive = !empty($request->get('archive'));
if ($course->getCourseNature() === 'CourseSubscription') {
foreach ($orderItems as $orderItem) {
foreach ($orderItem->getParticipants() as $participant) {
$participant->isAfterCancelDate = $orderService->isOrderItemOccurrenceAfterCancelDateByParticipant($this->getCurrentClient(), $orderItem, $participant->getId());
$participant->cancelDate = $orderService->getCancelDateForParticipantInCourse($this->getCurrentClient(), $participant);
}
}
}
return $this->render('course/participants.html.twig', [
'tagsPerson' => $tagsPersonRepository->findAll(),
'env' => $_ENV,
'course' => $course,
'orderItems' => $orderItems->getIterator(),
'showCertificatesLink' => !empty($_ENV['CERTIFICATES_ENABLED']),
'archive' => $archive,
]);
}
/**
* @Route("/{id}/participants-pdf/{page}/{orderby}/{order}", name="course_participants_pdf", methods="GET", requirements={"id"="\d+"})
* @IsGranted("ROLE_SPEAKER")
*/
public function courseParticipantsPdf(
Request $request,
CourseOccurrence $courseOccurrence,
OrderItemRepository $repo,
PdfService $pdfService,
OrderService $orderService,
$page = 1,
$orderby = 'customerLastname',
$order = 'asc'
) {
// $this->denyAccessUnlessGranted('client_allowed', $courseOccurrence);
$this->denyAccessUnlessGranted('ROLE_SPEAKER', $courseOccurrence);
$orderItems = $repo->findByCourseOccurrence($courseOccurrence, $orderby, $order);
if ($courseOccurrence->getCourse()->getCourseNature() === 'CourseSubscription') {
foreach ($orderItems as $orderItem) {
foreach ($orderItem->getParticipants() as $participant) {
$participant->isAfterCancelDate = $orderService->isOrderItemOccurrenceAfterCancelDateByParticipant($this->getCurrentClient(), $orderItem, $participant->getId());
}
}
}
$pdf = $pdfService->getParticipantsPdf($this->getCurrentClient(), $courseOccurrence, $orderItems);
$pdf->Output('D', 'Teilnehmerliste-' . $courseOccurrence->getStart()->format('Y-m-d') . '.pdf');
exit();
}
/**
* @Route("/participant/{id}/certificateemail", name="course_participants_certificate_email", methods="GET", requirements={"id"="\d+","downlaod"="\d+"})
*/
public function courseParticipantsCertificateEmail(
Request $request,
$id,
ConfigurationService $configService,
OrderItemPerson $orderItemPerson,
TextblocksRepository $textblocksRepository,
CourseDataRepository $courseDataRepository,
OrderItemRepository $repo
): Response {
$orderItem = $repo->find($id);
$currentUrl = $request->getUri();
// $orderItemPerson = $orderItemPersonRepository->find($id);
$this->certificateService->generateAndSendCertificate(
$request,
$orderItemPerson->getOrderItem()->getOrder()->getNumber().'-von-'.count($orderItemPerson->getOrderItem()->getParticipants()), // Beispiel-ID, ändern je nach Datenstruktur
// $id,
$configService,
$orderItemPerson,
$textblocksRepository,
$courseDataRepository,
$repo
);
return $this->redirectToRoute('course_participants', ['id' => $orderItemPerson->getOrderItem()->getCourse()->getId()]);
}
/**
* @Route("/{id}/presences", name="course_presences", methods="GET", requirements={"id"="\d+"})
*/
public function coursePresences(
Request $request,
Course $course,
OrderItemRepository $repo,
OrderService $orderService,
CourseOccurrenceRepository $occurrencesrepo,
TagsPersonRepository $tagsPersonRepository,
\App\Service\UiService $uiService,
PresenceRepository $presenceRepository,
) {
$this->denyAccessUnlessGranted('ROLE_SPEAKER', $course);
$orderItems = $repo->findByCoursePaged($course);
$order = $uiService->getSortOrder('course-occurrences-listing');
$archive = !empty($request->get('archive'));
if ($course->getCourseNature() === 'CourseSubscription') {
foreach ($orderItems as $orderItem) {
foreach ($orderItem->getParticipants() as $participant) {
$participant->isAfterCancelDate = $orderService->isOrderItemOccurrenceAfterCancelDateByParticipant($this->getCurrentClient(), $orderItem, $participant->getId());
$participant->cancelDate = $orderService->getCancelDateForParticipantInCourse($this->getCurrentClient(), $participant);
}
}
}
$occurrences = $occurrencesrepo->findByCoursePaged(
$course,
self::LISTING_LIMIT,
$order['orderDirection'] ?? 'ASC',
$order['orderBy'] ?? 'title'
);
return $this->render('course/presences.html.twig', [
'presences' => $presenceRepository->findAll(),
'uiService' => $uiService,
'tagsPerson' => $tagsPersonRepository->findAll(),
'env' => $_ENV,
'course' => $course,
'occurrences' => $occurrences->getIterator(),
'total' => $occurrences->count(),
'pages' => ceil($occurrences->count() / self::LISTING_LIMIT),
'page' => 1,
'orderItems' => $orderItems->getIterator(),
'showCertificatesLink' => !empty($_ENV['CERTIFICATES_ENABLED']),
'archive' => $archive,
]);
}
/**
* @Route("/coursepresence/{id}/add/{courseOccurrence}/{participant}", name="course_presence_add", methods="GET|POST")
*/
public function savePresenseNew(
$id,
$courseOccurrence,
$participant,
CourseOccurrenceTimeRepository $occurrenceTimeRepository,
CourseOccurrenceRepository $occurrenceRepository,
PersonRepository $personRepository,
)
{
$occurrenceTime = $occurrenceTimeRepository->find($id);
$occurrence = $occurrenceRepository->find($courseOccurrence);
$user = $this->getCurrentUser();
$person = $personRepository->find($participant);
$newpresence = new Presence();
$newpresence->setOccurrence($occurrence);
$newpresence->setOccurrenceTime($occurrenceTime);
$newpresence->setUser($user);
$newpresence->setPerson($person);
$newpresence->setPresence('1');
$newpresence->setCreated(new \Datetime());
$newpresence->setClient($this->getCurrentClient());
$this->managerRegistry->persist($newpresence);
$this->managerRegistry->flush();
return $this->json([
'success' => "Die Anwesenheit wurde eingetragen.",
'presence' => true,
]);
}
/**
* @Route("/coursepresence/{id}/delete", name="course_presence_delete", methods="GET|POST")
*/
public function deletePresense(
$id,
PresenceRepository $presenceRepository,
): Response
{
$presence = $presenceRepository->find($id);
// $presenceRepository->remove($presenceremove);
$presence->setPresence('0');
$presence->setModified(new \Datetime());
$this->managerRegistry->persist($presence);
$this->managerRegistry->flush();
return $this->json([
'success' => "Die Anwesenheit wurde ausgetragen.",
'presence' => true,
]);
}
/**
* @Route("/coursepresence/{id}/edit", name="course_presence_edit", methods="GET|POST")
*/
public function editPresense(
$id,
PresenceRepository $presenceRepository,
): Response
{
$presence = $presenceRepository->find($id);
// $presenceRepository->remove($presenceremove);
$presence->setReason('x');
$presence->setModified(new \Datetime());
$this->managerRegistry->persist($presence);
$this->managerRegistry->flush();
return $this->json([
'success' => "Der Grund wurde eingetragen.",
]);
}
/**
* @Route("/coursepresence/{id}/update", name="course_presence_update", methods="GET|POST")
*/
public function updatePresence(Request $request): JsonResponse
{
// JSON-Daten aus der Anfrage extrahieren
$data = json_decode($request->getContent(), true);
$id = $data['id'] ?? null;
$value = $data['value'] ?? null;
if ($id === null || $value === null) {
return new JsonResponse(['success' => false, 'message' => 'Invalid data'], 400);
}
// Hier können Sie die Logik für das Aktualisieren der Anwesenheit implementieren
// Zum Beispiel: Suchen Sie das entsprechende Entity und aktualisieren Sie den Wert
$entityManager = $this->getDoctrine()->getManager();
$presence = $entityManager->getRepository(Presence::class)->find($id);
if (!$presence) {
return new JsonResponse(['success' => false, 'message' => 'Presence not found'], 404);
}
// Setzen Sie den neuen Wert und speichern Sie ihn
$presence->setreason($value); // Beispiel: setValue() sollte zu Ihrem Entity passen
$entityManager->persist($presence);
$entityManager->flush();
// Erfolgreiche Antwort zurückgeben
return new JsonResponse(['success' => true]);
}
/**
* @Route("/coursepresence/{id}/participantspresenceexport", name="course_participants_presences_export", methods="GET", requirements={"id"="\d+"})
* @IsGranted("ROLE_SPEAKER")
*/
public function courseParticipantsPresencesExport(
Request $request,
CourseOccurrence $courseOccurrence,
OrderItemRepository $repo,
PresenceRepository $presenceRepository,
CourseOccurrenceTimeRepository $occurrenceTimeRepository,
CourseOccurrenceRepository $occurrenceRepository,
$orderby = 'customerLastname',
$order = 'asc'
) {
$this->denyAccessUnlessGranted('ROLE_SPEAKER', $courseOccurrence);
$orderItems = $repo->findByCourseOccurrence($courseOccurrence, $orderby, $order);
$course = $courseOccurrence->getCourse()->getId();
$orderItems = $repo->findByCourseOccurrence($courseOccurrence, $orderby, $order);
$response = $this->render('person/export-participants-presences.csv.twig', [
'presences' => $presenceRepository->findByOccurrence($courseOccurrence),
'course' => $course,
'occurrence' => $courseOccurrence,
'orderItems' => $orderItems,
]);
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
$response->headers->set('Content-Disposition', 'attachment; filename="Anwesenheit_Kurs.csv"');
return $response;
}
/**
* @Route("/coursepresence/{id}/exportcourseparticipants", name="export_course_participants", methods="GET", requirements={"id"="\d+"})
* @IsGranted("ROLE_SPEAKER")
*/
public function courseParticipantsExport(
Request $request,
CourseOccurrence $courseOccurrence,
OrderItemRepository $repo,
$orderby = 'customerLastname',
$order = 'asc'
) {
$this->denyAccessUnlessGranted('ROLE_SPEAKER', $courseOccurrence);
$header = $request->get('header', false); // Holen Sie den Wert von 'header'
// Wenn 'header' true ist, setzen Sie ihn auf 1
if ($header) {
$header = '1';
} else
{ $header = '0';}
$course = $courseOccurrence->getCourse()->getId();
$orderItems = $repo->findByCourseOccurrence($courseOccurrence, $orderby, $order);
// Rendern des CSV-Inhalts als String (UTF-8)
$csvContent = $this->renderView('person/export-course-participants.csv.twig', [
'header' => $header,
'course' => $course,
'occurrence' => $courseOccurrence,
'orderItems' => $orderItems,
]);
// Konvertiere den CSV-Inhalt in ISO-8859-1
$encodedCsvContent = mb_convert_encoding($csvContent, 'ISO-8859-1', 'UTF-8');
// Erstelle eine Antwort mit dem konvertierten Inhalt
$response = new Response($encodedCsvContent);
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/csv; charset=ISO-8859-1');
// $response->headers->set('Content-Type', 'text/csv; charset=utf-8');
$startDate = $courseOccurrence->getStart();
$formattedDate = $startDate->format('d.m.y');
// Konstruktion des Dateinamens
$courseTitle = $courseOccurrence->getCourse()->getTitle();
$fileName = 'Kurs-Teilnehmer-' . $courseTitle . '-' . $formattedDate . '.csv';
// Setzen des Content-Disposition-Headers
$response->headers->set('Content-Disposition', 'attachment; filename="' . $fileName . '"');
return $response;
}
/**
* @Route("/{id}/reservations", name="course_reservations", methods="GET", requirements={"id"="\d+"})
*/
public function courseReservations(
Request $request,
Course $course,
WaitItemRepository $repo,
TagsPersonRepository $tagsPersonRepository,
) {
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$waitItems = $repo->findByCoursePaged($course);
return $this->render('course/reservations.html.twig', [
'course' => $course,
'waitItems' => $waitItems->getIterator(),
'tagsPerson' => $tagsPersonRepository->findAll(),
]);
}
/**
* @Route("/waititem/{id}/delete", name="waititem_delete", methods="GET|POST")
*/
public function deleteWaitItem($id,
WaitItemRepository $waitItemRepository,
TagsPersonRepository $tagsPersonRepository,
EntityManagerInterface $entityManager): Response
{
$waitItem = $waitItemRepository->find($id);
$course = $waitItem->getCourseOccurrence()->getCourse();
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$waitItems = $waitItemRepository->findByCoursePaged($course);
if (!$waitItem) {
throw $this->createNotFoundException('WaitItem not found');
}
$entityManager->remove($waitItem);
$entityManager->flush();
$this->addFlash('success', 'WaitItem deleted successfully');
return $this->render('course/reservations.html.twig', [
'course' => $course,
'waitItems' => $waitItems->getIterator(),
'tagsPerson' => $tagsPersonRepository->findAll(),
]);
}
/**
* @Route("/{id}/reservations/move", name="course_reservations_move", methods="POST", requirements={"id"="\d+"})
*/
public function moveCourseReservations(
Request $request,
Course $course,
WaitItemRepository $repo
): Response {
$this->denyAccessUnlessGranted('ROLE_MANAGER', $course);
$em = $this->getDoctrine()->getManager();
$moveIds = $request->request->get('item');
foreach ($moveIds as $id => $value) {
if ($value) {
$waitItem = $repo->find($value);
$orderItem = OrderItem::createFromWaitItem($waitItem);
$participants = $waitItem->getParticipants();
foreach ($participants as $participant) {
if ($participant->getPerson()->getId() === $id) {
$participant->setWaitItem(null);
$participant->setOrderItem($orderItem);
$orderItem->setQuantity($orderItem->getQuantity() + 1);
$waitItem->setQuantity($waitItem->getQuantity() - 1);
break;
}
}
$waitItem->getCourseOccurrence()->bookSlots($orderItem->getQuantity());
$order = $waitItem->getOrder();
$order->addOrderItem($orderItem);
if ($waitItem->getQuantity() === 0) {
$order->removeWaitItem($waitItem);
}
$em->persist($order);
}
}
$this->addFlash('notice', count($moveIds) . (count($moveIds) > 1 ? ' Wartelistenplätze verschoben' : ' Wartelistenplatz verschoben'));
$em->flush();
return $this->redirectToRoute('course_reservations', ['id' => $course->getId()]);
}
private function generateUniqueFileName()
{
return md5(uniqid());
}
private function createDescription($field, $option)
{
switch ($option) {
case 'course':
if (!empty($field['certificate'])) {
$field['name'] = $this->generateHTMLForDescription(
$field['name'],
'für den Kurs und das Zertifikat'
);
} else {
$field['name'] = $this->generateHTMLForDescription(
$field['name'],
'für den Kurs'
);
}
break;
case 'certificate':
$field['name'] = $this->generateHTMLForDescription(
$field['name'],
'für das Zertifikat'
);
break;
default:
break;
}
return $field;
}
private function generateHTMLForDescription($name, $text)
{
return '<strong>' . $name . '</strong>' . '<span style="font-size: 0.7rem"> (' . $text . ')</span>';
}
}