[#56] 예약 & 결제 프로세스 및 패키지 구조 재정의 #57

Merged
pricelees merged 45 commits from refactor/#56 into main 2025-10-09 09:33:29 +00:00
3 changed files with 47 additions and 12 deletions
Showing only changes of commit 44c556776d - Show all commits

View File

@ -71,20 +71,19 @@ class ScheduleService(
@Transactional
fun holdSchedule(id: Long) {
log.info { "[holdSchedule] 일정 Holding 시작: id=$id" }
val result: Int = scheduleRepository.changeStatus(
id = id,
currentStatus = ScheduleStatus.AVAILABLE,
val schedule = findForUpdateOrThrow(id).also {
scheduleValidator.validateCanHold(it)
}
scheduleRepository.changeStatus(
id = schedule.id,
currentStatus = schedule.status,
changeStatus = ScheduleStatus.HOLD
).also {
log.info { "[holdSchedule] $it 개의 row 변경 완료" }
}
if (result == 0) {
throw ScheduleException(ScheduleErrorCode.SCHEDULE_NOT_AVAILABLE)
}
log.info { "[holdSchedule] 일정 Holding 완료: id=$id" }
}
}
// ========================================
// All-Admin (본사, 매장 모두 사용가능)
@ -222,7 +221,18 @@ class ScheduleService(
return scheduleRepository.findByIdOrNull(id)
?.also { log.info { "[findOrThrow] 일정 조회 완료: id=$id" } }
?: run {
log.warn { "[updateSchedule] 일정 조회 실패. id=$id" }
log.warn { "[findOrThrow] 일정 조회 실패. id=$id" }
throw ScheduleException(ScheduleErrorCode.SCHEDULE_NOT_FOUND)
}
}
private fun findForUpdateOrThrow(id: Long): ScheduleEntity {
log.info { "[findForUpdateOrThrow] 일정 LOCK + 조회 시작: id=$id" }
return scheduleRepository.findByIdForUpdate(id)
?.also { log.info { "[findForUpdateOrThrow] 일정 조회 완료: id=$id" } }
?: run {
log.warn { "[findForUpdateOrThrow] 일정 조회 실패. id=$id" }
throw ScheduleException(ScheduleErrorCode.SCHEDULE_NOT_FOUND)
}
}

View File

@ -22,6 +22,15 @@ private val log: KLogger = KotlinLogging.logger {}
class ScheduleValidator(
private val scheduleRepository: ScheduleRepository
) {
fun validateCanHold(schedule: ScheduleEntity) {
if (schedule.status != ScheduleStatus.AVAILABLE) {
log.info { "[validateCanHold] HOLD 실패: id=${schedule.id}, status=${schedule.status}" }
throw ScheduleException(ScheduleErrorCode.SCHEDULE_NOT_AVAILABLE)
}
validateNotInPast(schedule.date, schedule.time)
}
fun validateCanDelete(schedule: ScheduleEntity) {
val status: ScheduleStatus = schedule.status

View File

@ -155,12 +155,28 @@ class ScheduleApiTest(
}
}
test("해당 일정의 시작 시간이 현재 시간 이전이면 실패한다.") {
val schedule = dummyInitializer.createSchedule(
request = ScheduleFixture.createRequest.copy(
date = KoreaDate.today(),
time = KoreaTime.now().minusMinutes(1)
)
)
runExceptionTest(
token = testAuthUtil.defaultUserLogin().second,
method = HttpMethod.POST,
endpoint = "/schedules/${schedule.id}/hold",
expectedErrorCode = ScheduleErrorCode.PAST_DATE_TIME
)
}
test("일정이 없으면 실패한다.") {
runExceptionTest(
token = testAuthUtil.defaultUserLogin().second,
method = HttpMethod.POST,
endpoint = "/schedules/${INVALID_PK}/hold",
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_AVAILABLE
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_FOUND
)
}
}