forked from Somnia/SomniaRooms
205 lines
7.3 KiB
PHP
205 lines
7.3 KiB
PHP
<?php
|
|
|
|
namespace App\Controller;
|
|
|
|
use App\Entity\Booking;
|
|
use App\Entity\BookingCustomer;
|
|
use App\Entity\BookingRoom;
|
|
use App\Repository\BookingRepository;
|
|
use App\Repository\RoomCategoryRepository;
|
|
use App\Repository\RoomAvailabilityRepository;
|
|
use App\Request\BookingCreateRequest;
|
|
use App\Request\BookingDetailsRequest;
|
|
use App\Response\BookingCreateResponse;
|
|
use App\Service\PricesService;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Nelmio\ApiDocBundle\Annotation\Model;
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
|
use Symfony\Component\Routing\Attribute\Route;
|
|
use OpenApi\Attributes as OA;
|
|
|
|
class BookingController extends AbstractController
|
|
{
|
|
/**
|
|
* Get booking details
|
|
*/
|
|
#[Route('/api/booking/details', name: 'app_booking_details', methods: ["POST"])]
|
|
#[OA\Tag(name: "Booking")]
|
|
#[OA\Response(
|
|
response: 200,
|
|
description: 'Returns booking details',
|
|
content: new OA\JsonContent(
|
|
type: 'object',
|
|
ref: new Model(type: Booking::class),
|
|
)
|
|
)]
|
|
#[OA\RequestBody(
|
|
content: new OA\JsonContent(
|
|
type: 'object',
|
|
ref: new Model(type: BookingDetailsRequest::class),
|
|
)
|
|
)]
|
|
public function getBookingDetails(Request $request, BookingRepository $repoBooking): JsonResponse
|
|
{
|
|
$payload = $request->toArray();
|
|
if (\is_null($payload)) {
|
|
throw new \Exception('Invalid Payload', 400);
|
|
}
|
|
|
|
$refNumber = $payload["refNumber"];
|
|
$customerEmail = $payload["email"];
|
|
|
|
$bookingList = $repoBooking->findBy(["refNumber" => $refNumber]);
|
|
if (\is_null($bookingList) || \count($bookingList) == 0) {
|
|
throw new HttpException(404, 'Invalid Booking');
|
|
}
|
|
|
|
$customerBooking = $bookingList[0];
|
|
if ($customerBooking->getBookingCustomer()->getEmail() != $customerEmail) {
|
|
throw new HttpException(404, 'Invalid Booking');
|
|
}
|
|
|
|
return $this->json($customerBooking);
|
|
}
|
|
|
|
/**
|
|
* Create a new Booking.
|
|
*/
|
|
#[Route('/api/booking/create', name: 'app_booking_create', methods: ["POST"])]
|
|
#[OA\Tag(name: "Booking")]
|
|
#[OA\Response(
|
|
response: 200,
|
|
description: 'Returns booking details',
|
|
content: new OA\JsonContent(
|
|
type: 'object',
|
|
ref: new Model(type: BookingCreateResponse::class)
|
|
)
|
|
)]
|
|
#[OA\RequestBody(
|
|
content: new OA\JsonContent(
|
|
type: 'object',
|
|
ref: new Model(type: BookingCreateRequest::class),
|
|
)
|
|
)]
|
|
public function newBooking(Request $request, BookingRepository $repoBooking, EntityManagerInterface $entityManager,
|
|
RoomCategoryRepository $repoCat, RoomAvailabilityRepository $repoAvailability,
|
|
PricesService $priceSrv): JsonResponse
|
|
{
|
|
$payload = $request->toArray();
|
|
if (\is_null($payload)) {
|
|
throw new HttpException('Invalid Payload', 400);
|
|
}
|
|
|
|
|
|
$booking = new Booking();
|
|
try {
|
|
$reqArrivalDate = $payload["arrivalDate"];
|
|
$reqDepartureDate = $payload["departureDate"];
|
|
|
|
$arrivalDate = new \DateTime($reqArrivalDate);
|
|
$departureDate = new \DateTime($reqDepartureDate);
|
|
|
|
if ($arrivalDate >= $departureDate) {
|
|
throw new HttpException(400, "Arrival cant be before departure");
|
|
}
|
|
|
|
$entityManager->beginTransaction();
|
|
|
|
$currentTime = new \DateTime();
|
|
|
|
// Create booking from request data.
|
|
$booking->setBookingTime($currentTime);
|
|
$booking->setArrivalDate($arrivalDate);
|
|
$booking->setDepartureDate($departureDate);
|
|
|
|
$highest_id = $entityManager->createQueryBuilder()
|
|
->select('MAX(e.id)')
|
|
->from('App\Entity\Booking', 'e')
|
|
->getQuery()
|
|
->getSingleScalarResult();
|
|
|
|
$booking->setRefNumber($currentTime->format("Y") . $highest_id + 1);
|
|
|
|
$entityManager->persist($booking);
|
|
|
|
// Create booking customer.
|
|
$reqCustomer = $payload["customerDetails"];
|
|
$bookingCustomer = new BookingCustomer();
|
|
$bookingCustomer->setName($reqCustomer["name"]);
|
|
$bookingCustomer->setSurname($reqCustomer["surname"]);
|
|
$bookingCustomer->setEmail($reqCustomer["email"]);
|
|
$bookingCustomer->setPhoneNumber($reqCustomer["phoneNumber"]);
|
|
$bookingCustomer->setBooking($booking);
|
|
|
|
$entityManager->persist($bookingCustomer);
|
|
|
|
$reqRoomList = $payload["rooms"];
|
|
if (\count($reqRoomList) == 0) {
|
|
throw new HttpException(400, "Se debe indicar al menos una habitación");
|
|
}
|
|
|
|
// Create each room.
|
|
foreach ($reqRoomList as $roomItem) {
|
|
$room = new BookingRoom();
|
|
$room->setBooking($booking);
|
|
|
|
//Get Room category.
|
|
$roomCategory = $repoCat->find($roomItem["roomCategory"]);
|
|
if ($roomCategory == null) {
|
|
throw new HttpException(400, "La RoomCategory no es válida.");
|
|
}
|
|
|
|
//Check room availability.
|
|
$amountAvailable = $repoAvailability->getAvailabilityForCategoryInPeriod($roomCategory, $arrivalDate, $departureDate);
|
|
$selectedAmount = $roomItem['amount'];
|
|
$selectedGuestAmount = $roomItem["guestNumber"];
|
|
|
|
if($amountAvailable == null || $selectedAmount > $amountAvailable) {
|
|
throw new HttpException(400, "No se pueden reservar más habitaciones de las disponibles.");
|
|
}
|
|
|
|
$room->setRoomCategory($roomCategory);
|
|
$room->setGuestNumber($selectedGuestAmount);
|
|
$room->setAmount($selectedAmount);
|
|
|
|
//Get Price for period.
|
|
$priceList = $priceSrv->getFinalPricesForSearch($roomCategory, $arrivalDate, $departureDate);
|
|
$priceFound = false;
|
|
foreach ($priceList as $key => $value) {
|
|
if($key == $selectedGuestAmount) {
|
|
$room->setRoomPrice($value);
|
|
$priceFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!$priceFound) {
|
|
throw new HttpException(
|
|
500,
|
|
"No se puedo obtener el precio para la categoría: " . $roomCategory->getId() . " , guests: " . $selectedGuestAmount
|
|
);
|
|
}
|
|
|
|
$entityManager->persist($room);
|
|
|
|
//If booking is nice, let's update current availability.
|
|
$repoAvailability->updateAvailabilityForRoomCategoryOnPeriod($roomCategory, $arrivalDate, $departureDate, $selectedAmount, true); //Update using "diff" mode.
|
|
}
|
|
|
|
$entityManager->commit();
|
|
$entityManager->flush();
|
|
|
|
} catch (\Throwable $th) {
|
|
$entityManager->rollback();
|
|
throw $th;
|
|
}
|
|
|
|
$results = ["refNumber" => $booking->getRefNumber()];
|
|
|
|
return $this->json($results);
|
|
}
|
|
}
|