API - Search Prices:
CI / Docker Lint (push) Successful in 31s

- Added endpoint to get prices for all RoomCategories.
- Improvements to Prices API.
This commit is contained in:
2025-10-13 14:52:36 +02:00
parent aaae8563c6
commit 7673521708
7 changed files with 234 additions and 42 deletions
+138 -13
View File
@@ -5,9 +5,12 @@ namespace App\Service;
use App\Entity\FareTable;
use App\Entity\RoomCategory;
use App\Repository\FareTableRepository;
use App\Repository\RoomCategoryRepository;
use App\Repository\RoomFareRepository;
use Doctrine\Common\Collections\ArrayCollection;
use App\Response\SearchPricesResponse;
use App\Response\SearchPricesResponsePriceItem;
use Doctrine\Common\Collections\Collection;
use Ds\Set;
use Psr\Log\LoggerInterface;
/**
@@ -18,11 +21,11 @@ class PricesService
{
public function __construct(
private RoomCategoryRepository $repoRoomCategory,
private FareTableRepository $repoFareTable,
private RoomFareRepository $repoRoomFares,
private LoggerInterface $logger
) {
}
) {}
/**
* Calcula los precios de la estancia para la categoría y periodo indicados.
@@ -43,7 +46,7 @@ class PricesService
$fareTablesForPeriod = $this->repoFareTable->findFareTable($category->getId(), $startDate, $endDate);
//Obtenemos el número de personas permitido por todos los tarifarios activos.
$allowedGuestNumbers = $this->repoFareTable->getAllowedGuestNumberOnFareTableList($fareTablesForPeriod);
$allowedGuestNumbers = $this->getAllowedGuestNumberFromFaretableList($fareTablesForPeriod);
$rs = [];
@@ -70,7 +73,73 @@ class PricesService
}
return $finalResult;
}
/**
* Calculate stay total price on each roomCategory for the given time period
* Returns a list with all roomCategories, containing the total price by guestnumber.
*
* e. g. --> [ 2 => 120€, 3 => 180€ ]
*
* @return SearchPricesResponse[] Total prices for each guestnumber of each roomCategory.
*/
public function getRoomSearch(\DateTimeInterface $startDate, \DateTimeInterface $endDate): array
{
$daysDiff = $startDate->diff($endDate)->days;
if (!$daysDiff) {
$this->logger->warning("PricesService.getFinalPricesForSearch - Invalid search period");
return [];
}
$rs = [];
$roomCategoryList = $this->repoRoomCategory->findAll();
$fareTableList = $this->repoFareTable->getFareTableListForPeriod($startDate, $endDate);
$faretablesByRoomCategory = [];
foreach ($fareTableList as $faretable) {
$faretablesByRoomCategory[$faretable->getRoomCategory()->getId()][] = $faretable;
}
foreach ($roomCategoryList as $roomCat) {
//Get Faretables for RoomCategory.
$roomFaretables = [];
if (array_key_exists($roomCat->getId(), $faretablesByRoomCategory)) {
$roomFaretables = $faretablesByRoomCategory[$roomCat->getId()];
}
//Calculate distinct GuestNumber for RoomCategory by it's faretables.
$allowedGuestNumberList = $this->getAllowedGuestNumberFromFaretableList($roomFaretables);
//Calculate stay price for each allowed GuestNumber.
$roomPricesByGuestNum = [];
foreach ($allowedGuestNumberList as $currentGuestNumber) {
//Calculate the price for each day.
$dailyPrices = $this->getDailyPricesForSearch($startDate, $endDate, $currentGuestNumber, $roomFaretables);
$stayPrice = $this->getTotalPriceForStay($dailyPrices);
$roomPricesByGuestNum[$currentGuestNumber] = $stayPrice;
}
$roomPrices = [];
foreach ($roomPricesByGuestNum as $guestNum => $price) {
$item = new SearchPricesResponsePriceItem();
$item->guestNumber = $guestNum;
$item->price = $price;
$roomPrices[] = $item;
}
$roomItem = new SearchPricesResponse();
$roomItem->roomCategoryId = $roomCat->getId();
$roomItem->prices = $roomPrices;
$rs[] = $roomItem;
}
return $rs;
}
/**
@@ -81,12 +150,12 @@ class PricesService
* @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, ...].
*/
public function getDailyPricesForSearch(\DateTimeInterface $startDate, \DateTimeInterface $endDate, int $guestNumber, array $fareTableList): array
private function getDailyPricesForSearch(\DateTimeInterface $startDate, \DateTimeInterface $endDate, int $guestNumber, array $fareTableList): array
{
$daysDiff = $startDate->diff($endDate)->days;
$dailyPrices = [];
$currentDate = new \DateTime($startDate->format("Y-m-d")); //TODOME: Comprobar si es tipo referencia y está cambiando.
$currentDate = new \DateTime($startDate->format("Y-m-d")); //Copy start date to operate.
for ($i = 0; $i < $daysDiff; $i++) {
$strCurrentDate = $currentDate->format("Y-m-d");
@@ -96,8 +165,16 @@ class PricesService
});
if (count($currentFareTableList) != 1) {
$dailyPrices[$strCurrentDate] = "ERROR - Number of FareTable found: " . count($currentFareTableList);
continue;
$this->logger->error(
"PricesService.getDailyPricesForSearch: Can't calculate prices: Invalid number of FareTable found: " . count($currentFareTableList),
[
"startDate" => $startDate,
"endDate" => $endDate,
"fareTableList" => $fareTableList,
"currentFareTableList" => $currentFareTableList
]
);
return [];
}
$currentFareTable = array_values($currentFareTableList)[0];
@@ -107,8 +184,15 @@ class PricesService
//Si no hay precio, calcular mediante tarifarios.
$roomFares = $currentFareTable->getRoomFaresByGuestNumber($guestNumber);
if (count($roomFares) < 1) {
$dailyPrices[$strCurrentDate] = "ERROR - Invalid RoomFares found";
continue;
$this->logger->error(
"PricesService.getDailyPricesForSearch: Can't calculate prices: Found faretable without fares",
[
"currentFareTable" => $currentFareTable,
"guestNumber" => $guestNumber,
"roomFaresForGuestNumber" => $roomFares
]
);
return [];
}
//Si sólo hay 1 tarifa, aplico esa, sino calculo la apropiada según condiciones.
@@ -134,10 +218,14 @@ class PricesService
* @param DateTimeInterface $fareCondDate Fecha utilizada para las condiciones.
*
*/
public function calculateFareApplyingConditions(ArrayCollection $roomFareList, \DateTimeInterface $fareCondDate): int
private function calculateFareApplyingConditions(Collection $roomFareList, \DateTimeInterface $fareCondDate): int
{
$currentDayOfWeek = $fareCondDate->format("w");
if (count($roomFareList) == 1) {
return $roomFareList->first()->getFareAmount();
}
//Comprobamos si a alguna de las tarifas se la aplica la condición de "DayType" y coincide con el actual.
// Si es así, devolvemos su valor.
foreach ($roomFareList as $roomFare) {
@@ -145,7 +233,7 @@ class PricesService
if ($dayType == null || $dayType == "") {
continue;
}
if($dayType == $currentDayOfWeek) {
if ($dayType == $currentDayOfWeek) {
return $roomFare->getFareAmount();
}
}
@@ -157,4 +245,41 @@ class PricesService
return $faresWithoutConditions->first()->getFareAmount();
}
/**
* Gets a list of allowed GuestNumbers from a list of FareTables.
* @param FareTable[] $faretableList List of Faretables
* @return int[] Array of allowed guestNumbers from faretable list.
*/
private function getAllowedGuestNumberFromFaretableList(array $faretableList): array
{
if (count($faretableList) == 0) {
return [];
}
$guestSet = new Set();
foreach ($faretableList as $table) {
$fares = $table->getRoomFares();
foreach ($fares as $roomFare) {
$guestSet->add($roomFare->getGuestNumber());
}
}
return $guestSet->toArray();
}
/**
* Calculate total stay price given a list of prices.
* @param array $dailyPrices Array containing the price for each day.
* @return int Total stay price.
*/
private function getTotalPriceForStay(array $dailyPrices): int
{
// TODOME: Crear y configurar diversas estrategias de precios -> Por el momento utilizamos "Suma del precio de cada día".
$finalAmount = \array_reduce($dailyPrices, function ($acc, $element) {
return $acc + $element;
});
return $finalAmount;
}
}