generated from pricelees/issue-pr-template
[#39] '시간' -> '일정' 스키마 변경으로 테마별 시간 지정 #40
123
src/main/kotlin/roomescape/schedule/business/ScheduleService.kt
Normal file
123
src/main/kotlin/roomescape/schedule/business/ScheduleService.kt
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package roomescape.schedule.business
|
||||||
|
|
||||||
|
import ScheduleException
|
||||||
|
import com.github.f4b6a3.tsid.TsidFactory
|
||||||
|
import io.github.oshai.kotlinlogging.KLogger
|
||||||
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import roomescape.common.config.next
|
||||||
|
import roomescape.member.business.MemberService
|
||||||
|
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.*
|
||||||
|
import java.time.LocalDate
|
||||||
|
|
||||||
|
private val log: KLogger = KotlinLogging.logger {}
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class ScheduleService(
|
||||||
|
private val scheduleRepository: ScheduleRepository,
|
||||||
|
private val scheduleValidator: ScheduleValidator,
|
||||||
|
private val tsidFactory: TsidFactory,
|
||||||
|
private val memberService: MemberService
|
||||||
|
) {
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun findThemesByDate(date: LocalDate): AvailableThemeIdListResponse {
|
||||||
|
log.info { "[ScheduleService.findThemesByDate] 동일한 날짜의 모든 테마 조회: date=$date" }
|
||||||
|
|
||||||
|
return scheduleRepository.findAllByDate(date)
|
||||||
|
.toThemeIdListResponse()
|
||||||
|
.also {
|
||||||
|
log.info { "[ScheduleService.findThemesByDate] date=${date}인 ${it.themeIds.size}개 테마 조회 완료" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun findSchedules(date: LocalDate, themeId: Long): ScheduleRetrieveListResponse {
|
||||||
|
log.info { "[ScheduleService.findSchedules] 동일한 날짜와 테마인 모든 일정 조회: date=${date}, themeId=${themeId}" }
|
||||||
|
|
||||||
|
return scheduleRepository.findAllByDateAndThemeId(date, themeId)
|
||||||
|
.toRetrieveListResponse()
|
||||||
|
.also {
|
||||||
|
log.info { "[ScheduleService.findSchedules] date=${date}, themeId=${themeId}인 ${it.schedules.size}개 일정 조회 완료" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun findDetail(id: Long): ScheduleDetailRetrieveResponse {
|
||||||
|
log.info { "[ScheduleService.findDetail] 일정 상세 정보조회 시작: id=$id" }
|
||||||
|
|
||||||
|
val schedule: ScheduleEntity = findOrThrow(id)
|
||||||
|
|
||||||
|
val createdBy = memberService.findById(schedule.createdBy).name
|
||||||
|
val updatedBy = memberService.findById(schedule.updatedBy).name
|
||||||
|
|
||||||
|
return schedule.toDetailRetrieveResponse(createdBy, updatedBy)
|
||||||
|
.also {
|
||||||
|
log.info { "[ScheduleService.findDetail] 일정 상세 조회 완료: id=$id" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun createSchedule(request: ScheduleCreateRequest): ScheduleCreateResponse {
|
||||||
|
log.info { "[ScheduleService.createSchedule] 일정 생성 시작: date=${request.date}, time=${request.time}, themeId=${request.themeId}" }
|
||||||
|
|
||||||
|
scheduleValidator.validateCanCreate(request)
|
||||||
|
|
||||||
|
val schedule = ScheduleEntity(
|
||||||
|
id = tsidFactory.next(),
|
||||||
|
date = request.date,
|
||||||
|
time = request.time,
|
||||||
|
themeId = request.themeId,
|
||||||
|
status = ScheduleStatus.AVAILABLE
|
||||||
|
)
|
||||||
|
|
||||||
|
return ScheduleCreateResponse(scheduleRepository.save(schedule).id)
|
||||||
|
.also {
|
||||||
|
log.info { "[ScheduleService.createSchedule] 일정 생성 완료: id=${it.id}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun updateSchedule(id: Long, request: ScheduleUpdateRequest) {
|
||||||
|
log.info { "[ScheduleService.updateSchedule] 일정 수정 시작: id=$id, request=${request}" }
|
||||||
|
val schedule: ScheduleEntity = findOrThrow(id)
|
||||||
|
|
||||||
|
scheduleValidator.validateCanUpdate(schedule, request)
|
||||||
|
|
||||||
|
schedule.modifyIfNotNull(
|
||||||
|
request.time,
|
||||||
|
request.status
|
||||||
|
).also {
|
||||||
|
log.info { "[ScheduleService.updateSchedule] 일정 수정 완료: id=$id, request=${request}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun deleteSchedule(id: Long) {
|
||||||
|
log.info { "[ScheduleService.deleteSchedule] 일정 삭제 시작: id=$id" }
|
||||||
|
|
||||||
|
val schedule: ScheduleEntity = findOrThrow(id)
|
||||||
|
|
||||||
|
scheduleValidator.validateCanDelete(schedule)
|
||||||
|
|
||||||
|
scheduleRepository.delete(schedule).also {
|
||||||
|
log.info { "[ScheduleService.deleteSchedule] 일정 삭제 완료: id=$id" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findOrThrow(id: Long): ScheduleEntity {
|
||||||
|
log.info { "[ScheduleService.findOrThrow] 일정 조회 시작: id=$id" }
|
||||||
|
|
||||||
|
return scheduleRepository.findByIdOrNull(id)
|
||||||
|
?: run {
|
||||||
|
log.warn { "[ScheduleService.updateSchedule] 일정 조회 실패. id=$id" }
|
||||||
|
throw ScheduleException(ScheduleErrorCode.SCHEDULE_NOT_FOUND)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
validateDateTime(date, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun validateCanCreate(request: ScheduleCreateRequest) {
|
||||||
|
val date: LocalDate = request.date
|
||||||
|
val time: LocalTime = request.time
|
||||||
|
val themeId: Long = request.themeId
|
||||||
|
|
||||||
|
validateAlreadyExists(date, themeId, time)
|
||||||
|
validateDateTime(date, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateAlreadyExists(date: LocalDate, themeId: Long, time: LocalTime) {
|
||||||
|
if (scheduleRepository.existsByDateAndThemeIdAndTime(date, themeId, time)) {
|
||||||
|
log.info {
|
||||||
|
"[ScheduleValidator.validateAlreadyExists] 동일한 날짜, 테마, 시간 존재: date=${date} / themeId=${themeId} / time=${time}"
|
||||||
|
}
|
||||||
|
throw ScheduleException(ScheduleErrorCode.SCHEDULE_ALREADY_EXISTS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateDateTime(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user