<?php
namespace App\Controller;
use App\Entity\Appointment;
use App\Form\AppointmentType;
use App\Form\UndoMessageType;
use App\Form\UndoType;
use App\Repository\AppointmentDateRepository;
use App\Repository\AppointmentRepository;
use App\Repository\ParametersRepository;
use App\Repository\TimeSlotRepository;
use App\Service\AppointmentChecker;
use App\Service\AppointmentInfosMaker;
use App\Service\Calendar\Calendar;
use App\Service\Mailer\Mailer;
use App\Service\Tools\AppointmentInfosVerificator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
class PlanningController extends AbstractController
{
/**
* @throws \Exception
*/
#[Route('/planning/{reservation}', name: 'planning')]
public function planning(
Request $request,
AppointmentDateRepository $dateRepository,
AppointmentRepository $appointmentRepository,
TimeSlotRepository $timeSlotRepository,
AppointmentChecker $checker,
AppointmentInfosMaker $appointmentInfosMaker,
Mailer $mailer,
Calendar $calendar,
string $reservation = null
): Response {
if($reservation) {
$reservation = $appointmentRepository->findOneBy([
'id' => base64_decode($reservation)
]);
}
$dates = $dateRepository->findPlanning();
$appointment = new Appointment();
$form = $this->createForm(AppointmentType::class, $appointment);
$form->handleRequest($request);
$undoForm = $this->createForm(UndoMessageType::class);
$undoForm->handleRequest($request);
if($undoForm->isSubmitted() && $undoForm->isValid()) {
$undoAppointment = $appointmentRepository->findOneById($undoForm->get('appointment')->getData());
if($undoAppointment) {
$mailer->sendUndoMessage($undoAppointment, $undoForm->get('message')->getData());
if($undoAppointment->getLinkedTo()) {
$linked = $undoAppointment->getLinkedTo();
$linked->setLinkedTo(null);
$undoAppointment->setLinkedTo(null);
$appointmentRepository->remove($linked, true);
}
$appointmentRepository->remove($undoAppointment, true);
$this->addFlash('success', 'Le rendez-vous a bien été annulé.');
return $this->redirectToRoute('planning', [
]);
}
}
if($form->isSubmitted() && $form->isValid()) {
$appointmentInfosMaker->addForm($request->request->All()['appointment']);
$infos = $appointmentInfosMaker->getInfos();
if(count($infos) === 1 && $appointmentInfosMaker->shouldHaveChildrenButHaveNot()) {
$this->addFlash('error', 'Des informations sont manquantes. Merci de renouveler votre demande');
return $this->redirectToRoute('planning', [
]);
}
if(!AppointmentInfosVerificator::isValid($infos)) {
$this->addFlash('error', 'Vous n\'avez pas rempli tous les champs requis');
return $this->redirectToRoute('planning', [
]);
}
if(!$checker->canReserve($form->get('email')->getData())) {
$this->addFlash('error', 'Vous avez déjà un rendez-vous dans les jours à venir. Réservation impossible');
return $this->redirectToRoute('planning', [
]);
}
if($form->get('slot')->getData() && $checker->canReserve($form->get('email')->getData())) {
$slot = $timeSlotRepository->findOneById($form->get('slot')->getData());
if($slot->getAppointment()) {
$success = false;
$this->addFlash('error', 'Désolé, ce créneau a déjà été pris entre temps');
}
if(!$slot->getAppointment()) {
$appointment->setTimeSlot($slot);
$appointment->setInfos($infos);
$appointment->setCreatedAt(new \DateTimeImmutable('now', new \DateTimeZone('Europe/Paris')));
$appointmentRepository->save($appointment, true);
$this->addFlash('success', 'Votre demande a bien été enregistrée. Vous allez recevoir une confirmation par email');
$success = true;
if ($checker->needsMultipleTimeSlots($appointment)) {
$nextSlot = $checker->getNextTimeSlot($appointment);
if ($nextSlot && !$nextSlot->getAppointment()) {
$nextAppointment = clone($appointment);
$nextAppointment->setTimeSlot($nextSlot);
$nextAppointment->setLinkedTo($appointment);
$appointmentRepository->save($nextAppointment, true);
$appointment->setLinkedTo($nextAppointment);
$appointment->setIsMain(true);
$appointmentRepository->save($appointment, true);
$success = true;
$this->addFlash('success', 'Compte tenu des informations que vous nous avez fourni, nous vous avons réservé deux créneaux pour avoir le temps de vous accueillir convenablement.');
} else {
$appointmentRepository->remove($appointment, true);
$this->addFlash(
'error',
'D\'après les informations que vous nous avez fourni,
il semble qu\'il faille deux créneaux pour traiter convenablement votre demande.
Hors il n\'y a pas de créneau suivant disponible. Merci de choisir un moment ou deux créneaux consécutifs sont disponibles.');
$success = false;
}
}
}
if($success) {
$mailer->sendRegisterEmail($appointment);
}
return $this->redirectToRoute('planning', [
'reservation' => base64_encode($appointment->getId()),
]);
}
}
return $this->render('admin/planning.html.twig', [
'dates' => $dates,
'form' => $form->createView(),
'reservation' => $reservation,
'undoForm' => $undoForm->createView(),
]);
}
#[Route('/undo_appointment/{id}', name:'undo_appointment', methods: ['GET', 'POST'])]
public function undoAppointment(
AppointmentRepository $appointmentRepository,
ParametersRepository $parametersRepository,
Mailer $mailer,
Request $request,
Appointment $appointment = null
) {
$params = $parametersRepository->findOneBy([]);
if(!$appointment) {
$this->addFlash('error', 'Ce rendez-vous n\'existe pas ou a déjà été annulé');
return $this->redirectToRoute('planning');
}
$form = $this->createForm(UndoType::class);
$form->handleRequest($request);
if(!$form->isSubmitted()) {
$code = strtoupper(substr(uniqid(), -5));
$appointment->setUndoCode($code);
$appointmentRepository->save($appointment, true);
$mailer->sendUndoCode($appointment);
}
if($form->isSubmitted() && $form->isValid()) {
if($form->get('code')->getData() === $appointment->getUndoCode()) {
if($appointment->getLinkedTo()) {
$linked = $appointment->getLinkedTo();
$linked->setLinkedTo(null);
$appointment->setLinkedTo(null);
$appointmentRepository->remove($linked, true);
}
if($params->isWantsToreceiveEmailOnUndo()) {
$mailer->sendUndoNotification($appointment);
}
$appointmentRepository->remove($appointment, true);
$this->addFlash('success', 'Votre rendez-vous a bien été annulé');
return $this->redirectToRoute('planning');
} else {
$this->addFlash('error', 'Code erroné');
}
}
return $this->render('planning/undo.html.twig', [
'appointment' => $appointment,
'form' => $form->createView()
]);
}
#[Route('/search', name: 'search', methods: ['POST'])]
public function search(Request $request, AppointmentRepository $appointmentRepository)
{
$search = $request->request->get('search');
$isGlobal = $request->request->get('global') === '1';
$appointments = $isGlobal ? $appointmentRepository->globalSearch($search) : $appointmentRepository->search($search);
$data = [];
/** @var Appointment $appointment */
foreach ($appointments as $appointment) {
if(!$appointment->getLinkedTo() || ($appointment->getLinkedTo() && $appointment->isIsMain())) {
$data[] = $appointment;
}
}
return $this->render('admin/_search_results.html.twig', [
'appointments' => $data,
'is_global' => $isGlobal,
]);
}
}