From ec3c7891a4b0216aae1aa040b1f534a9ba96b766 Mon Sep 17 00:00:00 2001 From: androidlover5842 Date: Thu, 29 Jan 2026 03:42:30 +0530 Subject: [PATCH] Add booking create endpoint --- AGENTS.md | 1 + .../controller/BookingFlow.kt | 56 +++++++++++++++++++ .../controller/dto/BookingDtos.kt | 18 ++++++ 3 files changed, 75 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index b47a1f6..e73ff2b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -95,6 +95,7 @@ Properties - Property create/update accepts addressText, otaAliases, emailAddresses, allowedTransportModes. Booking flow +- POST /properties/{propertyId}/bookings (create booking) - /properties/{propertyId}/bookings/{bookingId}/check-in (creates RoomStay rows) - /properties/{propertyId}/bookings/{bookingId}/check-out (closes RoomStay) - /properties/{propertyId}/bookings/{bookingId}/cancel diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/BookingFlow.kt b/src/main/kotlin/com/android/trisolarisserver/controller/BookingFlow.kt index a841333..4b9e351 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/BookingFlow.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/BookingFlow.kt @@ -5,6 +5,8 @@ import com.android.trisolarisserver.component.RoomBoardEvents import com.android.trisolarisserver.controller.dto.BookingCancelRequest import com.android.trisolarisserver.controller.dto.BookingCheckInRequest import com.android.trisolarisserver.controller.dto.BookingCheckOutRequest +import com.android.trisolarisserver.controller.dto.BookingCreateRequest +import com.android.trisolarisserver.controller.dto.BookingCreateResponse import com.android.trisolarisserver.controller.dto.BookingNoShowRequest import com.android.trisolarisserver.controller.dto.RoomStayPreAssignRequest import com.android.trisolarisserver.db.repo.BookingRepo @@ -13,6 +15,7 @@ import com.android.trisolarisserver.models.booking.TransportMode import com.android.trisolarisserver.models.room.RoomStay import com.android.trisolarisserver.models.property.Role import com.android.trisolarisserver.repo.AppUserRepo +import com.android.trisolarisserver.repo.PropertyRepo import com.android.trisolarisserver.repo.RoomRepo import com.android.trisolarisserver.repo.RoomStayRepo import com.android.trisolarisserver.security.MyPrincipal @@ -37,9 +40,62 @@ class BookingFlow( private val roomRepo: RoomRepo, private val roomStayRepo: RoomStayRepo, private val appUserRepo: AppUserRepo, + private val propertyRepo: PropertyRepo, private val roomBoardEvents: RoomBoardEvents ) { + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + @Transactional + fun createBooking( + @PathVariable propertyId: UUID, + @AuthenticationPrincipal principal: MyPrincipal?, + @RequestBody request: BookingCreateRequest + ): BookingCreateResponse { + val actor = requireActor(propertyId, principal) + val property = propertyRepo.findById(propertyId).orElseThrow { + ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found") + } + + val expectedCheckInAt = parseOffset(request.expectedCheckInAt) + ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "expectedCheckInAt required") + val expectedCheckOutAt = parseOffset(request.expectedCheckOutAt) + ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "expectedCheckOutAt required") + if (!expectedCheckOutAt.isAfter(expectedCheckInAt)) { + throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid date range") + } + + val now = OffsetDateTime.now() + val booking = com.android.trisolarisserver.models.booking.Booking( + property = property, + status = BookingStatus.OPEN, + source = request.source?.trim().takeIf { !it.isNullOrBlank() } ?: "WALKIN", + expectedCheckinAt = expectedCheckInAt, + expectedCheckoutAt = expectedCheckOutAt, + transportMode = request.transportMode?.let { + val mode = parseTransportMode(it) + if (!isTransportModeAllowed(property, mode)) { + throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Transport mode disabled") + } + mode + }, + transportVehicleNumber = request.transportVehicleNumber, + adultCount = request.adultCount, + totalGuestCount = request.totalGuestCount, + notes = request.notes, + createdBy = actor, + updatedAt = now + ) + + val saved = bookingRepo.save(booking) + return BookingCreateResponse( + id = saved.id!!, + status = saved.status.name, + expectedCheckInAt = expectedCheckInAt.toString(), + expectedCheckOutAt = expectedCheckOutAt.toString() + ) + } + @PostMapping("/{bookingId}/check-in") @ResponseStatus(HttpStatus.CREATED) @Transactional diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/dto/BookingDtos.kt b/src/main/kotlin/com/android/trisolarisserver/controller/dto/BookingDtos.kt index 5c6d404..72b15e2 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/dto/BookingDtos.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/dto/BookingDtos.kt @@ -10,6 +10,24 @@ data class BookingCheckInRequest( val notes: String? = null ) +data class BookingCreateRequest( + val source: String? = null, + val expectedCheckInAt: String, + val expectedCheckOutAt: String, + val transportMode: String? = null, + val transportVehicleNumber: String? = null, + val adultCount: Int? = null, + val totalGuestCount: Int? = null, + val notes: String? = null +) + +data class BookingCreateResponse( + val id: UUID, + val status: String, + val expectedCheckInAt: String, + val expectedCheckOutAt: String +) + data class BookingCheckOutRequest( val checkOutAt: String? = null, val notes: String? = null