diff --git a/src/main/kotlin/roomescape/reservation/business/ReservationService.kt b/src/main/kotlin/roomescape/reservation/business/ReservationService.kt index 7e8f5f94..b7a17aaa 100644 --- a/src/main/kotlin/roomescape/reservation/business/ReservationService.kt +++ b/src/main/kotlin/roomescape/reservation/business/ReservationService.kt @@ -2,18 +2,19 @@ package roomescape.reservation.business import org.springframework.data.jpa.domain.Specification import org.springframework.data.repository.findByIdOrNull -import org.springframework.http.HttpStatus import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.common.exception.ErrorType -import roomescape.common.exception.RoomescapeException import roomescape.member.business.MemberService +import roomescape.member.infrastructure.persistence.MemberEntity +import roomescape.reservation.exception.ReservationErrorCode +import roomescape.reservation.exception.ReservationException import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationRepository import roomescape.reservation.infrastructure.persistence.ReservationSearchSpecification import roomescape.reservation.infrastructure.persistence.ReservationStatus import roomescape.reservation.web.* import roomescape.theme.business.ThemeService +import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.time.business.TimeService import roomescape.time.infrastructure.persistence.TimeEntity import java.time.LocalDate @@ -34,7 +35,6 @@ class ReservationService( .confirmed() .build() - return ReservationRetrieveListResponse(findAllReservationByStatus(spec)) } @@ -56,17 +56,18 @@ class ReservationService( reservationRepository.deleteById(reservationId) } - fun addReservation(request: ReservationCreateWithPaymentRequest, memberId: Long): ReservationEntity { - validateIsReservationExist(request.themeId, request.timeId, request.date) - return getReservationForSave( - request.timeId, - request.themeId, - request.date, - memberId, - ReservationStatus.CONFIRMED - ).also { - reservationRepository.save(it) - } + fun createConfirmedReservation( + request: ReservationCreateWithPaymentRequest, + memberId: Long + ): ReservationEntity { + val themeId = request.themeId + val timeId = request.timeId + val date: LocalDate = request.date + validateIsReservationExist(themeId, timeId, date) + + val reservation: ReservationEntity = createEntity(timeId, themeId, date, memberId, ReservationStatus.CONFIRMED) + + return reservationRepository.save(reservation) } fun createReservationByAdmin(request: AdminReservationCreateRequest): ReservationRetrieveResponse { @@ -98,12 +99,12 @@ class ReservationService( date: LocalDate, memberId: Long, status: ReservationStatus - ): ReservationRetrieveResponse = getReservationForSave(timeId, themeId, date, memberId, status) + ): ReservationRetrieveResponse = createEntity(timeId, themeId, date, memberId, status) .also { reservationRepository.save(it) }.toRetrieveResponse() - private fun validateMemberAlreadyReserve(themeId: Long?, timeId: Long?, date: LocalDate?, memberId: Long?) { + private fun validateMemberAlreadyReserve(themeId: Long, timeId: Long, date: LocalDate, memberId: Long) { val spec: Specification = ReservationSearchSpecification() .sameMemberId(memberId) .sameThemeId(themeId) @@ -112,7 +113,7 @@ class ReservationService( .build() if (reservationRepository.exists(spec)) { - throw RoomescapeException(ErrorType.HAS_RESERVATION_OR_WAITING, HttpStatus.BAD_REQUEST) + throw ReservationException(ReservationErrorCode.ALREADY_RESERVE) } } @@ -125,7 +126,7 @@ class ReservationService( .build() if (reservationRepository.exists(spec)) { - throw RoomescapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT) + throw ReservationException(ReservationErrorCode.RESERVATION_DUPLICATED) } } @@ -137,24 +138,20 @@ class ReservationService( val request = LocalDateTime.of(requestDate, requestTime.startAt) if (request.isBefore(now)) { - throw RoomescapeException( - ErrorType.RESERVATION_PERIOD_IN_PAST, - "[now: $now | request: $request]", - HttpStatus.BAD_REQUEST - ) + throw ReservationException(ReservationErrorCode.PAST_REQUEST_DATETIME) } } - private fun getReservationForSave( + private fun createEntity( timeId: Long, themeId: Long, date: LocalDate, memberId: Long, status: ReservationStatus ): ReservationEntity { - val time = timeService.findById(timeId) - val theme = themeService.findById(themeId) - val member = memberService.findById(memberId) + val time: TimeEntity = timeService.findById(timeId) + val theme: ThemeEntity = themeService.findById(themeId) + val member: MemberEntity = memberService.findById(memberId) validateDateAndTime(date, time) @@ -191,58 +188,54 @@ class ReservationService( return } if (startFrom.isAfter(endAt)) { - throw RoomescapeException( - ErrorType.INVALID_DATE_RANGE, - "[startFrom: $startFrom, endAt: $endAt", HttpStatus.BAD_REQUEST - ) + throw ReservationException(ReservationErrorCode.INVALID_SEARCH_DATE_RANGE) } } @Transactional(readOnly = true) fun findReservationsByMemberId(memberId: Long): MyReservationRetrieveListResponse { - return MyReservationRetrieveListResponse(reservationRepository.findAllById(memberId)) + return MyReservationRetrieveListResponse(reservationRepository.findAllByMemberId(memberId)) } fun confirmWaiting(reservationId: Long, memberId: Long) { validateIsMemberAdmin(memberId) if (reservationRepository.isExistConfirmedReservation(reservationId)) { - throw RoomescapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT) + throw ReservationException(ReservationErrorCode.CONFIRMED_RESERVATION_ALREADY_EXISTS) } reservationRepository.updateStatusByReservationId(reservationId, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED) } fun deleteWaiting(reservationId: Long, memberId: Long) { - reservationRepository.findByIdOrNull(reservationId)?.takeIf { - it.isWaiting() && it.isSameMember(memberId) - }?.let { - reservationRepository.delete(it) - } ?: throw throwReservationNotFound(reservationId) + val reservation: ReservationEntity = findReservationOrThrow(reservationId) + if (!reservation.isWaiting()) { + throw ReservationException(ReservationErrorCode.ALREADY_CONFIRMED) + } + if (!reservation.isReservedBy(memberId)) { + throw ReservationException(ReservationErrorCode.NOT_RESERVATION_OWNER) + } + reservationRepository.delete(reservation) } fun rejectWaiting(reservationId: Long, memberId: Long) { validateIsMemberAdmin(memberId) - reservationRepository.findByIdOrNull(reservationId)?.takeIf { - it.isWaiting() - }?.let { - reservationRepository.delete(it) - } ?: throw throwReservationNotFound(reservationId) + val reservation: ReservationEntity = findReservationOrThrow(reservationId) + + if (!reservation.isWaiting()) { + throw ReservationException(ReservationErrorCode.ALREADY_CONFIRMED) + } + reservationRepository.delete(reservation) } private fun validateIsMemberAdmin(memberId: Long) { - memberService.findById(memberId).takeIf { - it.isAdmin() - } ?: throw RoomescapeException( - ErrorType.PERMISSION_DOES_NOT_EXIST, - "[memberId: $memberId]", - HttpStatus.FORBIDDEN - ) + val member: MemberEntity = memberService.findById(memberId) + if (member.isAdmin()) { + return + } + throw ReservationException(ReservationErrorCode.NO_PERMISSION) } - private fun throwReservationNotFound(reservationId: Long?): RoomescapeException { - return RoomescapeException( - ErrorType.RESERVATION_NOT_FOUND, - "[reservationId: $reservationId]", - HttpStatus.NOT_FOUND - ) + private fun findReservationOrThrow(reservationId: Long): ReservationEntity { + return reservationRepository.findByIdOrNull(reservationId) + ?: throw ReservationException(ReservationErrorCode.RESERVATION_NOT_FOUND) } } diff --git a/src/main/kotlin/roomescape/reservation/business/ReservationWithPaymentService.kt b/src/main/kotlin/roomescape/reservation/business/ReservationWithPaymentService.kt index 3d48e276..f8705f38 100644 --- a/src/main/kotlin/roomescape/reservation/business/ReservationWithPaymentService.kt +++ b/src/main/kotlin/roomescape/reservation/business/ReservationWithPaymentService.kt @@ -22,7 +22,7 @@ class ReservationWithPaymentService( paymentInfo: PaymentApproveResponse, memberId: Long ): ReservationRetrieveResponse { - val reservation: ReservationEntity = reservationService.addReservation(request, memberId) + val reservation: ReservationEntity = reservationService.createConfirmedReservation(request, memberId) return paymentService.createPayment(paymentInfo, reservation) .reservation diff --git a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt b/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt index 31acb5f6..6153ef28 100644 --- a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt +++ b/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt @@ -35,7 +35,7 @@ class ReservationEntity( fun isWaiting(): Boolean = reservationStatus == ReservationStatus.WAITING @JsonIgnore - fun isSameMember(memberId: Long): Boolean { + fun isReservedBy(memberId: Long): Boolean { return this.member.id == memberId } } diff --git a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt b/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt index 3dd73807..43e9cf42 100644 --- a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt +++ b/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt @@ -59,5 +59,5 @@ interface ReservationRepository ON p.reservation = r WHERE r.member.id = :memberId """) - fun findAllById(memberId: Long): List + fun findAllByMemberId(memberId: Long): List }