package com.android.trisolarisserver.controller.booking import com.android.trisolarisserver.controller.common.computeExpectedPay import com.android.trisolarisserver.controller.common.requireMember import com.android.trisolarisserver.component.auth.PropertyAccess import com.android.trisolarisserver.controller.dto.payment.BookingBalanceResponse import com.android.trisolarisserver.repo.booking.BookingRepo import com.android.trisolarisserver.repo.booking.ChargeRepo import com.android.trisolarisserver.repo.booking.PaymentRepo 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.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import org.springframework.web.server.ResponseStatusException import java.util.UUID @RestController @RequestMapping("/properties/{propertyId}/bookings/{bookingId}/balance") class BookingBalances( private val propertyAccess: PropertyAccess, private val bookingRepo: BookingRepo, private val roomStayRepo: RoomStayRepo, private val chargeRepo: ChargeRepo, private val paymentRepo: PaymentRepo ) { @GetMapping @Transactional(readOnly = true) fun getBalance( @PathVariable propertyId: UUID, @PathVariable bookingId: UUID, @AuthenticationPrincipal principal: MyPrincipal? ): BookingBalanceResponse { requireMember(propertyAccess, propertyId, principal) 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 expected = computeExpectedPay( roomStayRepo.findByBookingId(bookingId), booking.property.timezone, booking.billingMode, booking.billingCheckinTime, booking.billingCheckoutTime ) val charges = chargeRepo.sumAmountByBookingId(bookingId) val collected = paymentRepo.sumAmountByBookingId(bookingId) val pending = expected + charges - collected return BookingBalanceResponse( expectedPay = expected + charges, amountCollected = collected, pending = pending ) } }