API - Search Prices - Added RoomPrices
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20251017201308 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
CREATE TABLE room_price (date VARCHAR(10) NOT NULL, guest_number SMALLINT NOT NULL, price INT NOT NULL, room_category_id INT NOT NULL, PRIMARY KEY(room_category_id, date, guest_number))
|
||||||
|
SQL);
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
CREATE INDEX IDX_8074837267333DD ON room_price (room_category_id)
|
||||||
|
SQL);
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE room_price ADD CONSTRAINT FK_8074837267333DD FOREIGN KEY (room_category_id) REFERENCES room_category (id) NOT DEFERRABLE INITIALLY IMMEDIATE
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE room_price DROP CONSTRAINT FK_8074837267333DD
|
||||||
|
SQL);
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
DROP TABLE room_price
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -162,11 +162,7 @@ class SearchRoomsController extends AbstractController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$fareList = $priceService->getFinalPricesForSearch($roomCategory, $searchRequest->startDate, $searchRequest->endDate);
|
$rs = $priceService->getFinalPricesForSearch($roomCategory, $searchRequest->startDate, $searchRequest->endDate);
|
||||||
$rs = [];
|
|
||||||
foreach ($fareList as $key => $value) {
|
|
||||||
$rs[] = ["guestNumber" => $key, "price" => $value];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->json(["results" => $rs]);
|
return $this->json(["results" => $rs]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\RoomPriceRepository;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: RoomPriceRepository::class)]
|
||||||
|
class RoomPrice
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\ManyToOne]
|
||||||
|
#[ORM\JoinColumn(nullable: false)]
|
||||||
|
private ?RoomCategory $roomCategory = null;
|
||||||
|
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\Column(length: 10, nullable: false)]
|
||||||
|
private ?string $date = null;
|
||||||
|
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\Column(type: Types::SMALLINT, nullable: false)]
|
||||||
|
private ?int $guestNumber = null;
|
||||||
|
|
||||||
|
#[ORM\Column(nullable: false)]
|
||||||
|
private ?int $price = null;
|
||||||
|
|
||||||
|
|
||||||
|
public function getRoomCategory(): ?RoomCategory
|
||||||
|
{
|
||||||
|
return $this->roomCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRoomCategory(?RoomCategory $roomCategory): static
|
||||||
|
{
|
||||||
|
$this->roomCategory = $roomCategory;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDate(): ?\DateTime
|
||||||
|
{
|
||||||
|
return new \DateTime($this->date);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateString(): ?string
|
||||||
|
{
|
||||||
|
return $this->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDate(\DateTime $date): static
|
||||||
|
{
|
||||||
|
$this->date = $date->format('Y-m-d');
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGuestNumber(): ?int
|
||||||
|
{
|
||||||
|
return $this->guestNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setGuestNumber(int $guestNumber): static
|
||||||
|
{
|
||||||
|
$this->guestNumber = $guestNumber;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrice(): ?int
|
||||||
|
{
|
||||||
|
return $this->price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPrice(int $price): static
|
||||||
|
{
|
||||||
|
$this->price = $price;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\RoomPrice;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<RoomPrice>
|
||||||
|
*/
|
||||||
|
class RoomPriceRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, RoomPrice::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all pricer for the given period.
|
||||||
|
* @param DateTimeInterface $startDate Period start date (included)
|
||||||
|
* @param DateTimeInterface $endDate Period end date (included)
|
||||||
|
* @return RoomPrice[] Array of RoomPrices
|
||||||
|
*/
|
||||||
|
public function getListForPeriod(DateTimeInterface $startDate, DateTimeInterface $endDate, ?int $roomCategoryId = null): array
|
||||||
|
{
|
||||||
|
$strStartDate = $startDate->format('Y-m-d');
|
||||||
|
$strEndDate = $endDate->format('Y-m-d');
|
||||||
|
$hasRoomCategory = $roomCategoryId != null;
|
||||||
|
|
||||||
|
$dql = 'SELECT p, rc FROM App\Entity\RoomPrice p
|
||||||
|
JOIN p.roomCategory rc
|
||||||
|
WHERE p.date >= :startDate
|
||||||
|
AND p.date <= :endDate';
|
||||||
|
|
||||||
|
if ($hasRoomCategory) {
|
||||||
|
$dql .= ' AND IDENTITY(p.roomCategory) = :roomCategoryId';
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->getEntityManager()->createQuery($dql)
|
||||||
|
->setParameter('startDate', $strStartDate)
|
||||||
|
->setParameter('endDate', $strEndDate);
|
||||||
|
|
||||||
|
if ($hasRoomCategory) {
|
||||||
|
$query->setParameter('roomCategoryId', $roomCategoryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return RoomPrice[] Returns an array of RoomPrice objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('r')
|
||||||
|
// ->andWhere('r.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('r.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?RoomPrice
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('r')
|
||||||
|
// ->andWhere('r.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ use App\Entity\RoomFare;
|
|||||||
use App\Repository\FareTableRepository;
|
use App\Repository\FareTableRepository;
|
||||||
use App\Repository\RoomCategoryRepository;
|
use App\Repository\RoomCategoryRepository;
|
||||||
use App\Repository\RoomFareRepository;
|
use App\Repository\RoomFareRepository;
|
||||||
|
use App\Repository\RoomPriceRepository;
|
||||||
use App\Response\SearchPricesResponse;
|
use App\Response\SearchPricesResponse;
|
||||||
use App\Response\SearchPricesResponsePriceItem;
|
use App\Response\SearchPricesResponsePriceItem;
|
||||||
use App\Util\PriceSelectionMethods;
|
use App\Util\PriceSelectionMethods;
|
||||||
@@ -28,7 +29,7 @@ class PricesService
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private RoomCategoryRepository $repoRoomCategory,
|
private RoomCategoryRepository $repoRoomCategory,
|
||||||
private FareTableRepository $repoFareTable,
|
private FareTableRepository $repoFareTable,
|
||||||
private RoomFareRepository $repoRoomFares,
|
private RoomPriceRepository $repoRoomPrices,
|
||||||
private ConfigVariableService $configVarService,
|
private ConfigVariableService $configVarService,
|
||||||
private LoggerInterface $logger
|
private LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
@@ -53,35 +54,40 @@ class PricesService
|
|||||||
}
|
}
|
||||||
|
|
||||||
$fareTablesForPeriod = $this->repoFareTable->findFareTable($category->getId(), $startDate, $endDate);
|
$fareTablesForPeriod = $this->repoFareTable->findFareTable($category->getId(), $startDate, $endDate);
|
||||||
|
$roomPriceList = $this->repoRoomPrices->getListForPeriod($startDate, $endDate, $category->getId());
|
||||||
|
|
||||||
|
//"Organize" RoomPrices.
|
||||||
|
$filteredRoomPriceList = [];
|
||||||
|
foreach ($roomPriceList as $roomPrice) {
|
||||||
|
$priceDate = $roomPrice->getDateString();
|
||||||
|
$filteredRoomPriceList[$roomPrice->getGuestNumber()][$priceDate] = $roomPrice->getPrice();
|
||||||
|
}
|
||||||
|
|
||||||
//Obtenemos el número de personas permitido por todos los tarifarios activos.
|
//Obtenemos el número de personas permitido por todos los tarifarios activos.
|
||||||
$allowedGuestNumbers = $this->getAllowedGuestNumberFromFaretableList($fareTablesForPeriod);
|
$allowedGuestNumberList = $this->getAllowedGuestNumberFromFaretableList($fareTablesForPeriod);
|
||||||
|
|
||||||
$rs = [];
|
//Calculate stay price for each allowed GuestNumber.
|
||||||
|
$priceItems = [];
|
||||||
|
foreach ($allowedGuestNumberList as $currentGuestNumber) {
|
||||||
|
|
||||||
//Calculamos los precios para cada GuestNumber permitido.
|
//Get RoomPrices for current GuestNumber.
|
||||||
foreach ($allowedGuestNumbers as $currentGuestNumber) {
|
$roomPricesForGuestNum = [];
|
||||||
|
if (array_key_exists($currentGuestNumber, $filteredRoomPriceList)) {
|
||||||
//Calculamos el precio de cada día.
|
$roomPricesForGuestNum = $filteredRoomPriceList[$currentGuestNumber];
|
||||||
// e.g. --> [ "2024-04-30" => 20, "2024-05-01" => 28, "2024-05-02" => 20, ...].
|
|
||||||
$dailyPrices = $this->getDailyPricesForSearch($startDate, $endDate, $currentGuestNumber, $fareTablesForPeriod);
|
|
||||||
|
|
||||||
$rs[$currentGuestNumber] = $dailyPrices;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Aplicamos la estrategia de precios configurada para calcular el precio final de la estancia.
|
//Calculate the price for each day.
|
||||||
// TODOME: Crear y configurar diversas estrategias de precios -> Por el momento utilizamos "Suma del precio de cada día".
|
$dailyPrices = $this->getDailyPricesForSearch($startDate, $endDate, $currentGuestNumber, $fareTablesForPeriod, $roomPricesForGuestNum);
|
||||||
|
|
||||||
$finalResult = [];
|
$stayPrice = $this->getTotalPriceForStay($dailyPrices);
|
||||||
foreach ($rs as $guestNum => $priceArray) {
|
|
||||||
$finalAmount = \array_reduce($priceArray, function ($acc, $element) {
|
|
||||||
return $acc + $element;
|
|
||||||
});
|
|
||||||
|
|
||||||
$finalResult[$guestNum] = $finalAmount;
|
$item = new SearchPricesResponsePriceItem();
|
||||||
|
$item->guestNumber = $currentGuestNumber;
|
||||||
|
$item->price = $stayPrice;
|
||||||
|
$priceItems[] = $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $finalResult;
|
return $priceItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,46 +113,57 @@ class PricesService
|
|||||||
$faretablesByRoomCategory[$faretable->getRoomCategory()->getId()][] = $faretable;
|
$faretablesByRoomCategory[$faretable->getRoomCategory()->getId()][] = $faretable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Get and filter prices.
|
||||||
|
$priceList = $this->repoRoomPrices->getListForPeriod($startDate, $endDate);
|
||||||
|
$filteredPrices = [];
|
||||||
|
foreach ($priceList as $price) {
|
||||||
|
$priceDate = $price->getDateString();
|
||||||
|
//Store price in multi-level array by: RoomCategoryId, GuestNumber and Date.
|
||||||
|
$filteredPrices[$price->getRoomCategory()->getId()][$price->getGuestNumber()][$priceDate] = $price->getPrice();
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($roomCategoryList as $roomCat) {
|
foreach ($roomCategoryList as $roomCat) {
|
||||||
|
$currentRoomCategoryId = $roomCat->getId();
|
||||||
|
|
||||||
//Get Faretables for RoomCategory.
|
//Get Faretables for RoomCategory.
|
||||||
$roomFaretables = [];
|
$roomFaretables = [];
|
||||||
if (array_key_exists($roomCat->getId(), $faretablesByRoomCategory)) {
|
if (array_key_exists($currentRoomCategoryId, $faretablesByRoomCategory)) {
|
||||||
$roomFaretables = $faretablesByRoomCategory[$roomCat->getId()];
|
$roomFaretables = $faretablesByRoomCategory[$currentRoomCategoryId];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get RoomPrices for current RoomCategory.
|
||||||
|
$roomPricesForCategory = [];
|
||||||
|
if (array_key_exists($currentRoomCategoryId, $filteredPrices)) {
|
||||||
|
$roomPricesForCategory = $filteredPrices[$currentRoomCategoryId];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Calculate distinct GuestNumber for RoomCategory by it's faretables.
|
//Calculate distinct GuestNumber for RoomCategory by it's faretables.
|
||||||
$allowedGuestNumberList = $this->getAllowedGuestNumberFromFaretableList($roomFaretables);
|
$allowedGuestNumberList = $this->getAllowedGuestNumberFromFaretableList($roomFaretables);
|
||||||
|
|
||||||
//Calculate stay price for each allowed GuestNumber.
|
//Calculate stay price for each allowed GuestNumber.
|
||||||
$roomPricesByGuestNum = [];
|
$priceItems = [];
|
||||||
foreach ($allowedGuestNumberList as $currentGuestNumber) {
|
foreach ($allowedGuestNumberList as $currentGuestNumber) {
|
||||||
|
|
||||||
|
//Get RoomPrices for current GuestNumber.
|
||||||
|
$roomPricesForGuestNum = [];
|
||||||
|
if (array_key_exists($currentGuestNumber, $roomPricesForCategory)) {
|
||||||
|
$roomPricesForGuestNum = $roomPricesForCategory[$currentGuestNumber];
|
||||||
|
}
|
||||||
|
|
||||||
//Calculate the price for each day.
|
//Calculate the price for each day.
|
||||||
$dailyPrices = $this->getDailyPricesForSearch($startDate, $endDate, $currentGuestNumber, $roomFaretables);
|
$dailyPrices = $this->getDailyPricesForSearch($startDate, $endDate, $currentGuestNumber, $roomFaretables, $roomPricesForGuestNum);
|
||||||
|
|
||||||
$stayPrice = $this->getTotalPriceForStay($dailyPrices);
|
$stayPrice = $this->getTotalPriceForStay($dailyPrices);
|
||||||
|
|
||||||
$roomPricesByGuestNum[$currentGuestNumber] = $stayPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
$roomPrices = [];
|
|
||||||
foreach ($roomPricesByGuestNum as $guestNum => $price) {
|
|
||||||
if ($price == null) {
|
|
||||||
$roomPrices = [];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$item = new SearchPricesResponsePriceItem();
|
$item = new SearchPricesResponsePriceItem();
|
||||||
$item->guestNumber = $guestNum;
|
$item->guestNumber = $currentGuestNumber;
|
||||||
$item->price = $price;
|
$item->price = $stayPrice;
|
||||||
|
$priceItems[] = $item;
|
||||||
$roomPrices[] = $item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$roomItem = new SearchPricesResponse();
|
$roomItem = new SearchPricesResponse();
|
||||||
$roomItem->roomCategoryId = $roomCat->getId();
|
$roomItem->roomCategoryId = $roomCat->getId();
|
||||||
$roomItem->prices = $roomPrices;
|
$roomItem->prices = $priceItems;
|
||||||
|
|
||||||
$rs[] = $roomItem;
|
$rs[] = $roomItem;
|
||||||
}
|
}
|
||||||
@@ -162,7 +179,7 @@ class PricesService
|
|||||||
* @param array $fareTableList Array con los tarifarios que aplican en el periodo indicado.
|
* @param array $fareTableList Array con los tarifarios que aplican en el periodo indicado.
|
||||||
* @return array Devuelve un array con los precios: e.g. --> [ "2024-04-30" => 2500, "2024-05-01" => 3500, "2024-05-02" => 3000, ...].
|
* @return array Devuelve un array con los precios: e.g. --> [ "2024-04-30" => 2500, "2024-05-01" => 3500, "2024-05-02" => 3000, ...].
|
||||||
*/
|
*/
|
||||||
private function getDailyPricesForSearch(\DateTimeInterface $startDate, \DateTimeInterface $endDate, int $guestNumber, array $fareTableList): array
|
private function getDailyPricesForSearch(\DateTimeInterface $startDate, \DateTimeInterface $endDate, int $guestNumber, array $fareTableList, array $roomPricesByGuestNum): array
|
||||||
{
|
{
|
||||||
$daysDiff = $startDate->diff($endDate)->days;
|
$daysDiff = $startDate->diff($endDate)->days;
|
||||||
|
|
||||||
@@ -190,11 +207,18 @@ class PricesService
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$currentFareTable = array_values($currentFareTableList)[0];
|
|
||||||
|
|
||||||
//TODOME: -> Obtener precio específico (RoomPrices).
|
//Check for Prices.
|
||||||
|
$roomPrice = null;
|
||||||
|
if (array_key_exists($strCurrentDate, $roomPricesByGuestNum)) {
|
||||||
|
$roomPrice = $roomPricesByGuestNum[$strCurrentDate];
|
||||||
|
}
|
||||||
|
|
||||||
//Si no hay precio, calcular mediante tarifarios.
|
//Si no hay precio, calcular mediante tarifarios.
|
||||||
|
$fareAmount = null;
|
||||||
|
if ($roomPrice == null) {
|
||||||
|
//Get Faretables for guestNumber.
|
||||||
|
$currentFareTable = array_values($currentFareTableList)[0];
|
||||||
$roomFares = $currentFareTable->getRoomFaresByGuestNumber($guestNumber);
|
$roomFares = $currentFareTable->getRoomFaresByGuestNumber($guestNumber);
|
||||||
if (count($roomFares) < 1) {
|
if (count($roomFares) < 1) {
|
||||||
$this->logger->error(
|
$this->logger->error(
|
||||||
@@ -210,13 +234,14 @@ class PricesService
|
|||||||
|
|
||||||
//Calculate RoomFare.
|
//Calculate RoomFare.
|
||||||
$fareAmount = $this->calculateFareApplyingConditions($roomFares, $currentDate);
|
$fareAmount = $this->calculateFareApplyingConditions($roomFares, $currentDate);
|
||||||
|
}
|
||||||
|
|
||||||
//If any price can't be calculated, NO price should be returned.
|
//If any price can't be calculated, NO price should be returned.
|
||||||
if ($fareAmount == null) {
|
if ($roomPrice == null && $fareAmount == null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$dailyPrices[$strCurrentDate] = $fareAmount;
|
$dailyPrices[$strCurrentDate] = $roomPrice ?? $fareAmount;
|
||||||
|
|
||||||
//Add 1 day to current date.
|
//Add 1 day to current date.
|
||||||
$currentDate->add(new \DateInterval("P1D"));
|
$currentDate->add(new \DateInterval("P1D"));
|
||||||
|
|||||||
Reference in New Issue
Block a user