From cb6fb94bf788179cd74b27592c5074b72dc7c2b6 Mon Sep 17 00:00:00 2001 From: androidlover5842 Date: Wed, 4 Feb 2026 17:38:02 +0530 Subject: [PATCH] Merge range rate data into availability-range and remove old rate endpoint --- docs/API_REFERENCE.txt | 29 +-------- .../controller/dto/room/RoomDtos.kt | 10 +--- .../trisolarisserver/controller/room/Rooms.kt | 60 ++++--------------- 3 files changed, 13 insertions(+), 86 deletions(-) diff --git a/docs/API_REFERENCE.txt b/docs/API_REFERENCE.txt index 9714d2d..b08f84f 100644 --- a/docs/API_REFERENCE.txt +++ b/docs/API_REFERENCE.txt @@ -1004,6 +1004,7 @@ ROOM TYPE + ROOMS + ROOM IMAGES What it does: - 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). - Active stays with no expected checkout are treated as occupied. @@ -1013,34 +1014,6 @@ ROOM TYPE + ROOMS + ROOM IMAGES 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 - to=YYYY-MM-DD - ratePlanCode (optional) diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/dto/room/RoomDtos.kt b/src/main/kotlin/com/android/trisolarisserver/controller/dto/room/RoomDtos.kt index 9c56770..c4101b5 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/dto/room/RoomDtos.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/dto/room/RoomDtos.kt @@ -27,16 +27,10 @@ data class RoomAvailabilityResponse( ) data class RoomAvailabilityRangeResponse( - val roomTypeName: String, - val freeRoomNumbers: List, - val freeCount: Int -) - -data class RoomAvailabilityWithRateResponse( - val roomId: UUID, - val roomNumber: Int, val roomTypeCode: String, val roomTypeName: String, + val freeRoomNumbers: List, + val freeCount: Int, val averageRate: Double?, val currency: String, val ratePlanCode: String? = null diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt b/src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt index 80f68b1..a24ead3 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/room/Rooms.kt @@ -7,7 +7,6 @@ import com.android.trisolarisserver.component.auth.PropertyAccess import com.android.trisolarisserver.component.room.RoomBoardEvents import com.android.trisolarisserver.controller.dto.room.RoomAvailabilityRangeResponse 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.RoomBoardStatus import com.android.trisolarisserver.controller.dto.room.RoomResponse @@ -185,7 +184,8 @@ class Rooms( @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("to") to: String, + @org.springframework.web.bind.annotation.RequestParam("ratePlanCode", required = false) ratePlanCode: String? ): List { requirePrincipal(principal) propertyAccess.requireMember(propertyId, principal!!.userId) @@ -205,53 +205,13 @@ class Rooms( val rooms = roomRepo.findByPropertyIdOrderByRoomNumber(propertyId) 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 { - 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 plansByRoomType = plans.groupBy { it.roomType.id!! } val averageCache = mutableMapOf() - - return freeRooms.map { room -> - val roomType = room.roomType + val freeRooms = rooms.filter { it.active && !it.maintenance && !occupiedRoomIds.contains(it.id) } + val grouped = freeRooms.groupBy { it.roomType.id!! } + return grouped.values.map { roomList -> + val roomType = roomList.first().roomType val chosenPlan = selectRatePlan(plansByRoomType[roomType.id!!], ratePlanCode) val average = when { chosenPlan != null -> averageCache.getOrPut(chosenPlan.id!!) { @@ -261,16 +221,16 @@ class Rooms( roomType.defaultRate != null -> RateAverage(roomType.defaultRate!!.toDouble(), property.currency, null) else -> RateAverage(null, property.currency, null) } - RoomAvailabilityWithRateResponse( - roomId = room.id!!, - roomNumber = room.roomNumber, + RoomAvailabilityRangeResponse( roomTypeCode = roomType.code, roomTypeName = roomType.name, + freeRoomNumbers = roomList.map { it.roomNumber }, + freeCount = roomList.size, averageRate = average.averageRate, currency = average.currency, ratePlanCode = average.ratePlanCode ) - } + }.sortedBy { it.roomTypeName } } @PostMapping