Merge range rate data into availability-range and remove old rate endpoint
All checks were successful
build-and-deploy / build-deploy (push) Successful in 37s

This commit is contained in:
androidlover5842
2026-02-04 17:38:02 +05:30
parent 2950af3332
commit cb6fb94bf7
3 changed files with 13 additions and 86 deletions

View File

@@ -1004,6 +1004,7 @@ ROOM TYPE + ROOMS + ROOM IMAGES
What it does: What it does:
- Returns free rooms in date range. - Returns free rooms in date range.
- Includes per-room-type average rate (`averageRate`, `currency`, `ratePlanCode`).
- Uses forecast logic for active stays: if `toAt` is null, occupancy is considered up to booking `expectedCheckOutAt` (if present). - 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. - Active stays with no expected checkout are treated as occupied.
@@ -1013,34 +1014,6 @@ ROOM TYPE + ROOMS + ROOM IMAGES
Query params: Query params:
- from=YYYY-MM-DD
- to=YYYY-MM-DD
- Allowed roles: property member.
Error Codes
- 400 Bad Request (invalid date/range)
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found (property)
- Availability with rate API is this one:
GET /properties/{propertyId}/rooms/available-range-with-rate
What it does:
- Returns available rooms with average rate over date range.
- Uses same forecast occupancy logic as availability-range.
Request body:
- None.
Query params:
- from=YYYY-MM-DD - from=YYYY-MM-DD
- to=YYYY-MM-DD - to=YYYY-MM-DD
- ratePlanCode (optional) - ratePlanCode (optional)

View File

@@ -27,16 +27,10 @@ data class RoomAvailabilityResponse(
) )
data class RoomAvailabilityRangeResponse( data class RoomAvailabilityRangeResponse(
val roomTypeName: String,
val freeRoomNumbers: List<Int>,
val freeCount: Int
)
data class RoomAvailabilityWithRateResponse(
val roomId: UUID,
val roomNumber: Int,
val roomTypeCode: String, val roomTypeCode: String,
val roomTypeName: String, val roomTypeName: String,
val freeRoomNumbers: List<Int>,
val freeCount: Int,
val averageRate: Double?, val averageRate: Double?,
val currency: String, val currency: String,
val ratePlanCode: String? = null val ratePlanCode: String? = null

View File

@@ -7,7 +7,6 @@ import com.android.trisolarisserver.component.auth.PropertyAccess
import com.android.trisolarisserver.component.room.RoomBoardEvents import com.android.trisolarisserver.component.room.RoomBoardEvents
import com.android.trisolarisserver.controller.dto.room.RoomAvailabilityRangeResponse import com.android.trisolarisserver.controller.dto.room.RoomAvailabilityRangeResponse
import com.android.trisolarisserver.controller.dto.room.RoomAvailabilityResponse import com.android.trisolarisserver.controller.dto.room.RoomAvailabilityResponse
import com.android.trisolarisserver.controller.dto.room.RoomAvailabilityWithRateResponse
import com.android.trisolarisserver.controller.dto.room.RoomBoardResponse import com.android.trisolarisserver.controller.dto.room.RoomBoardResponse
import com.android.trisolarisserver.controller.dto.room.RoomBoardStatus import com.android.trisolarisserver.controller.dto.room.RoomBoardStatus
import com.android.trisolarisserver.controller.dto.room.RoomResponse import com.android.trisolarisserver.controller.dto.room.RoomResponse
@@ -185,7 +184,8 @@ class Rooms(
@PathVariable propertyId: UUID, @PathVariable propertyId: UUID,
@AuthenticationPrincipal principal: MyPrincipal?, @AuthenticationPrincipal principal: MyPrincipal?,
@org.springframework.web.bind.annotation.RequestParam("from") from: String, @org.springframework.web.bind.annotation.RequestParam("from") from: String,
@org.springframework.web.bind.annotation.RequestParam("to") to: String @org.springframework.web.bind.annotation.RequestParam("to") to: String,
@org.springframework.web.bind.annotation.RequestParam("ratePlanCode", required = false) ratePlanCode: String?
): List<RoomAvailabilityRangeResponse> { ): List<RoomAvailabilityRangeResponse> {
requirePrincipal(principal) requirePrincipal(principal)
propertyAccess.requireMember(propertyId, principal!!.userId) propertyAccess.requireMember(propertyId, principal!!.userId)
@@ -205,53 +205,13 @@ class Rooms(
val rooms = roomRepo.findByPropertyIdOrderByRoomNumber(propertyId) val rooms = roomRepo.findByPropertyIdOrderByRoomNumber(propertyId)
val occupiedRoomIds = findForecastOccupiedRoomIds(propertyId, fromAt, toAt) 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 }
return grouped.entries.map { (typeName, roomList) ->
RoomAvailabilityRangeResponse(
roomTypeName = typeName,
freeRoomNumbers = roomList.map { it.roomNumber },
freeCount = roomList.size
)
}.sortedBy { it.roomTypeName }
}
@GetMapping("/available-range-with-rate")
fun availableRoomsWithRate(
@PathVariable propertyId: UUID,
@AuthenticationPrincipal principal: MyPrincipal?,
@org.springframework.web.bind.annotation.RequestParam("from") from: String,
@org.springframework.web.bind.annotation.RequestParam("to") to: String,
@org.springframework.web.bind.annotation.RequestParam("ratePlanCode", required = false) ratePlanCode: String?
): List<RoomAvailabilityWithRateResponse> {
requirePrincipal(principal)
propertyAccess.requireMember(propertyId, principal!!.userId)
val property = propertyRepo.findById(propertyId).orElseThrow {
ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
}
val fromDate = parseDate(from, "Invalid date format")
val toDate = parseDate(to, "Invalid date format")
if (!toDate.isAfter(fromDate)) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid date range")
}
val zone = ZoneId.of(property.timezone)
val fromAt = fromDate.atStartOfDay(zone).toOffsetDateTime()
val toAt = toDate.atStartOfDay(zone).toOffsetDateTime()
val rooms = roomRepo.findByPropertyIdOrderByRoomNumber(propertyId)
val occupiedRoomIds = findForecastOccupiedRoomIds(propertyId, fromAt, toAt)
val freeRooms = rooms.filter { it.active && !it.maintenance && !occupiedRoomIds.contains(it.id) }
if (freeRooms.isEmpty()) return emptyList()
val plans = ratePlanRepo.findByPropertyIdOrderByCode(propertyId) val plans = ratePlanRepo.findByPropertyIdOrderByCode(propertyId)
val plansByRoomType = plans.groupBy { it.roomType.id!! } val plansByRoomType = plans.groupBy { it.roomType.id!! }
val averageCache = mutableMapOf<UUID, RateAverage>() val averageCache = mutableMapOf<UUID, RateAverage>()
val freeRooms = rooms.filter { it.active && !it.maintenance && !occupiedRoomIds.contains(it.id) }
return freeRooms.map { room -> val grouped = freeRooms.groupBy { it.roomType.id!! }
val roomType = room.roomType return grouped.values.map { roomList ->
val roomType = roomList.first().roomType
val chosenPlan = selectRatePlan(plansByRoomType[roomType.id!!], ratePlanCode) val chosenPlan = selectRatePlan(plansByRoomType[roomType.id!!], ratePlanCode)
val average = when { val average = when {
chosenPlan != null -> averageCache.getOrPut(chosenPlan.id!!) { chosenPlan != null -> averageCache.getOrPut(chosenPlan.id!!) {
@@ -261,16 +221,16 @@ class Rooms(
roomType.defaultRate != null -> RateAverage(roomType.defaultRate!!.toDouble(), property.currency, null) roomType.defaultRate != null -> RateAverage(roomType.defaultRate!!.toDouble(), property.currency, null)
else -> RateAverage(null, property.currency, null) else -> RateAverage(null, property.currency, null)
} }
RoomAvailabilityWithRateResponse( RoomAvailabilityRangeResponse(
roomId = room.id!!,
roomNumber = room.roomNumber,
roomTypeCode = roomType.code, roomTypeCode = roomType.code,
roomTypeName = roomType.name, roomTypeName = roomType.name,
freeRoomNumbers = roomList.map { it.roomNumber },
freeCount = roomList.size,
averageRate = average.averageRate, averageRate = average.averageRate,
currency = average.currency, currency = average.currency,
ratePlanCode = average.ratePlanCode ratePlanCode = average.ratePlanCode
) )
} }.sortedBy { it.roomTypeName }
} }
@PostMapping @PostMapping