Expose active temp card state on room responses
All checks were successful
build-and-deploy / build-deploy (push) Successful in 33s

This commit is contained in:
androidlover5842
2026-01-28 17:56:59 +05:30
parent 2591768efb
commit b52cb1a88d
3 changed files with 44 additions and 10 deletions

View File

@@ -10,6 +10,7 @@ import com.android.trisolarisserver.controller.dto.RoomResponse
import com.android.trisolarisserver.controller.dto.RoomUpsertRequest
import com.android.trisolarisserver.repo.PropertyRepo
import com.android.trisolarisserver.repo.PropertyUserRepo
import com.android.trisolarisserver.repo.IssuedCardRepo
import com.android.trisolarisserver.repo.RoomImageRepo
import com.android.trisolarisserver.repo.RoomRepo
import com.android.trisolarisserver.repo.RoomStayRepo
@@ -31,6 +32,7 @@ import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ResponseStatusException
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter
import java.time.LocalDate
import java.time.OffsetDateTime
import java.time.ZoneId
import java.nio.file.Files
import java.nio.file.Paths
@@ -45,6 +47,7 @@ class Rooms(
private val roomStayRepo: RoomStayRepo,
private val propertyRepo: PropertyRepo,
private val roomTypeRepo: RoomTypeRepo,
private val issuedCardRepo: IssuedCardRepo,
private val propertyUserRepo: PropertyUserRepo,
private val roomBoardEvents: RoomBoardEvents
) {
@@ -58,14 +61,15 @@ class Rooms(
propertyAccess.requireMember(propertyId, principal!!.userId)
val roles = propertyUserRepo.findRolesByPropertyAndUser(propertyId, principal.userId)
val rooms = roomRepo.findByPropertyIdOrderByRoomNumber(propertyId)
val tempCardsByRoom = loadActiveTempCardsByRoom(propertyId)
if (isAgentOnly(roles)) {
val occupiedRoomIds = roomStayRepo.findOccupiedRoomIds(propertyId).toHashSet()
return rooms
.filter { it.active && !it.maintenance && !occupiedRoomIds.contains(it.id) }
.map { it.toRoomResponse() }
.map { it.toRoomResponse(tempCardsByRoom[it.id]) }
}
return rooms
.map { it.toRoomResponse() }
.map { it.toRoomResponse(tempCardsByRoom[it.id]) }
}
@GetMapping("/board")
@@ -134,9 +138,10 @@ class Rooms(
): List<RoomResponse> {
val rooms = roomRepo.findByPropertyIdOrderByRoomNumber(propertyId)
val occupiedRoomIds = roomStayRepo.findOccupiedRoomIds(propertyId).toHashSet()
val tempCardsByRoom = loadActiveTempCardsByRoom(propertyId)
return rooms
.filter { it.active && !it.maintenance && !occupiedRoomIds.contains(it.id) }
.map { it.toRoomResponse() }
.map { it.toRoomResponse(tempCardsByRoom[it.id]) }
}
@GetMapping("/by-type/{roomTypeCode}")
@@ -152,14 +157,15 @@ class Rooms(
val rooms = roomRepo.findByPropertyIdOrderByRoomNumber(propertyId)
.filter { it.roomType.id == roomType.id }
val tempCardsByRoom = loadActiveTempCardsByRoom(propertyId)
if (availableOnly || (principal != null && isAgentOnly(propertyUserRepo.findRolesByPropertyAndUser(propertyId, principal.userId)))) {
val occupiedRoomIds = roomStayRepo.findOccupiedRoomIds(propertyId).toHashSet()
return rooms
.filter { it.active && !it.maintenance && !occupiedRoomIds.contains(it.id) }
.map { it.toRoomResponse() }
.map { it.toRoomResponse(tempCardsByRoom[it.id]) }
}
return rooms.map { it.toRoomResponse() }
return rooms.map { it.toRoomResponse(tempCardsByRoom[it.id]) }
}
@GetMapping("/availability-range")
@@ -238,7 +244,9 @@ class Rooms(
hasNfc = saved.hasNfc,
active = saved.active,
maintenance = saved.maintenance,
notes = saved.notes
notes = saved.notes,
tempCardActive = false,
tempCardExpiresAt = null
)
roomBoardEvents.emit(propertyId)
return response
@@ -280,7 +288,9 @@ class Rooms(
hasNfc = saved.hasNfc,
active = saved.active,
maintenance = saved.maintenance,
notes = saved.notes
notes = saved.notes,
tempCardActive = false,
tempCardExpiresAt = null
)
roomBoardEvents.emit(propertyId)
return response
@@ -348,9 +358,16 @@ class Rooms(
return roomTypeRepo.findByPropertyIdAndCodeIgnoreCase(propertyId, code)
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Room type not found")
}
private fun loadActiveTempCardsByRoom(propertyId: UUID): Map<UUID, OffsetDateTime> {
val now = OffsetDateTime.now()
return issuedCardRepo.findActiveTempCardsForProperty(propertyId, now)
.groupBy { it.room.id ?: throw IllegalStateException("Room id is null") }
.mapValues { (_, cards) -> cards.maxBy { it.expiresAt }.expiresAt }
}
}
private fun Room.toRoomResponse(): RoomResponse {
private fun Room.toRoomResponse(tempCardExpiresAt: OffsetDateTime? = null): RoomResponse {
val roomId = id ?: throw IllegalStateException("Room id is null")
return RoomResponse(
id = roomId,
@@ -360,6 +377,8 @@ private fun Room.toRoomResponse(): RoomResponse {
hasNfc = hasNfc,
active = active,
maintenance = maintenance,
notes = notes
notes = notes,
tempCardActive = tempCardExpiresAt != null,
tempCardExpiresAt = tempCardExpiresAt?.toString()
)
}

View File

@@ -10,7 +10,9 @@ data class RoomResponse(
val hasNfc: Boolean,
val active: Boolean,
val maintenance: Boolean,
val notes: String?
val notes: String?,
val tempCardActive: Boolean = false,
val tempCardExpiresAt: String? = null
)
data class RoomBoardResponse(

View File

@@ -33,4 +33,17 @@ interface IssuedCardRepo : JpaRepository<IssuedCard, UUID> {
@org.springframework.data.repository.query.Param("roomStayId") roomStayId: UUID,
@org.springframework.data.repository.query.Param("now") now: java.time.OffsetDateTime
): Boolean
@org.springframework.data.jpa.repository.Query("""
select c
from IssuedCard c
where c.property.id = :propertyId
and c.roomStay is null
and c.revokedAt is null
and c.expiresAt > :now
""")
fun findActiveTempCardsForProperty(
@org.springframework.data.repository.query.Param("propertyId") propertyId: UUID,
@org.springframework.data.repository.query.Param("now") now: java.time.OffsetDateTime
): List<IssuedCard>
}