90 lines
3.7 KiB
Kotlin
90 lines
3.7 KiB
Kotlin
package com.android.trisolarisserver.controller
|
|
|
|
import com.android.trisolarisserver.controller.dto.BookingDetailResponse
|
|
import com.android.trisolarisserver.db.repo.BookingRepo
|
|
import com.android.trisolarisserver.repo.GuestVehicleRepo
|
|
import com.android.trisolarisserver.repo.PaymentRepo
|
|
import com.android.trisolarisserver.repo.RoomStayRepo
|
|
import org.springframework.http.HttpStatus
|
|
import org.springframework.stereotype.Component
|
|
import org.springframework.web.server.ResponseStatusException
|
|
import java.util.UUID
|
|
|
|
@Component
|
|
class BookingSnapshotBuilder(
|
|
private val bookingRepo: BookingRepo,
|
|
private val roomStayRepo: RoomStayRepo,
|
|
private val paymentRepo: PaymentRepo,
|
|
private val guestVehicleRepo: GuestVehicleRepo
|
|
) {
|
|
fun build(propertyId: UUID, bookingId: UUID): BookingDetailResponse {
|
|
val booking = bookingRepo.findById(bookingId).orElseThrow {
|
|
ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found")
|
|
}
|
|
if (booking.property.id != propertyId) {
|
|
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found for property")
|
|
}
|
|
|
|
val stays = roomStayRepo.findByBookingId(bookingId)
|
|
val activeRooms = stays.filter { it.toAt == null }
|
|
val roomsToShow = activeRooms.ifEmpty { stays }
|
|
val roomNumbers = roomsToShow.map { it.room.roomNumber }
|
|
.distinct()
|
|
.sorted()
|
|
|
|
val guest = booking.primaryGuest
|
|
val vehicleNumbers = if (guest?.id != null) {
|
|
guestVehicleRepo.findByGuestIdIn(listOf(guest.id!!))
|
|
.map { it.vehicleNumber }
|
|
.distinct()
|
|
.sorted()
|
|
} else {
|
|
emptyList()
|
|
}
|
|
val signatureUrl = guest?.signaturePath?.let {
|
|
"/properties/$propertyId/guests/${guest.id}/signature/file"
|
|
}
|
|
|
|
val totalNightlyRate = roomsToShow.sumOf { it.nightlyRate ?: 0L }
|
|
val expectedPay = computeExpectedPayTotal(stays, booking.expectedCheckoutAt, booking.property.timezone)
|
|
val accruedPay = computeExpectedPay(stays, booking.property.timezone)
|
|
val amountCollected = paymentRepo.sumAmountByBookingId(bookingId)
|
|
val pending = accruedPay - amountCollected
|
|
|
|
return BookingDetailResponse(
|
|
id = booking.id!!,
|
|
status = booking.status.name,
|
|
guestId = guest?.id,
|
|
guestName = guest?.name,
|
|
guestPhone = guest?.phoneE164,
|
|
guestNationality = guest?.nationality,
|
|
guestAddressText = guest?.addressText,
|
|
guestSignatureUrl = signatureUrl,
|
|
vehicleNumbers = vehicleNumbers,
|
|
roomNumbers = roomNumbers,
|
|
source = booking.source,
|
|
fromCity = booking.fromCity,
|
|
toCity = booking.toCity,
|
|
memberRelation = booking.memberRelation?.name,
|
|
transportMode = booking.transportMode?.name,
|
|
checkInAt = booking.checkinAt?.toString(),
|
|
checkOutAt = booking.checkoutAt?.toString(),
|
|
expectedCheckInAt = booking.expectedCheckinAt?.toString(),
|
|
expectedCheckOutAt = booking.expectedCheckoutAt?.toString(),
|
|
adultCount = booking.adultCount,
|
|
childCount = booking.childCount,
|
|
maleCount = booking.maleCount,
|
|
femaleCount = booking.femaleCount,
|
|
totalGuestCount = booking.totalGuestCount,
|
|
expectedGuestCount = booking.expectedGuestCount,
|
|
notes = booking.notes,
|
|
registeredByName = booking.createdBy?.name,
|
|
registeredByPhone = booking.createdBy?.phoneE164,
|
|
totalNightlyRate = totalNightlyRate,
|
|
expectedPay = expectedPay,
|
|
amountCollected = amountCollected,
|
|
pending = pending
|
|
)
|
|
}
|
|
}
|