<?php
namespace App\Controller\Front;
use App\Constant\BookingMetadata;
use App\Constant\BookingRoomStatus;
use App\Constant\BookingStatus;
use App\Constant\BookingType;
use App\Constant\NotificationType;
use App\Constant\OccupancyStatus;
use App\Constant\PaymentStatus;
use App\Controller\AppController;
use App\Entity\AccommodationOccupancy;
use App\Entity\AccommodationRoom;
use App\Entity\Booking;
use App\Entity\BookingRoom;
use App\Entity\Metadata;
use App\Entity\Page;
use App\Entity\User;
use App\Form\Front\BookingDateType;
use App\Form\Front\BookingFinancialSituationType;
use App\Form\Front\BookingIdentityType;
use App\Repository\UserRepository;
use App\Service\BookingService;
use App\Service\CouponChecker;
use App\Service\InventoryService;
use App\Service\PaymentService;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/reservation", name="front_booking_")
* @Security("is_granted('ROLE_USER')")
*/
class BookingController extends AppController
{
private function checkIfUserOwnBooking (Booking $booking, string $status = null) {
if($booking->getUser()->getId() !== $this->getUser()->getId()) throw $this->createNotFoundException('Réservation introuvable');
if(!empty($status)){
if($status !== $booking->getStatus()) throw $this->createNotFoundException('Réservation introuvable');
}
}
private function handleBookingDateForm ($request, $booking) {
$form = $this->createForm(BookingDateType::class, $booking);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$bookingRoom = $booking->getRooms()->first();
if(!empty($bookingRoom)) {
$date = \DateTime::createFromFormat(
$form->get('dateFormat')->getViewData(),
$form->get('dateFrom')->getViewData()
);
$bookingRoom->setEntranceDate($date);
}
if($booking->isMove()){
$metadata = new Metadata(BookingMetadata::INVENTORY_USER, $form->get('dateUid')->getViewData());
$booking->addMetadata($metadata);
}
$this->em->persist($booking);
$this->em->flush();
return $this->redirectToRoute("front_booking_identity", ["booking" => $booking->getId()]);
}
$page = new Page();
$page->setIndexed(false);
$page->setMetaTitle("Réservation de votre chambre - Citizens");
return $this->render('front/booking/booking_1.html.twig', [
'booking' => $booking,
'page' => $page,
'accommodation' => $booking->getAccommodation(),
'form' => $form->createView(),
]);
}
/**
* @Route("/chambre/{room}", name="index")
*/
public function index(Request $request, AccommodationRoom $room)
{
$occupancy = $this->getUser()->getCurrentOccupancy();
if($occupancy instanceof AccommodationOccupancy){
if($occupancy->isLeaving() || $occupancy->isSwitching()){
// If the user is leaving or switching room, show an alert message
return $this->render('front/booking/booking_1_alert.html.twig', [
'$occupancy' => $occupancy,
'page' => new Page(),
]);
}
}
if(empty($booking)) {
$booking = new Booking();
$booking->setUser($this->getUser());
$booking->generateReference();
$booking->setAccommodation($room->getAccommodation());
$booking->setStatus(BookingStatus::DRAFT);
$booking->setType((!$this->getUser()->isOccupyingRoom()) ? BookingType::CLASSIC : BookingType::MOVE);
$bookingRoom = new BookingRoom();
$bookingRoom->setUser($this->getUser());
$bookingRoom->setStatus(BookingRoomStatus::PENDING);
$bookingRoom->setRoom($room);
$booking->addRoom($bookingRoom);
}
return $this->handleBookingDateForm($request, $booking);
}
/**
* @Route("/room/{room}/date-update", name="ajax_date_update", methods={"GET"})
*/
public function dateUpdate(Request $request, AccommodationRoom $room)
{
$date = \DateTime::createFromFormat($request->query->get('format', 'd/m/Y'), $request->query->get('date'));
$booking = new Booking();
$bookingRoom = new BookingRoom();
$bookingRoom->setRoom($room);
$bookingRoom->setEntranceDate($date);
$booking->addRoom($bookingRoom);
$params = [
"accommodation" => $room->getAccommodation(),
"room" => $room,
"booking" => $booking,
];
return $this->json([
'to_pay_before' => $this->render('front/booking/booking_1_to_pay_before.html.twig', $params)->getContent(),
'sidebar' => $this->render('front/booking/booking_sidebar.html.twig', $params)->getContent(),
]);
}
/**
* @Route("/{booking}/date", name="date")
*/
public function date(Request $request, Booking $booking)
{
$this->checkIfUserOwnBooking($booking, BookingStatus::DRAFT);
return $this->handleBookingDateForm($request, $booking);
}
/**
* @Route("/{booking}/identite", name="identity")
*/
public function identity(Request $request, Booking $booking)
{
$user = $this->getUser();
$this->checkIfUserOwnBooking($booking, BookingStatus::DRAFT);
$form = $this->createForm(BookingIdentityType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->em->persist($user);
$this->em->flush();
return $this->redirectToRoute("front_booking_financial_situation", ["booking" => $booking->getId()]);
}
$page = new Page();
$page->setIndexed(false);
$page->setMetaTitle("Réservation de votre chambre - Citizens");
return $this->render('front/booking/booking_2.html.twig', [
'booking' => $booking,
'page' => $page,
'form' => $form->createView(),
]);
}
/**
* @Route("/{booking}/situation-financiere", name="financial_situation")
*/
public function financial_situation(Request $request, Booking $booking)
{
$user = $this->getUser();
$this->checkIfUserOwnBooking($booking, BookingStatus::DRAFT);
$form = $this->createForm(BookingFinancialSituationType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->em->persist($user);
$this->em->flush();
return $this->redirectToRoute("front_booking_payment", ["booking" => $booking->getId()]);
}
$page = new Page();
$page->setIndexed(false);
$page->setMetaTitle("Réservation de votre chambre - Citizens");
return $this->render('front/booking/booking_3.html.twig', [
'booking' => $booking,
'page' => $page,
'form' => $form->createView(),
]);
}
/**
* @Route("/{booking}/coupon-check", name="ajax_coupon_check", methods={"POST"})
*/
public function couponCheck(Request $request, Booking $booking, ParameterBagInterface $params, CouponChecker $couponChecker, PaymentService $paymentService)
{
$user = $this->getUser();
$this->checkIfUserOwnBooking($booking, BookingStatus::DRAFT);
$intent = $paymentService->getPaymentIntent($booking->getPayment());
$coupon = $couponChecker->apply_coupon($request->request->get('code'), $user, $booking);
$paymentService->updateAmount($booking->getPayment(), $booking->getTotalPrice() * 100);
$this->em->persist($booking);
$this->em->flush();
$params = [
"accommodation" => $booking->getAccommodation(),
"booking" => $booking,
'stripe' => [
'intent' => $intent,
],
];
return $this->json([
'coupon' => $this->render('front/booking/booking_discount_code.html.twig', $params)->getContent(),
'payment' => $this->render('front/booking/booking_payment_card.html.twig', $params)->getContent(),
'sidebar' => $this->render('front/booking/booking_sidebar.html.twig', $params)->getContent(),
]);
}
/**
* @Route("/{booking}/paiement", name="payment")
*/
public function payment(Request $request, Booking $booking, ParameterBagInterface $params, CouponChecker $couponChecker, PaymentService $paymentService)
{
$user = $this->getUser();
$this->checkIfUserOwnBooking($booking, BookingStatus::DRAFT);
//-------------------------------
// Check coupon code
if (!empty($booking->getDiscountCode())) {
$couponChecker->apply_coupon($booking->getDiscountCode(), $user, $booking); // Check if coupon is still valid
if (empty($booking->getDiscountCode())) {
$paymentService->updateAmount($booking->getPayment(), $booking->getTotalPrice() * 100);
}
}
//------------------------------------------------------------
// Create or Update stripe customer
if ($user instanceof User) {
$paymentService->updateCustomer($user);
}
//-------------------------------
// Stripe - Payment Intent
if(empty($booking->getPayment())) {
$intent = $paymentService->createBookingPayment($booking);
}else{
$intent = $paymentService->getPaymentIntent($booking->getPayment());
}
$this->em->flush();
$page = new Page();
$page->setIndexed(false);
$page->setMetaTitle("Réservation de votre chambre - Citizens");
return $this->render('front/booking/booking_4.html.twig', [
'booking' => $booking,
'page' => $page,
'stripe' => [
'intent' => $intent,
],
]);
}
/**
* @Route("/{booking}/confirmation", name="confirmation")
*/
public function confirmation(
Booking $booking,
PaymentService $paymentService,
BookingService $bookingService,
InventoryService $inventoryService,
UserRepository $userRepository
) {
$user = $this->getUser();
$this->checkIfUserOwnBooking($booking);
if (!empty($booking->getPayment()) && BookingStatus::DRAFT === $booking->getStatus()){
$paymentIntent = $paymentService->getPaymentIntent($booking->getPayment());
if (
(!empty($paymentIntent) && $paymentIntent->status === 'succeeded')
) {
$booking->setStatus(BookingStatus::PENDING);
$booking->getPayment()->setStatus(PaymentStatus::PAID);
// -----------------------------------------------------
// If user is switching room, create the inventories
if ($booking->getType() === BookingType::MOVE) {
$occupancy = $booking->getUser()->getCurrentOccupancy();
if ($occupancy instanceof AccommodationOccupancy) {
$occupancy->setStatus(OccupancyStatus::SWITCHING);
$this->em->persist($occupancy);
try {
// Get inventory admin user selected
$inventoryUser = $userRepository->findOneBy(["id" => $booking->getMetadata(BookingMetadata::INVENTORY_USER)]);
// ---------------------------------------
// Create the inventories (departure and entrance)
$date = $booking->getRooms()->first()->getEntranceDate();
$inventoryService->departure($user->getCurrentOccupancy(), $date, $inventoryUser);
$entranceDate = clone $date;
$entranceDate->modify("+2 hours");
$inventoryService->entrance($booking, $entranceDate, $inventoryUser, false);
} catch (\Exception $e) {
dump($e);
}
}
}
// -----------------------------------------------------
// Persist and notify
$this->em->persist($booking);
$this->em->flush();
$bookingService->updateAvailability($booking);
$this->notifier->notify($booking->getUser(), NotificationType::BOOKING_CONFIRM, [
"booking" => $booking,
]);
}
}
$page = new Page();
$page->setIndexed(false);
$page->setMetaTitle("Confirmation de réservation - Citizens");
return $this->render('front/booking/booking_confirm.html.twig', [
'booking' => $booking,
'page' => $page,
]);
}
}