diff --git a/service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationService.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationService.kt index 6be365ad..8496801d 100644 --- a/service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationService.kt @@ -4,17 +4,14 @@ import com.sangdol.common.persistence.IDGenerator import com.sangdol.roomescape.common.types.CurrentUserContext import com.sangdol.roomescape.payment.business.PaymentService import com.sangdol.roomescape.payment.dto.PaymentResponse -import com.sangdol.roomescape.reservation.dto.PendingReservationCreateRequest -import com.sangdol.roomescape.reservation.dto.PendingReservationCreateResponse -import com.sangdol.roomescape.reservation.dto.ReservationCancelRequest -import com.sangdol.roomescape.reservation.dto.ReservationAdditionalResponse -import com.sangdol.roomescape.reservation.dto.ReservationOverviewListResponse -import com.sangdol.roomescape.reservation.mapper.toEntity -import com.sangdol.roomescape.reservation.mapper.toOverviewResponse -import com.sangdol.roomescape.reservation.mapper.toAdditionalResponse +import com.sangdol.roomescape.reservation.dto.* import com.sangdol.roomescape.reservation.exception.ReservationErrorCode import com.sangdol.roomescape.reservation.exception.ReservationException import com.sangdol.roomescape.reservation.infrastructure.persistence.* +import com.sangdol.roomescape.reservation.mapper.toAdditionalResponse +import com.sangdol.roomescape.reservation.mapper.toEntity +import com.sangdol.roomescape.reservation.mapper.toOverviewResponse +import com.sangdol.roomescape.reservation.mapper.toStateResponse import com.sangdol.roomescape.schedule.business.ScheduleService import com.sangdol.roomescape.schedule.dto.ScheduleStateResponse import com.sangdol.roomescape.schedule.dto.ScheduleWithThemeAndStoreResponse @@ -142,6 +139,30 @@ class ReservationService( } } + @Transactional(readOnly = true) + fun findStatusWithLock(id: Long): ReservationStateResponse { + log.info { "[findStatusWithLock] 예약 LOCK + 상태 조회 시작: reservationId=${id}" } + + return reservationRepository.findByIdForUpdate(id)?.let { + log.info { "[findStatusWithLock] 예약 LOCK + 상태 조회 완료: reservationId=${id}" } + it.toStateResponse() + } ?: run { + log.warn { "[findStatusWithLock] 예약 LOCK + 상태 조회 실패: reservationId=${id}" } + throw ReservationException(ReservationErrorCode.RESERVATION_NOT_FOUND) + } + } + + @Transactional + fun markInProgress(reservationId: Long) { + log.info { "[markInProgress] 예약 상태 ${ReservationStatus.PAYMENT_IN_PROGRESS} 변경 시작." } + + findOrThrow(reservationId).apply { + this.status = ReservationStatus.PAYMENT_IN_PROGRESS + }.also { + log.info { "[markInProgress] 예약 상태 ${ReservationStatus.PAYMENT_IN_PROGRESS} 변경 완료" } + } + } + private fun findOrThrow(id: Long): ReservationEntity { log.info { "[findOrThrow] 예약 조회 시작: reservationId=${id}" } diff --git a/service/src/main/kotlin/com/sangdol/roomescape/reservation/dto/ReservationFindDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/dto/ReservationFindDTO.kt index 7244a70f..29737d9c 100644 --- a/service/src/main/kotlin/com/sangdol/roomescape/reservation/dto/ReservationFindDTO.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/dto/ReservationFindDTO.kt @@ -35,3 +35,10 @@ data class ReserverInfo( data class ReservationOverviewListResponse( val reservations: List ) + +data class ReservationStateResponse( + val id: Long, + val scheduleId: Long, + val status: ReservationStatus, + val createdAt: Instant +) diff --git a/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt index 7d1827f9..29a3500a 100644 --- a/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt @@ -1,6 +1,8 @@ package com.sangdol.roomescape.reservation.infrastructure.persistence +import jakarta.persistence.LockModeType import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Lock import org.springframework.data.jpa.repository.Modifying import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.query.Param @@ -10,6 +12,10 @@ interface ReservationRepository : JpaRepository { fun findAllByUserIdAndStatusIsIn(userId: Long, statuses: List): List + @Lock(LockModeType.PESSIMISTIC_WRITE) + @Query("SELECT r FROM ReservationEntity r WHERE r._id = :id") + fun findByIdForUpdate(@Param("id") id: Long): ReservationEntity? + @Modifying @Query( """ diff --git a/service/src/main/kotlin/com/sangdol/roomescape/reservation/mapper/ReservationMappingExtensions.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/mapper/ReservationMappingExtensions.kt index 052fffd4..33762eeb 100644 --- a/service/src/main/kotlin/com/sangdol/roomescape/reservation/mapper/ReservationMappingExtensions.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/mapper/ReservationMappingExtensions.kt @@ -4,6 +4,7 @@ import com.sangdol.roomescape.payment.dto.PaymentResponse import com.sangdol.roomescape.reservation.dto.PendingReservationCreateRequest import com.sangdol.roomescape.reservation.dto.ReservationAdditionalResponse import com.sangdol.roomescape.reservation.dto.ReservationOverviewResponse +import com.sangdol.roomescape.reservation.dto.ReservationStateResponse import com.sangdol.roomescape.reservation.dto.ReserverInfo import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationEntity import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationStatus @@ -57,3 +58,10 @@ private fun ReservationEntity.toReserverInfo() = ReserverInfo( participantCount = this.participantCount, requirement = this.requirement ) + +fun ReservationEntity.toStateResponse() = ReservationStateResponse( + id = this.id, + scheduleId = this.scheduleId, + status = this.status, + createdAt = this.createdAt +)