Remove room-stay change-room API
All checks were successful
build-and-deploy / build-deploy (push) Successful in 34s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 34s
This commit is contained in:
@@ -136,20 +136,6 @@ data class BookingNoShowRequest(
|
|||||||
val reason: String? = null
|
val reason: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
data class RoomChangeRequest(
|
|
||||||
val newRoomId: UUID,
|
|
||||||
val movedAt: String? = null,
|
|
||||||
val idempotencyKey: String
|
|
||||||
)
|
|
||||||
|
|
||||||
data class RoomChangeResponse(
|
|
||||||
val oldRoomStayId: UUID,
|
|
||||||
val newRoomStayId: UUID,
|
|
||||||
val oldRoomId: UUID,
|
|
||||||
val newRoomId: UUID,
|
|
||||||
val movedAt: String
|
|
||||||
)
|
|
||||||
|
|
||||||
data class RoomStayVoidRequest(
|
data class RoomStayVoidRequest(
|
||||||
val reason: String? = null
|
val reason: String? = null
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
package com.android.trisolarisserver.controller.room
|
|
||||||
import com.android.trisolarisserver.controller.common.parseOffset
|
|
||||||
import com.android.trisolarisserver.controller.common.requireOpenRoomStayForProperty
|
|
||||||
import com.android.trisolarisserver.controller.common.requireRole
|
|
||||||
|
|
||||||
import com.android.trisolarisserver.component.auth.PropertyAccess
|
|
||||||
import com.android.trisolarisserver.component.room.RoomBoardEvents
|
|
||||||
import com.android.trisolarisserver.controller.dto.booking.RoomChangeRequest
|
|
||||||
import com.android.trisolarisserver.controller.dto.booking.RoomChangeResponse
|
|
||||||
import com.android.trisolarisserver.models.room.RoomStay
|
|
||||||
import com.android.trisolarisserver.models.room.RoomStayChange
|
|
||||||
import com.android.trisolarisserver.models.property.Role
|
|
||||||
import com.android.trisolarisserver.repo.property.AppUserRepo
|
|
||||||
import com.android.trisolarisserver.repo.room.RoomRepo
|
|
||||||
import com.android.trisolarisserver.repo.room.RoomStayChangeRepo
|
|
||||||
import com.android.trisolarisserver.repo.room.RoomStayRepo
|
|
||||||
import com.android.trisolarisserver.security.MyPrincipal
|
|
||||||
import org.springframework.http.HttpStatus
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
|
||||||
import org.springframework.transaction.annotation.Transactional
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus
|
|
||||||
import org.springframework.web.bind.annotation.RestController
|
|
||||||
import org.springframework.web.server.ResponseStatusException
|
|
||||||
import java.time.OffsetDateTime
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/properties/{propertyId}/room-stays")
|
|
||||||
class RoomStayFlow(
|
|
||||||
private val propertyAccess: PropertyAccess,
|
|
||||||
private val roomStayRepo: RoomStayRepo,
|
|
||||||
private val roomStayChangeRepo: RoomStayChangeRepo,
|
|
||||||
private val roomRepo: RoomRepo,
|
|
||||||
private val appUserRepo: AppUserRepo,
|
|
||||||
private val roomBoardEvents: RoomBoardEvents
|
|
||||||
) {
|
|
||||||
|
|
||||||
@PostMapping("/{roomStayId}/change-room")
|
|
||||||
@ResponseStatus(HttpStatus.CREATED)
|
|
||||||
@Transactional
|
|
||||||
fun changeRoom(
|
|
||||||
@PathVariable propertyId: UUID,
|
|
||||||
@PathVariable roomStayId: UUID,
|
|
||||||
@AuthenticationPrincipal principal: MyPrincipal?,
|
|
||||||
@RequestBody request: RoomChangeRequest
|
|
||||||
): RoomChangeResponse {
|
|
||||||
val actor = requireActor(propertyId, principal)
|
|
||||||
|
|
||||||
val stay = requireOpenRoomStayForProperty(
|
|
||||||
roomStayRepo,
|
|
||||||
propertyId,
|
|
||||||
roomStayId,
|
|
||||||
"Room stay already closed"
|
|
||||||
)
|
|
||||||
if (request.idempotencyKey.isBlank()) {
|
|
||||||
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "idempotencyKey required")
|
|
||||||
}
|
|
||||||
if (request.newRoomId == stay.room.id) {
|
|
||||||
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "New room is same as current")
|
|
||||||
}
|
|
||||||
|
|
||||||
val existing = roomStayChangeRepo.findByRoomStayIdAndIdempotencyKey(roomStayId, request.idempotencyKey)
|
|
||||||
if (existing != null) {
|
|
||||||
return toResponse(existing)
|
|
||||||
}
|
|
||||||
|
|
||||||
val newRoom = roomRepo.findByIdAndPropertyId(request.newRoomId, propertyId)
|
|
||||||
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Room not found")
|
|
||||||
if (!newRoom.active || newRoom.maintenance) {
|
|
||||||
throw ResponseStatusException(HttpStatus.CONFLICT, "Room not available")
|
|
||||||
}
|
|
||||||
val occupied = roomStayRepo.findActiveRoomIds(propertyId, listOf(request.newRoomId))
|
|
||||||
if (occupied.isNotEmpty()) {
|
|
||||||
throw ResponseStatusException(HttpStatus.CONFLICT, "Room already occupied")
|
|
||||||
}
|
|
||||||
|
|
||||||
val movedAt = parseOffset(request.movedAt) ?: OffsetDateTime.now()
|
|
||||||
|
|
||||||
stay.toAt = movedAt
|
|
||||||
roomStayRepo.save(stay)
|
|
||||||
|
|
||||||
val newStay = RoomStay(
|
|
||||||
property = stay.property,
|
|
||||||
booking = stay.booking,
|
|
||||||
room = newRoom,
|
|
||||||
fromAt = movedAt,
|
|
||||||
toAt = null,
|
|
||||||
rateSource = stay.rateSource,
|
|
||||||
nightlyRate = stay.nightlyRate,
|
|
||||||
ratePlanCode = stay.ratePlanCode,
|
|
||||||
currency = stay.currency,
|
|
||||||
createdBy = actor
|
|
||||||
)
|
|
||||||
val savedNewStay = roomStayRepo.save(newStay)
|
|
||||||
|
|
||||||
val change = RoomStayChange(
|
|
||||||
property = stay.property,
|
|
||||||
roomStay = stay,
|
|
||||||
newRoomStay = savedNewStay,
|
|
||||||
idempotencyKey = request.idempotencyKey
|
|
||||||
)
|
|
||||||
val savedChange = roomStayChangeRepo.save(change)
|
|
||||||
roomBoardEvents.emit(propertyId)
|
|
||||||
return toResponse(savedChange)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toResponse(change: RoomStayChange): RoomChangeResponse {
|
|
||||||
return RoomChangeResponse(
|
|
||||||
oldRoomStayId = change.roomStay.id!!,
|
|
||||||
newRoomStayId = change.newRoomStay.id!!,
|
|
||||||
oldRoomId = change.roomStay.room.id!!,
|
|
||||||
newRoomId = change.newRoomStay.room.id!!,
|
|
||||||
movedAt = change.newRoomStay.fromAt.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requireActor(propertyId: UUID, principal: MyPrincipal?): com.android.trisolarisserver.models.property.AppUser {
|
|
||||||
val resolved = requireRole(propertyAccess, propertyId, principal, Role.ADMIN, Role.MANAGER, Role.STAFF)
|
|
||||||
return appUserRepo.findById(resolved.userId).orElseThrow {
|
|
||||||
ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user