pre assign rooms before checkin
This commit is contained in:
@@ -5,6 +5,7 @@ import com.android.trisolarisserver.controller.dto.BookingCancelRequest
|
|||||||
import com.android.trisolarisserver.controller.dto.BookingCheckInRequest
|
import com.android.trisolarisserver.controller.dto.BookingCheckInRequest
|
||||||
import com.android.trisolarisserver.controller.dto.BookingCheckOutRequest
|
import com.android.trisolarisserver.controller.dto.BookingCheckOutRequest
|
||||||
import com.android.trisolarisserver.controller.dto.BookingNoShowRequest
|
import com.android.trisolarisserver.controller.dto.BookingNoShowRequest
|
||||||
|
import com.android.trisolarisserver.controller.dto.RoomStayPreAssignRequest
|
||||||
import com.android.trisolarisserver.db.repo.BookingRepo
|
import com.android.trisolarisserver.db.repo.BookingRepo
|
||||||
import com.android.trisolarisserver.models.booking.BookingStatus
|
import com.android.trisolarisserver.models.booking.BookingStatus
|
||||||
import com.android.trisolarisserver.models.booking.TransportMode
|
import com.android.trisolarisserver.models.booking.TransportMode
|
||||||
@@ -172,6 +173,50 @@ class BookingFlow(
|
|||||||
bookingRepo.save(booking)
|
bookingRepo.save(booking)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{bookingId}/room-stays")
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
@Transactional
|
||||||
|
fun preAssignRoom(
|
||||||
|
@PathVariable propertyId: UUID,
|
||||||
|
@PathVariable bookingId: UUID,
|
||||||
|
@AuthenticationPrincipal principal: MyPrincipal?,
|
||||||
|
@RequestBody request: RoomStayPreAssignRequest
|
||||||
|
) {
|
||||||
|
val actor = requireActor(propertyId, principal)
|
||||||
|
val booking = requireBooking(propertyId, bookingId)
|
||||||
|
if (booking.status == BookingStatus.CANCELLED || booking.status == BookingStatus.NO_SHOW || booking.status == BookingStatus.CHECKED_OUT) {
|
||||||
|
throw ResponseStatusException(HttpStatus.CONFLICT, "Booking closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
val room = roomRepo.findByIdAndPropertyId(request.roomId, propertyId)
|
||||||
|
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Room not found")
|
||||||
|
if (!room.active || room.maintenance) {
|
||||||
|
throw ResponseStatusException(HttpStatus.CONFLICT, "Room not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
val fromAt = parseOffset(request.fromAt)
|
||||||
|
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "fromAt required")
|
||||||
|
val toAt = parseOffset(request.toAt)
|
||||||
|
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "toAt required")
|
||||||
|
if (!toAt.isAfter(fromAt)) {
|
||||||
|
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid date range")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roomStayRepo.existsOverlap(propertyId, request.roomId, fromAt, toAt)) {
|
||||||
|
throw ResponseStatusException(HttpStatus.CONFLICT, "Room already reserved/occupied for range")
|
||||||
|
}
|
||||||
|
|
||||||
|
val stay = RoomStay(
|
||||||
|
property = booking.property,
|
||||||
|
booking = booking,
|
||||||
|
room = room,
|
||||||
|
fromAt = fromAt,
|
||||||
|
toAt = toAt,
|
||||||
|
createdBy = actor
|
||||||
|
)
|
||||||
|
roomStayRepo.save(stay)
|
||||||
|
}
|
||||||
|
|
||||||
private fun requireBooking(propertyId: UUID, bookingId: UUID): com.android.trisolarisserver.models.booking.Booking {
|
private fun requireBooking(propertyId: UUID, bookingId: UUID): com.android.trisolarisserver.models.booking.Booking {
|
||||||
val booking = bookingRepo.findById(bookingId).orElseThrow {
|
val booking = bookingRepo.findById(bookingId).orElseThrow {
|
||||||
ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found")
|
ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found")
|
||||||
|
|||||||
@@ -38,3 +38,10 @@ data class RoomChangeResponse(
|
|||||||
val newRoomId: UUID,
|
val newRoomId: UUID,
|
||||||
val movedAt: String
|
val movedAt: String
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class RoomStayPreAssignRequest(
|
||||||
|
val roomId: UUID,
|
||||||
|
val fromAt: String,
|
||||||
|
val toAt: String,
|
||||||
|
val notes: String? = null
|
||||||
|
)
|
||||||
|
|||||||
@@ -47,4 +47,19 @@ interface RoomStayRepo : JpaRepository<RoomStay, UUID> {
|
|||||||
@Param("propertyId") propertyId: UUID,
|
@Param("propertyId") propertyId: UUID,
|
||||||
@Param("roomIds") roomIds: List<UUID>
|
@Param("roomIds") roomIds: List<UUID>
|
||||||
): List<UUID>
|
): List<UUID>
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
select case when count(rs) > 0 then true else false end
|
||||||
|
from RoomStay rs
|
||||||
|
where rs.property.id = :propertyId
|
||||||
|
and rs.room.id = :roomId
|
||||||
|
and rs.fromAt < :toAt
|
||||||
|
and (rs.toAt is null or rs.toAt > :fromAt)
|
||||||
|
""")
|
||||||
|
fun existsOverlap(
|
||||||
|
@Param("propertyId") propertyId: UUID,
|
||||||
|
@Param("roomId") roomId: UUID,
|
||||||
|
@Param("fromAt") fromAt: java.time.OffsetDateTime,
|
||||||
|
@Param("toAt") toAt: java.time.OffsetDateTime
|
||||||
|
): Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user