diff --git a/service/src/main/kotlin/com/sangdol/roomescape/order/business/OrderService.kt b/service/src/main/kotlin/com/sangdol/roomescape/order/business/OrderService.kt index 1662d322..76a9dcdc 100644 --- a/service/src/main/kotlin/com/sangdol/roomescape/order/business/OrderService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/order/business/OrderService.kt @@ -36,14 +36,18 @@ class OrderService( ) { fun confirm(reservationId: Long, paymentConfirmRequest: PaymentConfirmRequest) { - val trial = paymentAttemptRepository.countByReservationId(reservationId) + var trial: Long = 0 val paymentKey = paymentConfirmRequest.paymentKey log.info { "[confirm] 결제 및 예약 확정 시작: reservationId=${reservationId}, paymentKey=${paymentKey}" } - try { - transactionExecutionUtil.withNewTransaction(isReadOnly = false) { - validateAndMarkInProgress(reservationId) + trial = transactionExecutionUtil.withNewTransaction(isReadOnly = false) { + getTrialAfterValidateCanConfirm(reservationId).also { + reservationService.markInProgress(reservationId) + } + } ?: run { + log.warn { "[confirm] 모든 paymentAttempts 조회 과정에서의 예상치 못한 null 응답: reservationId=${reservationId}" } + throw OrderException(OrderErrorCode.BOOKING_UNEXPECTED_ERROR) } val paymentClientResponse: PaymentGatewayResponse = @@ -61,20 +65,32 @@ class OrderService( } } - private fun validateAndMarkInProgress(reservationId: Long) { + private fun getTrialAfterValidateCanConfirm(reservationId: Long): Long { log.info { "[validateAndMarkInProgress] 예약 확정 가능 여부 검증 시작: reservationId=${reservationId}" } val reservation: ReservationStateResponse = reservationService.findStatusWithLock(reservationId) val schedule: ScheduleStateResponse = scheduleService.findStateWithLock(reservation.scheduleId) try { orderValidator.validateCanConfirm(reservation, schedule) - log.info { "[validateAndMarkInProgress] 예약 확정 가능 여부 검증 완료: reservationId=${reservationId}" } + + return getTrialIfSuccessAttemptNotExists(reservationId).also { + log.info { "[validateAndMarkInProgress] 예약 확정 가능 여부 검증 완료: reservationId=${reservationId}" } + } } catch (e: OrderException) { val errorCode = OrderErrorCode.NOT_CONFIRMABLE throw OrderException(errorCode, e.message) } + } - reservationService.markInProgress(reservationId) + private fun getTrialIfSuccessAttemptNotExists(reservationId: Long): Long { + val paymentAttempts: List = paymentAttemptRepository.findAllByReservationId(reservationId) + + if (paymentAttempts.any { it.result == AttemptResult.SUCCESS }) { + log.info { "[validateCanConfirm] 이미 결제 완료된 예약: id=${reservationId}" } + throw OrderException(OrderErrorCode.BOOKING_ALREADY_COMPLETED) + } + + return paymentAttempts.size.toLong() } private fun requestConfirmPayment( diff --git a/service/src/main/kotlin/com/sangdol/roomescape/order/business/OrderValidator.kt b/service/src/main/kotlin/com/sangdol/roomescape/order/business/OrderValidator.kt index 8ee18671..7be57c88 100644 --- a/service/src/main/kotlin/com/sangdol/roomescape/order/business/OrderValidator.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/order/business/OrderValidator.kt @@ -16,18 +16,11 @@ import java.time.LocalDateTime private val log: KLogger = KotlinLogging.logger {} @Component -class OrderValidator( - private val paymentAttemptRepository: PaymentAttemptRepository -) { +class OrderValidator { fun validateCanConfirm( reservation: ReservationStateResponse, schedule: ScheduleStateResponse ) { - if (paymentAttemptRepository.isSuccessAttemptExists(reservation.id)) { - log.info { "[validateCanConfirm] 이미 결제 완료된 예약: id=${reservation.id}" } - throw OrderException(OrderErrorCode.BOOKING_ALREADY_COMPLETED) - } - validateReservationStatus(reservation) validateScheduleStatus(schedule) } diff --git a/service/src/main/kotlin/com/sangdol/roomescape/order/infrastructure/persistence/PaymentAttemptRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/order/infrastructure/persistence/PaymentAttemptRepository.kt index 3c5e8666..4f2ff58f 100644 --- a/service/src/main/kotlin/com/sangdol/roomescape/order/infrastructure/persistence/PaymentAttemptRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/order/infrastructure/persistence/PaymentAttemptRepository.kt @@ -23,4 +23,6 @@ interface PaymentAttemptRepository: JpaRepository { """ ) fun isSuccessAttemptExists(reservationId: Long): Boolean + + fun findAllByReservationId(reservationId: Long): List }