Add forecast occupancy logic for room availability range APIs
All checks were successful
build-and-deploy / build-deploy (push) Successful in 37s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 37s
This commit is contained in:
@@ -1004,6 +1004,8 @@ ROOM TYPE + ROOMS + ROOM IMAGES
|
||||
What it does:
|
||||
|
||||
- Returns free rooms in date range.
|
||||
- Uses forecast logic for active stays: if `toAt` is null, occupancy is considered up to booking `expectedCheckOutAt` (if present).
|
||||
- Active stays with no expected checkout are treated as occupied.
|
||||
|
||||
Request body:
|
||||
|
||||
@@ -1031,6 +1033,7 @@ ROOM TYPE + ROOMS + ROOM IMAGES
|
||||
What it does:
|
||||
|
||||
- Returns available rooms with average rate over date range.
|
||||
- Uses same forecast occupancy logic as availability-range.
|
||||
|
||||
Request body:
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ class Rooms(
|
||||
val toAt = toDate.atStartOfDay(zone).toOffsetDateTime()
|
||||
|
||||
val rooms = roomRepo.findByPropertyIdOrderByRoomNumber(propertyId)
|
||||
val occupiedRoomIds = roomStayRepo.findOccupiedRoomIdsBetween(propertyId, fromAt, toAt).toHashSet()
|
||||
val occupiedRoomIds = findForecastOccupiedRoomIds(propertyId, fromAt, toAt)
|
||||
|
||||
val freeRooms = rooms.filter { it.active && !it.maintenance && !occupiedRoomIds.contains(it.id) }
|
||||
val grouped = freeRooms.groupBy { it.roomType.name }
|
||||
@@ -242,7 +242,7 @@ class Rooms(
|
||||
val toAt = toDate.atStartOfDay(zone).toOffsetDateTime()
|
||||
|
||||
val rooms = roomRepo.findByPropertyIdOrderByRoomNumber(propertyId)
|
||||
val occupiedRoomIds = roomStayRepo.findOccupiedRoomIdsBetween(propertyId, fromAt, toAt).toHashSet()
|
||||
val occupiedRoomIds = findForecastOccupiedRoomIds(propertyId, fromAt, toAt)
|
||||
val freeRooms = rooms.filter { it.active && !it.maintenance && !occupiedRoomIds.contains(it.id) }
|
||||
if (freeRooms.isEmpty()) return emptyList()
|
||||
|
||||
@@ -447,6 +447,23 @@ class Rooms(
|
||||
.mapValues { (_, cards) -> cards.maxBy { it.expiresAt }.expiresAt }
|
||||
}
|
||||
|
||||
private fun findForecastOccupiedRoomIds(
|
||||
propertyId: UUID,
|
||||
fromAt: OffsetDateTime,
|
||||
toAt: OffsetDateTime
|
||||
): Set<UUID> {
|
||||
val occupied = roomStayRepo.findOccupiedRoomIdsBetweenClosed(propertyId, fromAt, toAt).toMutableSet()
|
||||
val activeRows = roomStayRepo.findActiveForecastRows(propertyId, toAt)
|
||||
activeRows
|
||||
.asSequence()
|
||||
.filter { row ->
|
||||
val expectedCheckoutAt = row.expectedCheckoutAt
|
||||
expectedCheckoutAt == null || expectedCheckoutAt.isAfter(fromAt)
|
||||
}
|
||||
.mapTo(occupied) { it.roomId }
|
||||
return occupied
|
||||
}
|
||||
|
||||
private fun prepareSse(response: HttpServletResponse) {
|
||||
response.setHeader("Cache-Control", "no-cache")
|
||||
response.setHeader("Connection", "keep-alive")
|
||||
|
||||
@@ -30,6 +30,37 @@ interface RoomStayRepo : JpaRepository<RoomStay, UUID> {
|
||||
@Param("toAt") toAt: java.time.OffsetDateTime
|
||||
): List<UUID>
|
||||
|
||||
@Query("""
|
||||
select distinct rs.room.id
|
||||
from RoomStay rs
|
||||
where rs.property.id = :propertyId
|
||||
and rs.isVoided = false
|
||||
and rs.toAt is not null
|
||||
and rs.fromAt < :toAt
|
||||
and rs.toAt > :fromAt
|
||||
""")
|
||||
fun findOccupiedRoomIdsBetweenClosed(
|
||||
@Param("propertyId") propertyId: UUID,
|
||||
@Param("fromAt") fromAt: java.time.OffsetDateTime,
|
||||
@Param("toAt") toAt: java.time.OffsetDateTime
|
||||
): List<UUID>
|
||||
|
||||
@Query("""
|
||||
select rs.room.id as roomId,
|
||||
rs.fromAt as fromAt,
|
||||
b.expectedCheckoutAt as expectedCheckoutAt
|
||||
from RoomStay rs
|
||||
join rs.booking b
|
||||
where rs.property.id = :propertyId
|
||||
and rs.isVoided = false
|
||||
and rs.toAt is null
|
||||
and rs.fromAt < :toAt
|
||||
""")
|
||||
fun findActiveForecastRows(
|
||||
@Param("propertyId") propertyId: UUID,
|
||||
@Param("toAt") toAt: java.time.OffsetDateTime
|
||||
): List<ActiveRoomStayForecastRow>
|
||||
|
||||
@Query("""
|
||||
select rs
|
||||
from RoomStay rs
|
||||
@@ -163,3 +194,9 @@ interface BookingRoomNumberRow {
|
||||
val bookingId: UUID
|
||||
val roomNumber: Int
|
||||
}
|
||||
|
||||
interface ActiveRoomStayForecastRow {
|
||||
val roomId: UUID
|
||||
val fromAt: java.time.OffsetDateTime
|
||||
val expectedCheckoutAt: java.time.OffsetDateTime?
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user