78 lines
3.2 KiB
Kotlin

package roomescape.schedule.business
import ScheduleException
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.stereotype.Component
import roomescape.schedule.exception.ScheduleErrorCode
import roomescape.schedule.infrastructure.persistence.ScheduleEntity
import roomescape.schedule.infrastructure.persistence.ScheduleRepository
import roomescape.schedule.infrastructure.persistence.ScheduleStatus
import roomescape.schedule.web.ScheduleCreateRequest
import roomescape.schedule.web.ScheduleUpdateRequest
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
private val log: KLogger = KotlinLogging.logger {}
@Component
class ScheduleValidator(
private val scheduleRepository: ScheduleRepository
) {
fun validateCanDelete(schedule: ScheduleEntity) {
val status: ScheduleStatus = schedule.status
if (status !in listOf(ScheduleStatus.AVAILABLE, ScheduleStatus.BLOCKED)) {
log.info { "[ScheduleValidator.validateCanDelete] 삭제 실패: id=${schedule.id} / status=${status}" }
throw ScheduleException(ScheduleErrorCode.SCHEDULE_IN_USE)
}
}
fun validateCanUpdate(schedule: ScheduleEntity, request: ScheduleUpdateRequest) {
val date: LocalDate = schedule.date
val time: LocalTime = request.time ?: schedule.time
validateNotInPast(date, time)
}
fun validateCanCreate(storeId: Long, request: ScheduleCreateRequest) {
val date: LocalDate = request.date
val time: LocalTime = request.time
val themeId: Long = request.themeId
validateAlreadyExists(storeId, date, themeId, time)
validateNotInPast(date, time)
validateTimeNotConflict(storeId, request.date, request.themeId, request.time)
}
private fun validateAlreadyExists(storeId: Long, date: LocalDate, themeId: Long, time: LocalTime) {
if (scheduleRepository.existsDuplicate(storeId, date, themeId, time)) {
log.info {
"[ScheduleValidator.validateAlreadyExists] 동일한 날짜, 테마, 시간 존재로 인한 실패: date=${date} / themeId=${themeId} / time=${time}"
}
throw ScheduleException(ScheduleErrorCode.SCHEDULE_ALREADY_EXISTS)
}
}
private fun validateNotInPast(date: LocalDate, time: LocalTime) {
val dateTime = LocalDateTime.of(date, time)
if (dateTime.isBefore(LocalDateTime.now())) {
log.info {
"[ScheduleValidator.validateDateTime] 이전 시간 선택으로 인한 실패: date=${date} / time=${time}"
}
throw ScheduleException(ScheduleErrorCode.PAST_DATE_TIME)
}
}
private fun validateTimeNotConflict(storeId: Long, date: LocalDate, themeId: Long, time: LocalTime) {
scheduleRepository.findStoreSchedulesWithThemeByDate(storeId, date, themeId)
.firstOrNull { it.containsTime(time) }
?.let {
log.info { "[ScheduleValidator.validateTimeNotConflict] 시간이 겹치는 일정 존재: conflictSchedule(Id=${it.id}, time=${it.time}~${it.getEndAt()})" }
throw ScheduleException(ScheduleErrorCode.SCHEDULE_TIME_CONFLICT)
}
}
}