diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingBalances.kt b/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingBalances.kt index 705290c..89b23c9 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingBalances.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingBalances.kt @@ -44,8 +44,9 @@ class BookingBalances( val expected = computeExpectedPay( roomStayRepo.findByBookingId(bookingId), booking.property.timezone, - booking.property.billingCheckinTime, - booking.property.billingCheckoutTime + booking.billingMode, + booking.billingCheckinTime, + booking.billingCheckoutTime ) val charges = chargeRepo.sumAmountByBookingId(bookingId) val collected = paymentRepo.sumAmountByBookingId(bookingId) diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt b/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt index e78ca4e..50e8f34 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingFlow.kt @@ -15,6 +15,7 @@ import com.android.trisolarisserver.controller.dto.booking.BookingCheckOutReques import com.android.trisolarisserver.controller.dto.booking.BookingCreateRequest import com.android.trisolarisserver.controller.dto.booking.BookingCreateResponse import com.android.trisolarisserver.controller.dto.booking.BookingDetailResponse +import com.android.trisolarisserver.controller.dto.booking.BookingBillingPolicyUpdateRequest import com.android.trisolarisserver.controller.dto.booking.BookingExpectedDatesUpdateRequest import com.android.trisolarisserver.controller.dto.booking.BookingLinkGuestRequest import com.android.trisolarisserver.controller.dto.booking.BookingNoShowRequest @@ -24,7 +25,9 @@ import com.android.trisolarisserver.repo.guest.GuestDocumentRepo import com.android.trisolarisserver.repo.guest.GuestRepo import com.android.trisolarisserver.repo.guest.GuestRatingRepo import com.android.trisolarisserver.models.booking.BookingStatus +import com.android.trisolarisserver.models.booking.BookingBillingMode import com.android.trisolarisserver.models.booking.BookingRoomRequestStatus +import com.android.trisolarisserver.models.booking.BookingBillingPolicyAuditLog import com.android.trisolarisserver.models.booking.Charge import com.android.trisolarisserver.models.booking.ChargeType import com.android.trisolarisserver.models.booking.MemberRelation @@ -38,6 +41,7 @@ import com.android.trisolarisserver.repo.property.AppUserRepo import com.android.trisolarisserver.repo.guest.GuestVehicleRepo import com.android.trisolarisserver.repo.booking.PaymentRepo import com.android.trisolarisserver.repo.booking.BookingRoomRequestRepo +import com.android.trisolarisserver.repo.booking.BookingBillingPolicyAuditLogRepo import com.android.trisolarisserver.repo.booking.ChargeRepo import com.android.trisolarisserver.repo.property.PropertyRepo import com.android.trisolarisserver.repo.property.PropertyCancellationPolicyRepo @@ -58,7 +62,10 @@ import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.ResponseStatus import org.springframework.web.bind.annotation.RestController import org.springframework.web.server.ResponseStatusException +import java.time.LocalTime import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeParseException import kotlin.math.abs import java.util.UUID @@ -82,6 +89,7 @@ class BookingFlow( private val bookingSnapshotBuilder: BookingSnapshotBuilder, private val roomStayAuditLogRepo: RoomStayAuditLogRepo, private val bookingRoomRequestRepo: BookingRoomRequestRepo, + private val bookingBillingPolicyAuditLogRepo: BookingBillingPolicyAuditLogRepo, private val propertyCancellationPolicyRepo: PropertyCancellationPolicyRepo ) { @@ -112,6 +120,12 @@ class BookingFlow( val fromCity = request.fromCity?.trim()?.ifBlank { null } val toCity = request.toCity?.trim()?.ifBlank { null } val memberRelation = parseMemberRelation(request.memberRelation) + val (billingMode, billingCheckinTime, billingCheckoutTime) = resolveBookingBillingPolicy( + property = property, + modeRaw = request.billingMode, + billingCheckinTimeRaw = request.billingCheckinTime, + billingCheckoutTimeRaw = request.billingCheckoutTime + ) val hasGuestCounts = request.maleCount != null || request.femaleCount != null || request.childCount != null val adultCount = if (hasGuestCounts) { (request.maleCount ?: 0) + (request.femaleCount ?: 0) @@ -131,6 +145,9 @@ class BookingFlow( checkinAt = null, expectedCheckinAt = expectedCheckInAt, expectedCheckoutAt = expectedCheckOutAt, + billingMode = billingMode, + billingCheckinTime = billingCheckinTime, + billingCheckoutTime = billingCheckoutTime, transportMode = request.transportMode?.let { val mode = parseTransportMode(it) if (!isTransportModeAllowed(property, mode)) { @@ -157,6 +174,9 @@ class BookingFlow( return BookingCreateResponse( id = saved.id!!, status = saved.status.name, + billingMode = saved.billingMode.name, + billingCheckinTime = saved.billingCheckinTime, + billingCheckoutTime = saved.billingCheckoutTime, guestId = guest.id, checkInAt = saved.checkinAt?.toString(), expectedCheckInAt = saved.expectedCheckinAt?.toString(), @@ -223,8 +243,9 @@ class BookingFlow( computeExpectedPay( stays, property.timezone, - property.billingCheckinTime, - property.billingCheckoutTime + booking.billingMode, + booking.billingCheckinTime, + booking.billingCheckoutTime ) } val collected = paymentsByBooking[booking.id] ?: 0L @@ -238,6 +259,9 @@ class BookingFlow( guestPhone = guest?.phoneE164, roomNumbers = roomNumbersByBooking[booking.id] ?: emptyList(), source = booking.source, + billingMode = booking.billingMode.name, + billingCheckinTime = booking.billingCheckinTime, + billingCheckoutTime = booking.billingCheckoutTime, expectedCheckInAt = booking.expectedCheckinAt?.toString(), expectedCheckOutAt = booking.expectedCheckoutAt?.toString(), checkInAt = booking.checkinAt?.toString(), @@ -447,6 +471,58 @@ class BookingFlow( bookingEvents.emit(propertyId, bookingId) } + @PostMapping("/{bookingId}/billing-policy") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Transactional + fun updateBillingPolicy( + @PathVariable propertyId: UUID, + @PathVariable bookingId: UUID, + @AuthenticationPrincipal principal: MyPrincipal?, + @RequestBody request: BookingBillingPolicyUpdateRequest + ) { + val actor = requireActor(propertyId, principal) + val booking = requireBooking(propertyId, bookingId) + when (booking.status) { + BookingStatus.CHECKED_OUT, + BookingStatus.CANCELLED, + BookingStatus.NO_SHOW -> throw ResponseStatusException(HttpStatus.CONFLICT, "Booking closed") + else -> {} + } + + val oldMode = booking.billingMode + val oldCheckin = booking.billingCheckinTime + val oldCheckout = booking.billingCheckoutTime + val (newMode, newCheckin, newCheckout) = resolveBookingBillingPolicy( + property = booking.property, + modeRaw = request.billingMode, + billingCheckinTimeRaw = request.billingCheckinTime, + billingCheckoutTimeRaw = request.billingCheckoutTime + ) + booking.billingMode = newMode + booking.billingCheckinTime = newCheckin + booking.billingCheckoutTime = newCheckout + booking.updatedAt = OffsetDateTime.now() + bookingRepo.save(booking) + + if (oldMode != newMode || oldCheckin != newCheckin || oldCheckout != newCheckout) { + bookingBillingPolicyAuditLogRepo.save( + BookingBillingPolicyAuditLog( + property = booking.property, + booking = booking, + actor = actor, + oldBillingMode = oldMode, + newBillingMode = newMode, + oldBillingCheckinTime = oldCheckin, + newBillingCheckinTime = newCheckin, + oldBillingCheckoutTime = oldCheckout, + newBillingCheckoutTime = newCheckout + ) + ) + } + + bookingEvents.emit(propertyId, bookingId) + } + @PostMapping("/{bookingId}/check-out") @ResponseStatus(HttpStatus.NO_CONTENT) @Transactional @@ -471,8 +547,9 @@ class BookingFlow( ensureLedgerToleranceForCheckout( bookingId = bookingId, timezone = booking.property.timezone, - billingCheckinTime = booking.property.billingCheckinTime, - billingCheckoutTime = booking.property.billingCheckoutTime, + billingMode = booking.billingMode, + billingCheckinTime = booking.billingCheckinTime, + billingCheckoutTime = booking.billingCheckoutTime, stays = stays, checkOutOverrides = stays.associate { it.id!! to checkOutAt }, restrictToClosedStaysOnly = false @@ -543,8 +620,9 @@ class BookingFlow( ensureLedgerToleranceForCheckout( bookingId = bookingId, timezone = booking.property.timezone, - billingCheckinTime = booking.property.billingCheckinTime, - billingCheckoutTime = booking.property.billingCheckoutTime, + billingMode = booking.billingMode, + billingCheckinTime = booking.billingCheckinTime, + billingCheckoutTime = booking.billingCheckoutTime, stays = staysForBooking, checkOutOverrides = mapOf(stay.id!! to checkOutAt), restrictToClosedStaysOnly = true @@ -798,6 +876,7 @@ class BookingFlow( private fun ensureLedgerToleranceForCheckout( bookingId: UUID, timezone: String?, + billingMode: BookingBillingMode, billingCheckinTime: String?, billingCheckoutTime: String?, stays: List, @@ -822,6 +901,7 @@ class BookingFlow( stay.fromAt, endAt, timezone, + billingMode, billingCheckinTime, billingCheckoutTime ) @@ -899,4 +979,53 @@ class BookingFlow( response.setHeader("X-Accel-Buffering", "no") } + private fun resolveBookingBillingPolicy( + property: com.android.trisolarisserver.models.property.Property, + modeRaw: String?, + billingCheckinTimeRaw: String?, + billingCheckoutTimeRaw: String? + ): Triple { + val mode = parseBillingMode(modeRaw) + return when (mode) { + BookingBillingMode.PROPERTY_POLICY -> Triple( + BookingBillingMode.PROPERTY_POLICY, + property.billingCheckinTime, + property.billingCheckoutTime + ) + BookingBillingMode.CUSTOM_WINDOW -> Triple( + BookingBillingMode.CUSTOM_WINDOW, + normalizeBillingTime(billingCheckinTimeRaw, "billingCheckinTime"), + normalizeBillingTime(billingCheckoutTimeRaw, "billingCheckoutTime") + ) + BookingBillingMode.FULL_24H -> Triple( + BookingBillingMode.FULL_24H, + "00:00", + "23:59" + ) + } + } + + private fun parseBillingMode(raw: String?): BookingBillingMode { + if (raw.isNullOrBlank()) return BookingBillingMode.PROPERTY_POLICY + return try { + BookingBillingMode.valueOf(raw.trim().uppercase()) + } catch (_: IllegalArgumentException) { + throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown billing mode") + } + } + + private fun normalizeBillingTime(raw: String?, fieldName: String): String { + val value = raw?.trim()?.takeIf { it.isNotEmpty() } + ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "$fieldName required") + return try { + LocalTime.parse(value, BILLING_TIME_FORMATTER).format(BILLING_TIME_FORMATTER) + } catch (_: DateTimeParseException) { + throw ResponseStatusException(HttpStatus.BAD_REQUEST, "$fieldName must be HH:mm") + } + } + + companion object { + private val BILLING_TIME_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm") + } + } diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingSnapshotBuilder.kt b/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingSnapshotBuilder.kt index f5c6645..314c0bd 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingSnapshotBuilder.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/booking/BookingSnapshotBuilder.kt @@ -54,14 +54,16 @@ class BookingSnapshotBuilder( stays, booking.expectedCheckoutAt, booking.property.timezone, - booking.property.billingCheckinTime, - booking.property.billingCheckoutTime + booking.billingMode, + booking.billingCheckinTime, + booking.billingCheckoutTime ) val accruedPay = computeExpectedPay( stays, booking.property.timezone, - booking.property.billingCheckinTime, - booking.property.billingCheckoutTime + booking.billingMode, + booking.billingCheckinTime, + booking.billingCheckoutTime ) val extraCharges = chargeRepo.sumAmountByBookingId(bookingId) val amountCollected = paymentRepo.sumAmountByBookingId(bookingId) @@ -80,6 +82,9 @@ class BookingSnapshotBuilder( vehicleNumbers = vehicleNumbers, roomNumbers = roomNumbers, source = booking.source, + billingMode = booking.billingMode.name, + billingCheckinTime = booking.billingCheckinTime, + billingCheckoutTime = booking.billingCheckoutTime, fromCity = booking.fromCity, toCity = booking.toCity, memberRelation = booking.memberRelation?.name, diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/common/ControllerLookups.kt b/src/main/kotlin/com/android/trisolarisserver/controller/common/ControllerLookups.kt index 53c6d7f..5a69409 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/common/ControllerLookups.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/common/ControllerLookups.kt @@ -12,6 +12,7 @@ import com.android.trisolarisserver.controller.common.requireRoomStayForProperty import com.android.trisolarisserver.repo.guest.GuestRepo import com.android.trisolarisserver.models.booking.Guest +import com.android.trisolarisserver.models.booking.BookingBillingMode import com.android.trisolarisserver.models.property.Property import com.android.trisolarisserver.models.room.RoomStay import com.android.trisolarisserver.repo.property.PropertyRepo @@ -107,6 +108,7 @@ internal fun nowForProperty(timezone: String?): OffsetDateTime { internal fun computeExpectedPay( stays: List, timezone: String?, + billingMode: BookingBillingMode, billingCheckinTime: String?, billingCheckoutTime: String? ): Long { @@ -122,6 +124,7 @@ internal fun computeExpectedPay( stay.fromAt, endAt, timezone, + billingMode, billingCheckinTime, billingCheckoutTime ) @@ -134,6 +137,7 @@ internal fun computeExpectedPayTotal( stays: List, expectedCheckoutAt: OffsetDateTime?, timezone: String?, + billingMode: BookingBillingMode, billingCheckinTime: String?, billingCheckoutTime: String? ): Long { @@ -149,6 +153,7 @@ internal fun computeExpectedPayTotal( stay.fromAt, endAt, timezone, + billingMode, billingCheckinTime, billingCheckoutTime ) @@ -164,10 +169,19 @@ internal fun billableNights( startAt: OffsetDateTime, endAt: OffsetDateTime, timezone: String?, + billingMode: BookingBillingMode, billingCheckinTime: String?, billingCheckoutTime: String? ): Long { if (!endAt.isAfter(startAt)) return 1L + if (billingMode == BookingBillingMode.FULL_24H) { + val minutes = java.time.Duration.between(startAt, endAt).toMinutes().coerceAtLeast(0L) + if (minutes == 0L) return 1L + val fullDays = minutes / (24L * 60L) + val remainder = minutes % (24L * 60L) + val extraNight = if (remainder > 120L) 1L else 0L + return (fullDays + extraNight).coerceAtLeast(1L) + } val zone = try { if (timezone.isNullOrBlank()) ZoneId.of("Asia/Kolkata") else ZoneId.of(timezone) } catch (_: Exception) { diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/dto/booking/BookingDtos.kt b/src/main/kotlin/com/android/trisolarisserver/controller/dto/booking/BookingDtos.kt index deebc09..dbf922f 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/dto/booking/BookingDtos.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/dto/booking/BookingDtos.kt @@ -24,6 +24,9 @@ data class BookingCreateRequest( val source: String? = null, val expectedCheckInAt: String, val expectedCheckOutAt: String, + val billingMode: String? = null, + val billingCheckinTime: String? = null, + val billingCheckoutTime: String? = null, val guestPhoneE164: String? = null, val fromCity: String? = null, val toCity: String? = null, @@ -39,6 +42,9 @@ data class BookingCreateRequest( data class BookingCreateResponse( val id: UUID, val status: String, + val billingMode: String, + val billingCheckinTime: String, + val billingCheckoutTime: String, val guestId: UUID?, val checkInAt: String?, val expectedCheckInAt: String?, @@ -53,6 +59,9 @@ data class BookingListItem( val guestPhone: String?, val roomNumbers: List, val source: String?, + val billingMode: String, + val billingCheckinTime: String, + val billingCheckoutTime: String, val expectedCheckInAt: String?, val expectedCheckOutAt: String?, val checkInAt: String?, @@ -80,6 +89,9 @@ data class BookingDetailResponse( val vehicleNumbers: List, val roomNumbers: List, val source: String?, + val billingMode: String, + val billingCheckinTime: String, + val billingCheckoutTime: String, val fromCity: String?, val toCity: String?, val memberRelation: String?, @@ -112,6 +124,12 @@ data class BookingExpectedDatesUpdateRequest( val expectedCheckOutAt: String? = null ) +data class BookingBillingPolicyUpdateRequest( + val billingMode: String, + val billingCheckinTime: String? = null, + val billingCheckoutTime: String? = null +) + data class BookingCheckOutRequest( val checkOutAt: String? = null, val notes: String? = null diff --git a/src/main/kotlin/com/android/trisolarisserver/models/booking/Booking.kt b/src/main/kotlin/com/android/trisolarisserver/models/booking/Booking.kt index bd7584a..4823e11 100644 --- a/src/main/kotlin/com/android/trisolarisserver/models/booking/Booking.kt +++ b/src/main/kotlin/com/android/trisolarisserver/models/booking/Booking.kt @@ -49,6 +49,16 @@ class Booking( @Column(name = "expected_checkout_at", columnDefinition = "timestamptz") var expectedCheckoutAt: OffsetDateTime? = null, + @Enumerated(EnumType.STRING) + @Column(name = "billing_mode", nullable = false) + var billingMode: BookingBillingMode = BookingBillingMode.PROPERTY_POLICY, + + @Column(name = "billing_checkin_time", nullable = false) + var billingCheckinTime: String = "12:00", + + @Column(name = "billing_checkout_time", nullable = false) + var billingCheckoutTime: String = "11:00", + @Column(name = "email_audit_pdf_url") var emailAuditPdfUrl: String? = null, diff --git a/src/main/kotlin/com/android/trisolarisserver/models/booking/BookingBillingMode.kt b/src/main/kotlin/com/android/trisolarisserver/models/booking/BookingBillingMode.kt new file mode 100644 index 0000000..a9e9210 --- /dev/null +++ b/src/main/kotlin/com/android/trisolarisserver/models/booking/BookingBillingMode.kt @@ -0,0 +1,7 @@ +package com.android.trisolarisserver.models.booking + +enum class BookingBillingMode { + PROPERTY_POLICY, + CUSTOM_WINDOW, + FULL_24H +} diff --git a/src/main/kotlin/com/android/trisolarisserver/models/booking/BookingBillingPolicyAuditLog.kt b/src/main/kotlin/com/android/trisolarisserver/models/booking/BookingBillingPolicyAuditLog.kt new file mode 100644 index 0000000..f72bb65 --- /dev/null +++ b/src/main/kotlin/com/android/trisolarisserver/models/booking/BookingBillingPolicyAuditLog.kt @@ -0,0 +1,63 @@ +package com.android.trisolarisserver.models.booking + +import com.android.trisolarisserver.models.property.AppUser +import com.android.trisolarisserver.models.property.Property +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.EnumType +import jakarta.persistence.Enumerated +import jakarta.persistence.FetchType +import jakarta.persistence.GeneratedValue +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import java.time.OffsetDateTime +import java.util.UUID + +@Entity +@Table(name = "booking_billing_policy_audit_log") +class BookingBillingPolicyAuditLog( + @Id + @GeneratedValue + @Column(columnDefinition = "uuid") + val id: UUID? = null, + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "property_id", nullable = false) + var property: Property, + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "booking_id", nullable = false) + var booking: Booking, + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "actor_user_id") + var actor: AppUser? = null, + + @Enumerated(EnumType.STRING) + @Column(name = "old_billing_mode", nullable = false) + var oldBillingMode: BookingBillingMode, + + @Enumerated(EnumType.STRING) + @Column(name = "new_billing_mode", nullable = false) + var newBillingMode: BookingBillingMode, + + @Column(name = "old_billing_checkin_time", nullable = false) + var oldBillingCheckinTime: String, + + @Column(name = "new_billing_checkin_time", nullable = false) + var newBillingCheckinTime: String, + + @Column(name = "old_billing_checkout_time", nullable = false) + var oldBillingCheckoutTime: String, + + @Column(name = "new_billing_checkout_time", nullable = false) + var newBillingCheckoutTime: String, + + @Column(name = "event", nullable = false) + var event: String = "POLICY_MODIFIED", + + @Column(name = "created_at", nullable = false, columnDefinition = "timestamptz") + val createdAt: OffsetDateTime = OffsetDateTime.now() +) diff --git a/src/main/kotlin/com/android/trisolarisserver/repo/booking/BookingBillingPolicyAuditLogRepo.kt b/src/main/kotlin/com/android/trisolarisserver/repo/booking/BookingBillingPolicyAuditLogRepo.kt new file mode 100644 index 0000000..112bb9d --- /dev/null +++ b/src/main/kotlin/com/android/trisolarisserver/repo/booking/BookingBillingPolicyAuditLogRepo.kt @@ -0,0 +1,7 @@ +package com.android.trisolarisserver.repo.booking + +import com.android.trisolarisserver.models.booking.BookingBillingPolicyAuditLog +import org.springframework.data.jpa.repository.JpaRepository +import java.util.UUID + +interface BookingBillingPolicyAuditLogRepo : JpaRepository diff --git a/src/main/kotlin/com/android/trisolarisserver/service/email/EmailIngestionService.kt b/src/main/kotlin/com/android/trisolarisserver/service/email/EmailIngestionService.kt index a55f8e2..065c820 100644 --- a/src/main/kotlin/com/android/trisolarisserver/service/email/EmailIngestionService.kt +++ b/src/main/kotlin/com/android/trisolarisserver/service/email/EmailIngestionService.kt @@ -6,6 +6,7 @@ import com.android.trisolarisserver.repo.booking.BookingRepo import com.android.trisolarisserver.repo.guest.GuestRepo import com.android.trisolarisserver.repo.email.InboundEmailRepo import com.android.trisolarisserver.models.booking.Booking +import com.android.trisolarisserver.models.booking.BookingBillingMode import com.android.trisolarisserver.models.booking.BookingStatus import com.android.trisolarisserver.models.booking.Guest import com.android.trisolarisserver.models.booking.InboundEmail @@ -186,6 +187,9 @@ class EmailIngestionService( sourceBookingId = sourceBookingId, expectedCheckinAt = checkin, expectedCheckoutAt = checkout, + billingMode = BookingBillingMode.PROPERTY_POLICY, + billingCheckinTime = property.billingCheckinTime, + billingCheckoutTime = property.billingCheckoutTime, emailAuditPdfUrl = emailAuditPdfUrl ) return bookingRepo.save(booking)