Replace placeholder guest with existing phone guest
All checks were successful
build-and-deploy / build-deploy (push) Successful in 35s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 35s
This commit is contained in:
@@ -8,6 +8,7 @@ import com.android.trisolarisserver.controller.dto.GuestVehicleRequest
|
|||||||
import com.android.trisolarisserver.models.booking.Guest
|
import com.android.trisolarisserver.models.booking.Guest
|
||||||
import com.android.trisolarisserver.models.booking.GuestVehicle
|
import com.android.trisolarisserver.models.booking.GuestVehicle
|
||||||
import com.android.trisolarisserver.db.repo.BookingRepo
|
import com.android.trisolarisserver.db.repo.BookingRepo
|
||||||
|
import com.android.trisolarisserver.db.repo.GuestDocumentRepo
|
||||||
import com.android.trisolarisserver.db.repo.GuestRepo
|
import com.android.trisolarisserver.db.repo.GuestRepo
|
||||||
import com.android.trisolarisserver.db.repo.GuestRatingRepo
|
import com.android.trisolarisserver.db.repo.GuestRatingRepo
|
||||||
import com.android.trisolarisserver.repo.AppUserRepo
|
import com.android.trisolarisserver.repo.AppUserRepo
|
||||||
@@ -19,6 +20,7 @@ import org.springframework.http.HttpStatus
|
|||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
import org.springframework.web.bind.annotation.*
|
import org.springframework.web.bind.annotation.*
|
||||||
import org.springframework.web.multipart.MultipartFile
|
import org.springframework.web.multipart.MultipartFile
|
||||||
import org.springframework.web.server.ResponseStatusException
|
import org.springframework.web.server.ResponseStatusException
|
||||||
@@ -34,12 +36,14 @@ class Guests(
|
|||||||
private val bookingRepo: BookingRepo,
|
private val bookingRepo: BookingRepo,
|
||||||
private val guestVehicleRepo: GuestVehicleRepo,
|
private val guestVehicleRepo: GuestVehicleRepo,
|
||||||
private val guestRatingRepo: GuestRatingRepo,
|
private val guestRatingRepo: GuestRatingRepo,
|
||||||
|
private val guestDocumentRepo: GuestDocumentRepo,
|
||||||
private val signatureStorage: GuestSignatureStorage,
|
private val signatureStorage: GuestSignatureStorage,
|
||||||
private val appUserRepo: AppUserRepo
|
private val appUserRepo: AppUserRepo
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
@ResponseStatus(HttpStatus.CREATED)
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
@Transactional
|
||||||
fun createGuest(
|
fun createGuest(
|
||||||
@PathVariable propertyId: UUID,
|
@PathVariable propertyId: UUID,
|
||||||
@AuthenticationPrincipal principal: MyPrincipal?,
|
@AuthenticationPrincipal principal: MyPrincipal?,
|
||||||
@@ -55,15 +59,26 @@ class Guests(
|
|||||||
if (booking.property.id != property.id) {
|
if (booking.property.id != property.id) {
|
||||||
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Booking not in property")
|
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Booking not in property")
|
||||||
}
|
}
|
||||||
if (booking.primaryGuest != null) {
|
val currentGuest = booking.primaryGuest
|
||||||
throw ResponseStatusException(HttpStatus.CONFLICT, "Booking already linked to guest")
|
if (currentGuest != null && phone == null) {
|
||||||
|
if (!isPlaceholderGuest(currentGuest)) {
|
||||||
|
throw ResponseStatusException(HttpStatus.CONFLICT, "Booking already linked to guest")
|
||||||
|
}
|
||||||
|
val updated = applyGuestDetails(currentGuest, request)
|
||||||
|
booking.updatedAt = OffsetDateTime.now()
|
||||||
|
bookingRepo.save(booking)
|
||||||
|
return setOf(updated).toResponse(propertyId, guestVehicleRepo, guestRatingRepo).first()
|
||||||
}
|
}
|
||||||
if (phone != null) {
|
if (phone != null) {
|
||||||
val existing = guestRepo.findByPropertyIdAndPhoneE164(propertyId, phone)
|
val existing = guestRepo.findByPropertyIdAndPhoneE164(propertyId, phone)
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
|
val previous = booking.primaryGuest
|
||||||
booking.primaryGuest = existing
|
booking.primaryGuest = existing
|
||||||
booking.updatedAt = OffsetDateTime.now()
|
booking.updatedAt = OffsetDateTime.now()
|
||||||
bookingRepo.save(booking)
|
bookingRepo.save(booking)
|
||||||
|
if (previous != null && previous.id != existing.id && isPlaceholderGuest(previous) && isSafeToDelete(previous)) {
|
||||||
|
guestRepo.delete(previous)
|
||||||
|
}
|
||||||
return setOf(existing).toResponse(propertyId, guestVehicleRepo, guestRatingRepo).first()
|
return setOf(existing).toResponse(propertyId, guestVehicleRepo, guestRatingRepo).first()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,6 +211,33 @@ class Guests(
|
|||||||
.body(resource)
|
.body(resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun applyGuestDetails(guest: Guest, request: GuestCreateRequest): Guest {
|
||||||
|
val name = request.name?.trim()?.ifBlank { null }
|
||||||
|
val nationality = request.nationality?.trim()?.ifBlank { null }
|
||||||
|
val address = request.addressText?.trim()?.ifBlank { null }
|
||||||
|
if (name != null) guest.name = name
|
||||||
|
if (nationality != null) guest.nationality = nationality
|
||||||
|
if (address != null) guest.addressText = address
|
||||||
|
guest.updatedAt = OffsetDateTime.now()
|
||||||
|
return guestRepo.save(guest)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isPlaceholderGuest(guest: Guest): Boolean {
|
||||||
|
return guest.phoneE164.isNullOrBlank() &&
|
||||||
|
guest.name.isNullOrBlank() &&
|
||||||
|
guest.nationality.isNullOrBlank() &&
|
||||||
|
guest.addressText.isNullOrBlank() &&
|
||||||
|
guest.signaturePath.isNullOrBlank()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isSafeToDelete(guest: Guest): Boolean {
|
||||||
|
val id = guest.id ?: return false
|
||||||
|
if (bookingRepo.countByPrimaryGuestId(id) > 0) return false
|
||||||
|
if (guestVehicleRepo.existsByGuestId(id)) return false
|
||||||
|
if (guestDocumentRepo.existsByGuestId(id)) return false
|
||||||
|
if (guestRatingRepo.existsByGuestId(id)) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Set<Guest>.toResponse(
|
private fun Set<Guest>.toResponse(
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ import java.util.UUID
|
|||||||
interface BookingRepo : JpaRepository<Booking, UUID> {
|
interface BookingRepo : JpaRepository<Booking, UUID> {
|
||||||
fun findByPropertyIdAndSourceBookingId(propertyId: UUID, sourceBookingId: String): Booking?
|
fun findByPropertyIdAndSourceBookingId(propertyId: UUID, sourceBookingId: String): Booking?
|
||||||
fun existsByPropertyIdAndSourceBookingId(propertyId: UUID, sourceBookingId: String): Boolean
|
fun existsByPropertyIdAndSourceBookingId(propertyId: UUID, sourceBookingId: String): Boolean
|
||||||
|
fun countByPrimaryGuestId(guestId: UUID): Long
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ import java.util.UUID
|
|||||||
interface GuestDocumentRepo : JpaRepository<GuestDocument, UUID> {
|
interface GuestDocumentRepo : JpaRepository<GuestDocument, UUID> {
|
||||||
fun findByPropertyIdAndGuestIdOrderByUploadedAtDesc(propertyId: UUID, guestId: UUID): List<GuestDocument>
|
fun findByPropertyIdAndGuestIdOrderByUploadedAtDesc(propertyId: UUID, guestId: UUID): List<GuestDocument>
|
||||||
fun findByIdAndPropertyIdAndGuestId(id: UUID, propertyId: UUID, guestId: UUID): GuestDocument?
|
fun findByIdAndPropertyIdAndGuestId(id: UUID, propertyId: UUID, guestId: UUID): GuestDocument?
|
||||||
|
fun existsByGuestId(guestId: UUID): Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.util.UUID
|
|||||||
interface GuestRatingRepo : JpaRepository<GuestRating, UUID> {
|
interface GuestRatingRepo : JpaRepository<GuestRating, UUID> {
|
||||||
fun findByGuestIdOrderByCreatedAtDesc(guestId: UUID): List<GuestRating>
|
fun findByGuestIdOrderByCreatedAtDesc(guestId: UUID): List<GuestRating>
|
||||||
fun existsByGuestIdAndBookingId(guestId: UUID, bookingId: UUID): Boolean
|
fun existsByGuestIdAndBookingId(guestId: UUID, bookingId: UUID): Boolean
|
||||||
|
fun existsByGuestId(guestId: UUID): Boolean
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ interface GuestVehicleRepo : JpaRepository<GuestVehicle, UUID> {
|
|||||||
fun findByPropertyIdAndVehicleNumberIgnoreCase(propertyId: UUID, vehicleNumber: String): GuestVehicle?
|
fun findByPropertyIdAndVehicleNumberIgnoreCase(propertyId: UUID, vehicleNumber: String): GuestVehicle?
|
||||||
fun findByGuestIdIn(guestIds: List<UUID>): List<GuestVehicle>
|
fun findByGuestIdIn(guestIds: List<UUID>): List<GuestVehicle>
|
||||||
fun existsByPropertyIdAndVehicleNumberIgnoreCase(propertyId: UUID, vehicleNumber: String): Boolean
|
fun existsByPropertyIdAndVehicleNumberIgnoreCase(propertyId: UUID, vehicleNumber: String): Boolean
|
||||||
|
fun existsByGuestId(guestId: UUID): Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user