<?php
namespace App\Controller;
use App\Entity\Delivery;
use App\Entity\Customer;
use App\Entity\DeliveryArticle;
use App\Entity\DeliveryHistoryStatus;
use App\Entity\Document;
use App\Entity\Packaging;
use App\Entity\Tracking;
use App\Entity\User;
use App\Entity\VehicleType;
use App\Enum\DeliveryStatusEnum;
use App\Enum\PriceComplementaryEnum;
use App\Event\DeliveryWorkflowEvent;
use App\Form\DeliveryArticleFormType;
use App\Form\DeliveryRecipientType;
use App\Form\DeliverySenderType;
use App\Repository\DeliveryStatusRepository;
use App\Service\DeliveryService;
use App\Service\FileUploader;
use App\Workflow\Transition\DeliveryTransition;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class DeliveryController extends AbstractController
{
#[Route('/delivery', name: 'app_delivery', methods: ['GET', 'POST'])]
public function index(Request $request): Response
{
if ($request->getMethod() == Request::METHOD_POST) {
$isPro = (int)$request->request->get('isPro');
$send = (int)$request->request->get('send');
return $this->redirectToRoute('delivery_create', ['isPro' => $isPro, 'send' => $send]);
}
return $this->render('delivery/index.html.twig', [
'controller_name' => 'DeliveryController',
]);
}
#[Route('/delivery/create', name: 'delivery_create', methods: ['GET', 'POST'])]
public function createDelivery(
DeliveryService $deliveryService,
ManagerRegistry $doctrine,
Request $request,
DeliveryStatusRepository $deliveryStatusRepository
): Response {
$entityManager = $doctrine->getManager();
$isPro = (bool)$request->query->get('isPro');
$send = (bool)$request->query->get('send');
/**
* @var ?User $user
*/
$user = $this->getUser();
if (!$user) {
throw new \Exception('User not found', Response::HTTP_NOT_FOUND);
}
$customer = $doctrine->getRepository(Customer::class)->find($user->getId());
//TODO interdire aux livreurs
if (!$customer) {
return $this->redirectToRoute('accueil_vitrine');
}
$status = $deliveryStatusRepository->findOneBy(['name' => DeliveryStatusEnum::IN_PROGRESS->value]);
if (!$status) {
throw new \Exception('Status not found', Response::HTTP_NOT_FOUND);
}
$history = (new DeliveryHistoryStatus())->setStatus($status);
$delivery = new Delivery();
$delivery->setRequester($customer)
->setIsPro($isPro)
->setIsSend($send)
->addDeliveryHistoryStatus($history);
$form = $this->createFormBuilder($delivery)
->add('sender', DeliverySenderType::class, [
'isPro' => $isPro,
'send' => $send
])
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var Delivery $delivery */
$delivery = $form->getData();
//TODO add autocomplete to get position
$sender = $delivery->getSender();
if (!$sender) {
throw new \Exception('Sender not found', Response::HTTP_NOT_FOUND);
}
$tracking = (new Tracking())->setLongitude('2.4383')->setLatitude('48.7780');
$sender->setPosition($tracking);
$delivery->setSender($sender);
$entityManager->persist($delivery);
$entityManager->flush();
$deliveryService->setDeliverySessionData($isPro, $send, $delivery->getId());
return $this->redirectToRoute('add_delivery_recipient', [
'id' => $delivery->getId()
]);
}
return $this->render('delivery/create.html.twig', [
'form' => $form->createView()
]);
}
#[Route('/delivery/add/recipient/{id}', name: 'add_delivery_recipient', methods: ['GET', 'POST'])]
public function addDeliveryRecipient(ManagerRegistry $doctrine, Request $request, Delivery $delivery): Response
{
$entityManager = $doctrine->getManager();
$form = $this->createFormBuilder($delivery)
->add('recipient', DeliveryRecipientType::class, [
'isPro' => $delivery->isPro(),
'send' => $delivery->isSend(),
])
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var Delivery $delivery */
$delivery = $form->getData();
$entityManager->flush();
return $this->redirectToRoute('add_delivery_articles', [
'id' => $delivery->getId()
]);
}
return $this->render('delivery/addRecipient.html.twig', [
'form' => $form->createView()
]);
}
#[Route('/delivery/add/articles/{id}', name: 'add_delivery_articles', methods: ['GET', 'POST'])]
public function addDeliveryArticles(ManagerRegistry $doctrine, Request $request, FileUploader $fileUploader, Delivery $delivery): Response
{
$entityManager = $doctrine->getManager();
$isPro = $delivery->isPro();
$send = $delivery->isSend();
$form = $this->createFormBuilder($delivery)
->add('deliveryArticles', CollectionType::class, [
'entry_type' => DeliveryArticleFormType::class,
'entry_options' => [
'label' => false,
'isPro' => $isPro,
'send' => $send
],
'allow_add' => true,
'allow_delete' => false,
'by_reference' => false
]);
if (!$isPro || $send) {
$form->add('packaging', ChoiceType::class, [
'choices' => [
'Oui' => true,
'Non' => false
],
'mapped' => false
]);
}
$form = $form->add('save', SubmitType::class, [
'attr' => ['class' => 'btn']
])
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$packaging = (!$isPro || $send) ? $form->get('packaging')->getData() : 0;
$articlesForm = $form->get('deliveryArticles');
foreach ($articlesForm as $articleForm) {
if ($isPro && !$send) {
//Upload documents
$documentsForm = $articleForm->get('documents');
foreach ($documentsForm as $documentForm) {
/** @var ?UploadedFile @documentFile */
$documentFile = $documentForm->get('realName')->getData();
/** @var Document $document */
$document = $documentForm->getData();
if ($documentFile) {
$document = $fileUploader->updateDocument($document, $documentFile);
}
}
} else {
//Upload photo
/** @var ?UploadedFile @photo */
$photo = $articleForm->get('photo')->getData();
/** @var DeliveryArticle $article */
$article = $articleForm->getData();
if ($photo) {
$photoFileName = $fileUploader->upload($photo);
$article->setPhoto($photoFileName);
}
}
}
/** @var Delivery $delivery */
$delivery = $form->getData();
$entityManager->flush();
if ($packaging) {
return $this->redirectToRoute('add_delivery_packaging', ['id' => $delivery->getId()]);
}
return $this->redirectToRoute('add_delivery_vehicle_type', ['id' => $delivery->getId()]);
}
return $this->render('delivery/addArticles.html.twig', [
'form' => $form->createView()
]);
}
#[Route('/delivery/add/packaging/{id}', name: 'add_delivery_packaging', methods: ['GET', 'POST'])]
public function addDeliveryPackaging(ManagerRegistry $doctrine, Request $request, Delivery $delivery): Response
{
$entityManager = $doctrine->getManager();
$form = $this->createFormBuilder($delivery)
->add('packaging', EntityType::class, [
'class' => Packaging::class,
'choice_label' => 'name',
])
->add('save', SubmitType::class)
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var Delivery $delivery */
$delivery = $form->getData();
$entityManager->flush();
return $this->redirectToRoute('add_delivery_vehicle_type', ['id' => $delivery->getId()]);
}
return $this->render('delivery/addPackaging.html.twig', [
'form' => $form->createView()
]);
}
#[Route('/delivery/add/vehicle_type/{id}', name: 'add_delivery_vehicle_type', methods: ['GET', 'POST'])]
public function addDeliveryVehicleType(ManagerRegistry $doctrine, Request $request, Delivery $delivery, EventDispatcherInterface $eventDispatcher): Response
{
$entityManager = $doctrine->getManager();
$form = $this->createFormBuilder($delivery)
->add('vehicleType', EntityType::class, [
'class' => VehicleType::class,
'choice_label' => 'name',
])
->add('save', SubmitType::class)
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var Delivery $delivery */
$delivery = $form->getData();
$entityManager->flush();
$eventDispatcher->dispatch(new DeliveryWorkflowEvent($delivery, DeliveryTransition::FINALIZATION), DeliveryWorkflowEvent::NAME);
return $this->redirectToRoute('delivery_validation', ['id' => $delivery->getId()]);
}
return $this->render('delivery/addVehicleType.html.twig', [
'form' => $form->createView()
]);
}
#[Route('/delivery/validation/{id}', name: 'delivery_validation', methods: ['GET'])]
public function deliveryValidation(ManagerRegistry $doctrine, Delivery $delivery, DeliveryService $deliveryService): Response
{
$entityManager = $doctrine->getManager();
/** TODO : get meteo */
$meteoFee = 2;
$electricFee = $deliveryService->getPrice(PriceComplementaryEnum::ELECTRIC);
$tva = $deliveryService->getTVA();
/** TODO : get distance */
$distance = 2500;
$sousTotalHT = $deliveryService->getSousTotalHT($distance, $meteoFee);
$cancellationFees = $deliveryService->getPrice(PriceComplementaryEnum::CANCELLATION_FEES);
$returnFees = 0;
$totalHT = $deliveryService->getTotalHT($delivery, $distance, $meteoFee, $electricFee);
$tvaCost = $totalHT * $tva;
$totals = [
'sousTotalHT' => $sousTotalHT,
'thermic' => $deliveryService->getThermicCost($delivery),
'electric' => $deliveryService->isElectric($delivery) ? $electricFee : 0,
'options' => $deliveryService->getOptions($delivery, $sousTotalHT),
'discount' => $deliveryService->getDiscount(),
'cancellationFees' => $cancellationFees,
'returnFees' => $returnFees,
'totalHT' => $totalHT,
'tva' => $tvaCost,
'totalTTC' => $totalHT + $tvaCost
];
$delivery->setDeliveryTotals($totals);
$entityManager->flush();
return $this->render(
'delivery/validation.html.twig',
array_merge(['delivery' => $delivery], $totals)
);
}
#[Route('/delivery/payment/choose/{id}', name: 'add_delivery_payment_choose', methods: ['GET'])]
public function addDeliveryPaymentChoose(Delivery $delivery): Response
{
return $this->render('delivery/paymentChoose.html.twig', [
'delivery' => $delivery
]);
}
#[Route('/delivery/cancel/{id}', name: 'cancel_delivery', methods: ['GET'])]
public function cancelDelivery(Delivery $delivery, EventDispatcherInterface $eventDispatcher): Response
{
$eventDispatcher->dispatch(new DeliveryWorkflowEvent($delivery, DeliveryTransition::CANCELATION), DeliveryWorkflowEvent::NAME);
return $this->redirectToRoute('app_course_index');
}
}