generated from pricelees/issue-pr-template
[#52] 만료 예약 / 일정 스케쥴링 작업 추가 및 동시성 처리를 위한 일부 코드 수정 #53
@ -11,7 +11,6 @@ import com.sangdol.roomescape.reservation.web.*
|
||||
import com.sangdol.roomescape.schedule.business.ScheduleService
|
||||
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus
|
||||
import com.sangdol.roomescape.schedule.web.ScheduleOverviewResponse
|
||||
import com.sangdol.roomescape.schedule.web.ScheduleUpdateRequest
|
||||
import com.sangdol.roomescape.theme.business.ThemeService
|
||||
import com.sangdol.roomescape.user.business.UserService
|
||||
import com.sangdol.roomescape.user.web.UserContactResponse
|
||||
@ -58,9 +57,10 @@ class ReservationService(
|
||||
|
||||
run {
|
||||
reservation.confirm()
|
||||
scheduleService.updateSchedule(
|
||||
reservation.scheduleId,
|
||||
ScheduleUpdateRequest(status = ScheduleStatus.RESERVED)
|
||||
scheduleService.changeStatus(
|
||||
scheduleId = reservation.scheduleId,
|
||||
currentStatus = ScheduleStatus.HOLD,
|
||||
changeStatus = ScheduleStatus.RESERVED
|
||||
)
|
||||
}.also {
|
||||
log.info { "[ReservationService.confirmReservation] Pending 예약 확정 완료: reservationId=${id}" }
|
||||
@ -74,9 +74,10 @@ class ReservationService(
|
||||
val reservation: ReservationEntity = findOrThrow(reservationId)
|
||||
|
||||
run {
|
||||
scheduleService.updateSchedule(
|
||||
reservation.scheduleId,
|
||||
ScheduleUpdateRequest(status = ScheduleStatus.AVAILABLE)
|
||||
scheduleService.changeStatus(
|
||||
scheduleId = reservation.scheduleId,
|
||||
currentStatus = ScheduleStatus.RESERVED,
|
||||
changeStatus = ScheduleStatus.AVAILABLE
|
||||
)
|
||||
saveCanceledReservation(user, reservation, request.cancelReason)
|
||||
reservation.cancel()
|
||||
@ -148,6 +149,7 @@ class ReservationService(
|
||||
status = CanceledReservationStatus.COMPLETED
|
||||
).also {
|
||||
canceledReservationRepository.save(it)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import com.sangdol.roomescape.schedule.exception.ScheduleErrorCode
|
||||
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity
|
||||
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntityFactory
|
||||
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository
|
||||
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus
|
||||
import com.sangdol.roomescape.schedule.web.*
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
@ -66,7 +67,11 @@ class ScheduleService(
|
||||
@Transactional
|
||||
fun holdSchedule(id: Long) {
|
||||
log.info { "[ScheduleService.holdSchedule] 일정 Holding 시작: id=$id" }
|
||||
val result: Int = scheduleRepository.holdAvailableScheduleById(id)
|
||||
val result: Int = scheduleRepository.changeStatus(
|
||||
id = id,
|
||||
currentStatus = ScheduleStatus.AVAILABLE,
|
||||
changeStatus = ScheduleStatus.HOLD
|
||||
)
|
||||
|
||||
if (result == 0) {
|
||||
log.info { "[ScheduleService.holdSchedule] Holding된 일정 없음: id=${id}, count = " }
|
||||
@ -188,6 +193,15 @@ class ScheduleService(
|
||||
return overview.toOverviewResponse()
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun changeStatus(scheduleId: Long, currentStatus: ScheduleStatus, changeStatus: ScheduleStatus) {
|
||||
log.info { "[ScheduleService.reserveSchedule] 일정 상태 변경 시작: id=${scheduleId}, currentStatus=${currentStatus}, changeStatus=${changeStatus}" }
|
||||
|
||||
scheduleRepository.changeStatus(scheduleId, currentStatus, changeStatus).also {
|
||||
log.info { "[ScheduleService.reserveSchedule] 일정 상태 변경 완료: id=${scheduleId}, currentStatus=${currentStatus}, changeStatus=${changeStatus}" }
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Common (공통 메서드)
|
||||
// ========================================
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package com.sangdol.roomescape.schedule.infrastructure.persistence
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.data.jpa.repository.Query
|
||||
import com.sangdol.roomescape.schedule.business.domain.ScheduleOverview
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.data.jpa.repository.Modifying
|
||||
import org.springframework.data.jpa.repository.Query
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
|
||||
@ -85,15 +85,22 @@ interface ScheduleRepository : JpaRepository<ScheduleEntity, Long> {
|
||||
fun findOverviewByIdOrNull(id: Long): ScheduleOverview?
|
||||
|
||||
@Modifying
|
||||
@Query("""
|
||||
@Query(
|
||||
"""
|
||||
UPDATE
|
||||
ScheduleEntity s
|
||||
SET
|
||||
s.status = 'HOLD'
|
||||
s.status = :changeStatus,
|
||||
s.holdExpiredAt = CASE
|
||||
WHEN :changeStatus = com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus.HOLD
|
||||
THEN CURRENT_TIMESTAMP + 5 MINUTE
|
||||
ELSE NULL
|
||||
END
|
||||
WHERE
|
||||
s._id = :id
|
||||
AND
|
||||
s.status = 'AVAILABLE'
|
||||
""")
|
||||
fun holdAvailableScheduleById(id: Long): Int
|
||||
s.status = :currentStatus
|
||||
"""
|
||||
)
|
||||
fun changeStatus(id: Long, currentStatus: ScheduleStatus, changeStatus: ScheduleStatus): Int
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import com.sangdol.roomescape.supports.FunSpecSpringbootTest
|
||||
import com.sangdol.roomescape.supports.IDGenerator
|
||||
import com.sangdol.roomescape.supports.initialize
|
||||
import io.kotest.assertions.assertSoftly
|
||||
import io.kotest.matchers.nulls.shouldBeNull
|
||||
import io.kotest.matchers.nulls.shouldNotBeNull
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
@ -48,7 +49,7 @@ class ScheduleServiceTest(
|
||||
}
|
||||
}
|
||||
|
||||
test("유저가 일정을 Holding 하는 경우에는 updatedAt, updatedBy 컬럼이 변경되지 않는다.") {
|
||||
test("유저가 일정을 Holding 상태로 변경하는 경우에는 holdExpiredAt 컬럼이 5분 뒤로 지정되며, updatedAt, updatedBy 컬럼이 변경되지 않는다.") {
|
||||
val createdScheduleId: Long = createSchedule()
|
||||
|
||||
initialize("updatedBy 변경 확인을 위한 MDC 재설정") {
|
||||
@ -64,6 +65,30 @@ class ScheduleServiceTest(
|
||||
this.shouldNotBeNull()
|
||||
this.updatedAt shouldBe this.createdAt
|
||||
this.updatedBy shouldBe this.createdBy
|
||||
this.holdExpiredAt.shouldNotBeNull()
|
||||
}
|
||||
}
|
||||
|
||||
test("유저가 일정을 Holding이 아닌 다른 상태로 변경 경우에는 holdExpiredAt 컬럼이 null로 지정되며, updatedAt, updatedBy 컬럼이 변경되지 않는다.") {
|
||||
val createdScheduleId: Long = createSchedule()
|
||||
|
||||
initialize("updatedBy 변경 확인을 위한 MDC 재설정") {
|
||||
MdcPrincipalIdUtil.clear()
|
||||
IDGenerator.create().also {
|
||||
MdcPrincipalIdUtil.set(it.toString())
|
||||
}
|
||||
}
|
||||
|
||||
scheduleService.holdSchedule(createdScheduleId).also {
|
||||
scheduleRepository.findByIdOrNull(createdScheduleId)!!.holdExpiredAt.shouldNotBeNull()
|
||||
}
|
||||
|
||||
scheduleService.changeStatus(createdScheduleId, ScheduleStatus.HOLD, ScheduleStatus.RESERVED).also {
|
||||
assertSoftly(scheduleRepository.findByIdOrNull(createdScheduleId)!!) {
|
||||
this.updatedAt shouldBe this.createdAt
|
||||
this.updatedBy shouldBe this.createdBy
|
||||
this.holdExpiredAt.shouldBeNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user