generated from pricelees/issue-pr-template
feat: 예약에서의 검증 케이스 추가 및 예약 확정 API Http 메서드 변경(PATCH -> POST)
This commit is contained in:
parent
36e846ded3
commit
9660d5438d
@ -21,7 +21,7 @@ import roomescape.schedule.infrastructure.persistence.ScheduleStatus
|
||||
import roomescape.schedule.web.ScheduleSummaryResponse
|
||||
import roomescape.schedule.web.ScheduleUpdateRequest
|
||||
import roomescape.theme.business.ThemeService
|
||||
import roomescape.theme.web.ThemeRetrieveResponseV2
|
||||
import roomescape.theme.web.ThemeSummaryResponse
|
||||
import java.time.LocalDateTime
|
||||
|
||||
private val log: KLogger = KotlinLogging.logger {}
|
||||
@ -29,6 +29,7 @@ private val log: KLogger = KotlinLogging.logger {}
|
||||
@Service
|
||||
class ReservationService(
|
||||
private val reservationRepository: ReservationRepository,
|
||||
private val reservationValidator: ReservationValidator,
|
||||
private val scheduleService: ScheduleService,
|
||||
private val memberService: MemberService,
|
||||
private val themeService: ThemeService,
|
||||
@ -44,10 +45,9 @@ class ReservationService(
|
||||
): PendingReservationCreateResponse {
|
||||
log.info { "[ReservationService.createPendingReservation] Pending 예약 생성 시작: schedule=${request.scheduleId}" }
|
||||
|
||||
val reservation: ReservationEntity = request.toEntity(
|
||||
id = tsidFactory.next(),
|
||||
memberId = memberId
|
||||
)
|
||||
validateCanCreate(request)
|
||||
|
||||
val reservation: ReservationEntity = request.toEntity(id = tsidFactory.next(), memberId = memberId)
|
||||
|
||||
return PendingReservationCreateResponse(reservationRepository.save(reservation).id)
|
||||
.also { "[ReservationService.createPendingReservation] Pending 예약 생성 완료: reservationId=${it}, schedule=${request.scheduleId}" }
|
||||
@ -58,10 +58,6 @@ class ReservationService(
|
||||
log.info { "[ReservationService.confirmReservation] Pending 예약 확정 시작: reservationId=${id}" }
|
||||
val reservation: ReservationEntity = findOrThrow(id)
|
||||
|
||||
if (reservation.status != ReservationStatus.PENDING) {
|
||||
log.warn { "[ReservationService.confirmReservation] 예약이 Pending 상태가 아님: reservationId=${id}, status=${reservation.status}" }
|
||||
}
|
||||
|
||||
run {
|
||||
reservation.confirm()
|
||||
scheduleService.updateSchedule(
|
||||
@ -100,7 +96,7 @@ class ReservationService(
|
||||
|
||||
return ReservationSummaryRetrieveListResponse(reservations.map {
|
||||
val schedule: ScheduleSummaryResponse = scheduleService.findSummaryById(it.scheduleId)
|
||||
val theme: ThemeRetrieveResponseV2 = themeService.findById(schedule.themeId)
|
||||
val theme: ThemeSummaryResponse = themeService.findSummaryById(schedule.themeId)
|
||||
|
||||
ReservationSummaryRetrieveResponse(
|
||||
id = it.id,
|
||||
@ -109,7 +105,9 @@ class ReservationService(
|
||||
startAt = schedule.time,
|
||||
status = it.status
|
||||
)
|
||||
})
|
||||
}).also {
|
||||
log.info { "[ReservationService.findSummaryByMemberId] ${it.reservations.size}개의 예약 조회 완료: memberId=${memberId}" }
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@ -160,4 +158,11 @@ class ReservationService(
|
||||
canceledReservationRepository.save(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateCanCreate(request: PendingReservationCreateRequest) {
|
||||
val schedule = scheduleService.findSummaryById(request.scheduleId)
|
||||
val theme = themeService.findSummaryById(schedule.themeId)
|
||||
|
||||
reservationValidator.validateCanCreate(schedule, theme, request)
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
package roomescape.reservation.business
|
||||
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.springframework.stereotype.Component
|
||||
import roomescape.reservation.exception.ReservationErrorCode
|
||||
import roomescape.reservation.exception.ReservationException
|
||||
import roomescape.reservation.web.PendingReservationCreateRequest
|
||||
import roomescape.schedule.infrastructure.persistence.ScheduleStatus
|
||||
import roomescape.schedule.web.ScheduleSummaryResponse
|
||||
import roomescape.theme.web.ThemeSummaryResponse
|
||||
|
||||
private val log: KLogger = KotlinLogging.logger {}
|
||||
|
||||
@Component
|
||||
class ReservationValidator {
|
||||
|
||||
fun validateCanCreate(
|
||||
schedule: ScheduleSummaryResponse,
|
||||
theme: ThemeSummaryResponse,
|
||||
request: PendingReservationCreateRequest
|
||||
) {
|
||||
if (schedule.status != ScheduleStatus.HOLD) {
|
||||
log.warn { "[ReservationValidator.validateCanCreate] ${schedule.status}인 일정으로 인한 예약 실패" }
|
||||
throw ReservationException(ReservationErrorCode.SCHEDULE_NOT_HOLD)
|
||||
}
|
||||
|
||||
if (theme.minParticipants > request.participantCount) {
|
||||
log.info { "[ReservationValidator.validateCanCreate] 최소 인원 미달로 인한 예약 실패: minParticipants=${theme.minParticipants}, participantCount=${request.participantCount}" }
|
||||
throw ReservationException(ReservationErrorCode.INVALID_PARTICIPANT_COUNT)
|
||||
}
|
||||
|
||||
if (theme.maxParticipants < request.participantCount) {
|
||||
log.info { "[ReservationValidator.validateCanCreate] 최대 인원 초과로 인한 예약 실패: minParticipants=${theme.minParticipants}, participantCount=${request.participantCount}" }
|
||||
throw ReservationException(ReservationErrorCode.INVALID_PARTICIPANT_COUNT)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11,5 +11,7 @@ enum class ReservationErrorCode(
|
||||
RESERVATION_NOT_FOUND(HttpStatus.NOT_FOUND, "R001", "예약을 찾을 수 없어요."),
|
||||
NO_PERMISSION_TO_CANCEL_RESERVATION(HttpStatus.FORBIDDEN, "R002", "예약을 취소할 수 있는 권한이 없어요."),
|
||||
INVALID_SEARCH_DATE_RANGE(HttpStatus.BAD_REQUEST, "R003", "종료 날짜는 시작 날짜 이후여야 해요."),
|
||||
SCHEDULE_NOT_HOLD(HttpStatus.BAD_REQUEST, "R004", "이미 예약되었거나 예약이 불가능한 일정이에요."),
|
||||
INVALID_PARTICIPANT_COUNT(HttpStatus.BAD_REQUEST, "R005", "참여 가능 인원 수를 확인해주세요.")
|
||||
;
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ class ReservationController(
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
}
|
||||
|
||||
@PatchMapping("/reservations/{id}/confirm")
|
||||
@PostMapping("/reservations/{id}/confirm")
|
||||
override fun confirmReservation(
|
||||
@PathVariable("id") id: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||
@ -41,7 +41,7 @@ class ReservationController(
|
||||
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||
reservationService.cancelReservation(memberId, reservationId, request)
|
||||
|
||||
return ResponseEntity.noContent().build()
|
||||
return ResponseEntity.ok().body(CommonApiResponse())
|
||||
}
|
||||
|
||||
@GetMapping("/reservations/summary")
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package roomescape.reservation.web
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty
|
||||
import roomescape.member.web.MemberSummaryRetrieveResponse
|
||||
import roomescape.payment.web.PaymentRetrieveResponse
|
||||
import roomescape.reservation.infrastructure.persistence.ReservationEntity
|
||||
@ -10,7 +11,9 @@ import java.time.LocalTime
|
||||
|
||||
data class PendingReservationCreateRequest(
|
||||
val scheduleId: Long,
|
||||
@NotEmpty
|
||||
val reserverName: String,
|
||||
@NotEmpty
|
||||
val reserverContact: String,
|
||||
val participantCount: Short,
|
||||
val requirement: String
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user