package com.android.trisolarisserver.repo.room import com.android.trisolarisserver.models.room.RoomStay import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.query.Param import java.util.UUID interface RoomStayRepo : JpaRepository { @Query(""" select rs.room.id from RoomStay rs where rs.property.id = :propertyId and rs.toAt is null and rs.isVoided = false """) fun findOccupiedRoomIds(@Param("propertyId") propertyId: UUID): List @Query(""" select distinct rs.room.id from RoomStay rs where rs.property.id = :propertyId and rs.isVoided = false and rs.fromAt < :toAt and (rs.toAt is null or rs.toAt > :fromAt) """) fun findOccupiedRoomIdsBetween( @Param("propertyId") propertyId: UUID, @Param("fromAt") fromAt: java.time.OffsetDateTime, @Param("toAt") toAt: java.time.OffsetDateTime ): List @Query(""" select distinct rs.room.id from RoomStay rs where rs.property.id = :propertyId and rs.isVoided = false and rs.toAt is not null and rs.fromAt < :toAt and rs.toAt > :fromAt """) fun findOccupiedRoomIdsBetweenClosed( @Param("propertyId") propertyId: UUID, @Param("fromAt") fromAt: java.time.OffsetDateTime, @Param("toAt") toAt: java.time.OffsetDateTime ): List @Query(""" select rs.room.id as roomId, rs.fromAt as fromAt, b.expectedCheckoutAt as expectedCheckoutAt from RoomStay rs join rs.booking b where rs.property.id = :propertyId and rs.isVoided = false and rs.toAt is null and rs.fromAt < :toAt """) fun findActiveForecastRows( @Param("propertyId") propertyId: UUID, @Param("toAt") toAt: java.time.OffsetDateTime ): List @Query(""" select rs from RoomStay rs where rs.booking.id = :bookingId and rs.toAt is null and rs.isVoided = false """) fun findActiveByBookingId(@Param("bookingId") bookingId: UUID): List @Query(""" select rs from RoomStay rs where rs.booking.id = :bookingId and rs.isVoided = false """) fun findByBookingId(@Param("bookingId") bookingId: UUID): List @Query(""" select rs from RoomStay rs join fetch rs.room r where rs.booking.id = :bookingId and rs.isVoided = false """) fun findByBookingIdWithRoom(@Param("bookingId") bookingId: UUID): List @Query(""" select rs from RoomStay rs where rs.booking.id in :bookingIds and rs.isVoided = false """) fun findByBookingIdIn(@Param("bookingIds") bookingIds: List): List @Query(""" select rs.room.id from RoomStay rs where rs.property.id = :propertyId and rs.room.id in :roomIds and rs.toAt is null and rs.isVoided = false """) fun findActiveRoomIds( @Param("propertyId") propertyId: UUID, @Param("roomIds") roomIds: List ): List @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.isVoided = false 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 @Query(""" select rs from RoomStay rs join fetch rs.room r join fetch r.roomType rt join fetch rs.booking b left join fetch b.primaryGuest g where rs.property.id = :propertyId and rs.toAt is null and rs.isVoided = false order by r.roomNumber """) fun findActiveByPropertyIdWithDetails(@Param("propertyId") propertyId: UUID): List @Query(""" select case when count(rs) > 0 then true else false end from RoomStay rs where rs.room.id = :roomId """) fun existsByRoomId(@Param("roomId") roomId: UUID): Boolean @Query(""" select rs.booking.id as bookingId, r.roomNumber as roomNumber from RoomStay rs join rs.room r where rs.booking.id in :bookingIds and rs.toAt is null and rs.isVoided = false """) fun findActiveRoomNumbersByBookingIds( @Param("bookingIds") bookingIds: List ): List @Query( """ select rs from RoomStay rs where rs.id = :roomStayId and rs.booking.id = :bookingId and rs.isVoided = false """ ) fun findByIdAndBookingId( @Param("roomStayId") roomStayId: UUID, @Param("bookingId") bookingId: UUID ): RoomStay? @Query( """ select count(distinct rs.room.id) from RoomStay rs where rs.property.id = :propertyId and rs.room.roomType.id = :roomTypeId and rs.isVoided = false and rs.fromAt < :toAt and (rs.toAt is null or rs.toAt > :fromAt) """ ) fun countOccupiedByTypeInRange( @Param("propertyId") propertyId: UUID, @Param("roomTypeId") roomTypeId: UUID, @Param("fromAt") fromAt: java.time.OffsetDateTime, @Param("toAt") toAt: java.time.OffsetDateTime ): Long } interface BookingRoomNumberRow { val bookingId: UUID val roomNumber: Int } interface ActiveRoomStayForecastRow { val roomId: UUID val fromAt: java.time.OffsetDateTime val expectedCheckoutAt: java.time.OffsetDateTime? }