feat: add raw contingent availability endpoint
This commit is contained in:
1 parent
7c8dbeef48
commit
ec36b61275
6 files changed
+189
-12
No files matched your search
@@ -181,6 +181,117 @@ class ContingentControllerTest extends TestCase
|
||||
$this->callCalendar([], null, null, $priceRepository);
|
||||
}
|
||||
|
||||
public function testAvailabilityKeepsTheStatusOfUnpricedDays(): void
|
||||
{
|
||||
$data = json_decode((string) $this->callAvailability([
|
||||
'2026-09-01' => ContingentStatus::Ok,
|
||||
'2026-09-02' => ContingentStatus::OnRequest,
|
||||
'2026-09-03' => ContingentStatus::Blocked,
|
||||
])->getContent(), true);
|
||||
|
||||
// The opposite of testCalendarServesTheSnapshotStatuses: no price here, and nothing is blocked for it.
|
||||
self::assertSame(['OK', 'ON_REQUEST', 'BLOCKED'], array_column($data, 'status'));
|
||||
}
|
||||
|
||||
public function testAvailabilityLeavesOutDaysMissingFromTheSnapshot(): void
|
||||
{
|
||||
$data = json_decode((string) $this->callAvailability([
|
||||
'2026-09-03' => ContingentStatus::Blocked,
|
||||
'2026-09-01' => ContingentStatus::Ok,
|
||||
])->getContent(), true);
|
||||
|
||||
self::assertSame([
|
||||
['date' => '2026-09-01', 'status' => 'OK'],
|
||||
['date' => '2026-09-03', 'status' => 'BLOCKED'],
|
||||
], $data);
|
||||
}
|
||||
|
||||
public function testAvailabilityFailsLoudlyWhenThereIsNoUsableSnapshot(): void
|
||||
{
|
||||
$response = $this->callAvailability(null);
|
||||
|
||||
self::assertSame(Response::HTTP_BAD_GATEWAY, $response->getStatusCode());
|
||||
self::assertSame('{"error":"Failed to fetch contingent data."}', $response->getContent());
|
||||
}
|
||||
|
||||
public function testAvailabilityRejectsAnUnknownHotel(): void
|
||||
{
|
||||
$accommodationRepository = $this->createStub(AccommodationRepository::class);
|
||||
$accommodationRepository->method('findOneBy')->willReturn(null);
|
||||
|
||||
$response = $this->callAvailability([], accommodationRepository: $accommodationRepository);
|
||||
|
||||
self::assertSame(Response::HTTP_BAD_REQUEST, $response->getStatusCode());
|
||||
self::assertSame('{"error":"Hotel not found for hotelCode."}', $response->getContent());
|
||||
}
|
||||
|
||||
public function testAvailabilityWithoutARangeReadsFromTodayToTheEndOfTheSnapshot(): void
|
||||
{
|
||||
CarbonImmutable::setTestNow('2026-10-29 09:00:00');
|
||||
|
||||
$snapshotReader = $this->createMock(ContingentSnapshotReader::class);
|
||||
$snapshotReader->expects(self::once())
|
||||
->method('statusesFor')
|
||||
->with(
|
||||
self::anything(),
|
||||
self::callback(fn (\DateTimeImmutable $from) => '2026-10-29 00:00:00' === $from->format('Y-m-d H:i:s')),
|
||||
self::isNull(),
|
||||
)
|
||||
->willReturn([]);
|
||||
|
||||
$response = $this->callAvailability(null, new ContingentCalendarQuery('HOTEL1'), $snapshotReader);
|
||||
|
||||
self::assertSame(Response::HTTP_OK, $response->getStatusCode());
|
||||
self::assertSame('[]', $response->getContent());
|
||||
}
|
||||
|
||||
public function testAvailabilityWithARangePassesItThrough(): void
|
||||
{
|
||||
$snapshotReader = $this->createMock(ContingentSnapshotReader::class);
|
||||
$snapshotReader->expects(self::once())
|
||||
->method('statusesFor')
|
||||
->with(self::anything(), new \DateTimeImmutable('2026-09-01'), new \DateTimeImmutable('2026-09-03'))
|
||||
->willReturn([]);
|
||||
|
||||
$this->callAvailability(null, snapshotReader: $snapshotReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, ContingentStatus>|null $statuses
|
||||
*/
|
||||
private function callAvailability(
|
||||
?array $statuses,
|
||||
?ContingentCalendarQuery $query = null,
|
||||
?ContingentSnapshotReader $snapshotReader = null,
|
||||
?AccommodationRepository $accommodationRepository = null,
|
||||
): Response {
|
||||
if (null === $accommodationRepository) {
|
||||
$accommodationRepository = $this->createStub(AccommodationRepository::class);
|
||||
$accommodationRepository->method('findOneBy')->willReturn((new Accommodation())->setCalendarCode('HOTEL1')->setCurrency('EUR'));
|
||||
}
|
||||
|
||||
if (null === $snapshotReader) {
|
||||
$snapshotReader = $this->createStub(ContingentSnapshotReader::class);
|
||||
$snapshotReader->method('statusesFor')->willReturn($statuses);
|
||||
}
|
||||
|
||||
// Prices play no part in this endpoint, so any call to their repository is a failure.
|
||||
$priceRepository = $this->createMock(AccommodationPriceRepository::class);
|
||||
$priceRepository->expects(self::never())->method(self::anything());
|
||||
|
||||
$controller = new ContingentController(
|
||||
$accommodationRepository,
|
||||
$priceRepository,
|
||||
$snapshotReader,
|
||||
new PriceTimelineBuilder(),
|
||||
new AccommodationPriceCoverage($this->createStub(AccommodationPriceRepository::class)),
|
||||
$this->createStub(LoggerInterface::class),
|
||||
);
|
||||
$controller->setContainer(new Container());
|
||||
|
||||
return $controller->availability($query ?? new ContingentCalendarQuery('HOTEL1', '2026-09-01', '2026-09-03'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{from: \DateTimeImmutable, to: \DateTimeImmutable}|null $bounds
|
||||
* @param AccommodationPrice[] $prices
|
||||
|
||||
Reference in new issue
Block a user