From 8befd457413c3a1d42636866a80aa5df1c959b53 Mon Sep 17 00:00:00 2001 From: pricelees Date: Tue, 22 Jul 2025 14:26:08 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20Time=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ReservationTime -> Time으로 접두사 수정 - DTO 네이밍 개선(-> 이후 다른 도메인에도 반영 예정) --- .../roomescape/common/exception/ErrorType.kt | 2 +- .../java/roomescape/payment/web/PaymentDTO.kt | 4 +- .../business/ReservationService.kt | 14 ++-- .../business/ReservationTimeService.kt | 74 ------------------- .../reservation/business/TimeService.kt | 74 +++++++++++++++++++ .../{ReservationTimeAPI.kt => TimeAPI.kt} | 24 +++--- .../persistence/ReservationEntity.kt | 8 +- .../persistence/ReservationRepository.kt | 8 +- .../ReservationSearchSpecification.kt | 2 +- ...ReservationTimeEntity.kt => TimeEntity.kt} | 4 +- ...ionTimeRepository.kt => TimeRepository.kt} | 2 +- .../reservation/web/ReservationResponse.kt | 8 +- .../web/ReservationTimeController.kt | 51 ------------- .../reservation/web/ReservationTimeDTO.kt | 58 --------------- .../reservation/web/TimeController.kt | 51 +++++++++++++ .../roomescape/reservation/web/TimeDTO.kt | 55 ++++++++++++++ src/main/resources/data.sql | 8 +- .../resources/static/js/user-reservation.js | 6 +- .../persistence/PaymentRepositoryTest.kt | 2 +- .../business/ReservationServiteTest.kt | 14 ++-- .../ReservationWithPaymentServiceTest.kt | 4 +- ...nTimeServiceTest.kt => TimeServiceTest.kt} | 47 ++++++------ .../persistence/ReservationRepositoryTest.kt | 18 ++--- .../ReservationSearchSpecificationTest.kt | 14 ++-- ...epositoryTest.kt => TimeRepositoryTest.kt} | 12 +-- .../web/ReservationControllerTest.kt | 14 ++-- ...ontrollerTest.kt => TimeControllerTest.kt} | 60 +++++++-------- .../theme/util/TestThemeCreateUtil.kt | 8 +- src/test/java/roomescape/util/Fixtures.kt | 10 +-- 29 files changed, 321 insertions(+), 335 deletions(-) delete mode 100644 src/main/java/roomescape/reservation/business/ReservationTimeService.kt create mode 100644 src/main/java/roomescape/reservation/business/TimeService.kt rename src/main/java/roomescape/reservation/docs/{ReservationTimeAPI.kt => TimeAPI.kt} (74%) rename src/main/java/roomescape/reservation/infrastructure/persistence/{ReservationTimeEntity.kt => TimeEntity.kt} (80%) rename src/main/java/roomescape/reservation/infrastructure/persistence/{ReservationTimeRepository.kt => TimeRepository.kt} (70%) delete mode 100644 src/main/java/roomescape/reservation/web/ReservationTimeController.kt delete mode 100644 src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt create mode 100644 src/main/java/roomescape/reservation/web/TimeController.kt create mode 100644 src/main/java/roomescape/reservation/web/TimeDTO.kt rename src/test/java/roomescape/reservation/business/{ReservationTimeServiceTest.kt => TimeServiceTest.kt} (50%) rename src/test/java/roomescape/reservation/infrastructure/persistence/{ReservationTimeRepositoryTest.kt => TimeRepositoryTest.kt} (62%) rename src/test/java/roomescape/reservation/web/{ReservationTimeControllerTest.kt => TimeControllerTest.kt} (82%) diff --git a/src/main/java/roomescape/common/exception/ErrorType.kt b/src/main/java/roomescape/common/exception/ErrorType.kt index cf340e70..d002f14d 100644 --- a/src/main/java/roomescape/common/exception/ErrorType.kt +++ b/src/main/java/roomescape/common/exception/ErrorType.kt @@ -26,7 +26,7 @@ enum class ErrorType( // 404 Not Found MEMBER_NOT_FOUND("회원(Member) 정보가 존재하지 않습니다."), RESERVATION_NOT_FOUND("예약(Reservation) 정보가 존재하지 않습니다."), - RESERVATION_TIME_NOT_FOUND("예약 시간(ReservationTime) 정보가 존재하지 않습니다."), + TIME_NOT_FOUND("예약 시간(Time) 정보가 존재하지 않습니다."), THEME_NOT_FOUND("테마(Theme) 정보가 존재하지 않습니다."), PAYMENT_NOT_FOUND("결제(Payment) 정보가 존재하지 않습니다."), diff --git a/src/main/java/roomescape/payment/web/PaymentDTO.kt b/src/main/java/roomescape/payment/web/PaymentDTO.kt index 6dd2885c..6c594b5d 100644 --- a/src/main/java/roomescape/payment/web/PaymentDTO.kt +++ b/src/main/java/roomescape/payment/web/PaymentDTO.kt @@ -5,7 +5,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize import roomescape.payment.infrastructure.client.PaymentCancelResponseDeserializer import roomescape.payment.infrastructure.persistence.PaymentEntity import roomescape.reservation.web.ReservationResponse -import roomescape.reservation.web.toResponse +import roomescape.reservation.web.toCreateResponse import java.time.OffsetDateTime data class PaymentApproveRequest( @@ -51,6 +51,6 @@ fun PaymentEntity.toReservationPaymentResponse(): ReservationPaymentResponse = R orderId = this.orderId, paymentKey = this.paymentKey, totalAmount = this.totalAmount, - reservation = this.reservation.toResponse(), + reservation = this.reservation.toCreateResponse(), approvedAt = this.approvedAt ) \ No newline at end of file diff --git a/src/main/java/roomescape/reservation/business/ReservationService.kt b/src/main/java/roomescape/reservation/business/ReservationService.kt index 6db9c0a6..6004d86f 100644 --- a/src/main/java/roomescape/reservation/business/ReservationService.kt +++ b/src/main/java/roomescape/reservation/business/ReservationService.kt @@ -18,7 +18,7 @@ import java.time.LocalDateTime @Transactional class ReservationService( private val reservationRepository: ReservationRepository, - private val reservationTimeService: ReservationTimeService, + private val timeService: TimeService, private val memberService: MemberService, private val themeService: ThemeService, ) { @@ -43,7 +43,7 @@ class ReservationService( } private fun findAllReservationByStatus(spec: Specification): List { - return reservationRepository.findAll(spec).map { it.toResponse() } + return reservationRepository.findAll(spec).map { it.toCreateResponse() } } fun removeReservationById(reservationId: Long, memberId: Long) { @@ -96,7 +96,7 @@ class ReservationService( ): ReservationResponse = getReservationForSave(timeId, themeId, date, memberId, status) .also { reservationRepository.save(it) - }.toResponse() + }.toCreateResponse() private fun validateMemberAlreadyReserve(themeId: Long?, timeId: Long?, date: LocalDate?, memberId: Long?) { @@ -127,10 +127,10 @@ class ReservationService( private fun validateDateAndTime( requestDate: LocalDate, - requestReservationTime: ReservationTimeEntity + requestTime: TimeEntity ) { val now = LocalDateTime.now() - val request = LocalDateTime.of(requestDate, requestReservationTime.startAt) + val request = LocalDateTime.of(requestDate, requestTime.startAt) if (request.isBefore(now)) { throw RoomescapeException( @@ -148,7 +148,7 @@ class ReservationService( memberId: Long, status: ReservationStatus ): ReservationEntity { - val time = reservationTimeService.findTimeById(timeId) + val time = timeService.findById(timeId) val theme = themeService.findById(themeId) val member = memberService.findById(memberId) @@ -156,7 +156,7 @@ class ReservationService( return ReservationEntity( date = date, - reservationTime = time, + time = time, theme = theme, member = member, reservationStatus = status diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt deleted file mode 100644 index 5f940834..00000000 --- a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt +++ /dev/null @@ -1,74 +0,0 @@ -package roomescape.reservation.business - -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.reservation.infrastructure.persistence.ReservationEntity -import roomescape.reservation.infrastructure.persistence.ReservationRepository -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository -import roomescape.reservation.web.* -import java.time.LocalDate -import java.time.LocalTime - -@Service -class ReservationTimeService( - private val reservationTimeRepository: ReservationTimeRepository, - private val reservationRepository: ReservationRepository -) { - @Transactional(readOnly = true) - fun findTimeById(id: Long): ReservationTimeEntity = reservationTimeRepository.findByIdOrNull(id) - ?: throw RoomescapeException( - ErrorType.RESERVATION_TIME_NOT_FOUND, - "[reservationTimeId: $id]", - HttpStatus.BAD_REQUEST - ) - - - @Transactional(readOnly = true) - fun findAllTimes(): ReservationTimesResponse = reservationTimeRepository.findAll() - .toResponses() - - @Transactional - fun addTime(reservationTimeRequest: ReservationTimeRequest): ReservationTimeResponse { - val startAt: LocalTime = reservationTimeRequest.startAt - - if (reservationTimeRepository.existsByStartAt(startAt)) { - throw RoomescapeException( - ErrorType.TIME_DUPLICATED, "[startAt: $startAt]", HttpStatus.CONFLICT - ) - } - - return ReservationTimeEntity(startAt = startAt) - .also { reservationTimeRepository.save(it) } - .toResponse() - } - - @Transactional - fun removeTimeById(id: Long) { - val reservationTime: ReservationTimeEntity = findTimeById(id) - reservationRepository.findByReservationTime(reservationTime) - .also { - if (it.isNotEmpty()) { - throw RoomescapeException( - ErrorType.TIME_IS_USED_CONFLICT, "[timeId: $id]", HttpStatus.CONFLICT - ) - } - reservationTimeRepository.deleteById(id) - } - } - - @Transactional(readOnly = true) - fun findAllAvailableTimesByDateAndTheme(date: LocalDate, themeId: Long): ReservationTimeInfosResponse { - val allTimes = reservationTimeRepository.findAll() - val reservations: List = reservationRepository.findByDateAndThemeId(date, themeId) - - return ReservationTimeInfosResponse(allTimes.map { time -> - val alreadyBooked: Boolean = reservations.any { reservation -> reservation.reservationTime.id == time.id } - time.toInfoResponse(alreadyBooked) - }) - } -} diff --git a/src/main/java/roomescape/reservation/business/TimeService.kt b/src/main/java/roomescape/reservation/business/TimeService.kt new file mode 100644 index 00000000..b3b6bb9e --- /dev/null +++ b/src/main/java/roomescape/reservation/business/TimeService.kt @@ -0,0 +1,74 @@ +package roomescape.reservation.business + +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.reservation.infrastructure.persistence.ReservationEntity +import roomescape.reservation.infrastructure.persistence.ReservationRepository +import roomescape.reservation.infrastructure.persistence.TimeEntity +import roomescape.reservation.infrastructure.persistence.TimeRepository +import roomescape.reservation.web.* +import java.time.LocalDate +import java.time.LocalTime + +@Service +class TimeService( + private val timeRepository: TimeRepository, + private val reservationRepository: ReservationRepository +) { + @Transactional(readOnly = true) + fun findById(id: Long): TimeEntity = timeRepository.findByIdOrNull(id) + ?: throw RoomescapeException( + ErrorType.TIME_NOT_FOUND, + "[timeId: $id]", + HttpStatus.BAD_REQUEST + ) + + + @Transactional(readOnly = true) + fun findAll(): TimeRetrieveListResponse = timeRepository.findAll().toRetrieveListResponse() + + @Transactional + fun create(timeCreateRequest: TimeCreateRequest): TimeCreateResponse { + val startAt: LocalTime = timeCreateRequest.startAt + + if (timeRepository.existsByStartAt(startAt)) { + throw RoomescapeException( + ErrorType.TIME_DUPLICATED, "[startAt: $startAt]", HttpStatus.CONFLICT + ) + } + + return TimeEntity(startAt = startAt) + .also { timeRepository.save(it) } + .toCreateResponse() + } + + @Transactional + fun deleteById(id: Long) { + val time: TimeEntity = findById(id) + reservationRepository.findByTime(time) + .also { + if (it.isNotEmpty()) { + throw RoomescapeException( + ErrorType.TIME_IS_USED_CONFLICT, "[timeId: $id]", HttpStatus.CONFLICT + ) + } + timeRepository.deleteById(id) + } + } + + @Transactional(readOnly = true) + fun findAllWithAvailability(date: LocalDate, themeId: Long): TimeWithAvailabilityListResponse { + val allTimes = timeRepository.findAll() + val reservations: List = reservationRepository.findByDateAndThemeId(date, themeId) + + return TimeWithAvailabilityListResponse(allTimes.map { time -> + val isAvailable: Boolean = reservations.none { reservation -> reservation.time.id == time.id } + + TimeWithAvailabilityResponse(time.id!!, time.startAt, isAvailable) + }) + } +} diff --git a/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt b/src/main/java/roomescape/reservation/docs/TimeAPI.kt similarity index 74% rename from src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt rename to src/main/java/roomescape/reservation/docs/TimeAPI.kt index 3b1535e2..bbb738c3 100644 --- a/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt +++ b/src/main/java/roomescape/reservation/docs/TimeAPI.kt @@ -12,39 +12,39 @@ import org.springframework.web.bind.annotation.RequestParam import roomescape.auth.web.support.Admin import roomescape.auth.web.support.LoginRequired import roomescape.common.dto.response.CommonApiResponse -import roomescape.reservation.web.ReservationTimeInfosResponse -import roomescape.reservation.web.ReservationTimeRequest -import roomescape.reservation.web.ReservationTimeResponse -import roomescape.reservation.web.ReservationTimesResponse +import roomescape.reservation.web.TimeWithAvailabilityListResponse +import roomescape.reservation.web.TimeCreateRequest +import roomescape.reservation.web.TimeCreateResponse +import roomescape.reservation.web.TimeRetrieveListResponse import java.time.LocalDate @Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.") -interface ReservationTimeAPI { +interface TimeAPI { @Admin @Operation(summary = "모든 시간 조회", tags = ["관리자 로그인이 필요한 API"]) @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) - fun getAllTimes(): ResponseEntity> + fun findAll(): ResponseEntity> @Admin @Operation(summary = "시간 추가", tags = ["관리자 로그인이 필요한 API"]) @ApiResponses(ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true)) - fun saveTime( - @Valid @RequestBody reservationTimeRequest: ReservationTimeRequest, - ): ResponseEntity> + fun create( + @Valid @RequestBody timeCreateRequest: TimeCreateRequest, + ): ResponseEntity> @Admin @Operation(summary = "시간 삭제", tags = ["관리자 로그인이 필요한 API"]) @ApiResponses(ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true)) - fun removeTime( + fun deleteById( @PathVariable id: Long ): ResponseEntity> @LoginRequired @Operation(summary = "예약 가능 여부를 포함한 모든 시간 조회", tags = ["로그인이 필요한 API"]) @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) - fun findAllAvailableReservationTimes( + fun findAllWithAvailability( @RequestParam date: LocalDate, @RequestParam themeId: Long - ): ResponseEntity> + ): ResponseEntity> } diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt index f513d5c2..37dfbd84 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt @@ -18,7 +18,7 @@ class ReservationEntity( @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "time_id", nullable = false) - var reservationTime: ReservationTimeEntity, + var time: TimeEntity, @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "theme_id", nullable = false) @@ -40,14 +40,8 @@ class ReservationEntity( } } -@Schema(description = "예약 상태를 나타냅니다.", allowableValues = ["CONFIRMED", "CONFIRMED_PAYMENT_REQUIRED", "WAITING"]) enum class ReservationStatus { - @Schema(description = "결제가 완료된 예약") CONFIRMED, - - @Schema(description = "결제가 필요한 예약") CONFIRMED_PAYMENT_REQUIRED, - - @Schema(description = "대기 중인 예약") WAITING } diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt index 5d17d47a..5f52afe5 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt @@ -10,7 +10,7 @@ import java.time.LocalDate interface ReservationRepository : JpaRepository, JpaSpecificationExecutor { - fun findByReservationTime(reservationTime: ReservationTimeEntity): List + fun findByTime(time: TimeEntity): List fun findByDateAndThemeId(date: LocalDate, themeId: Long): List @@ -33,7 +33,7 @@ interface ReservationRepository AND EXISTS ( SELECT 1 FROM ReservationEntity r WHERE r.theme.id = r2.theme.id - AND r.reservationTime.id = r2.reservationTime.id + AND r.time.id = r2.time.id AND r.date = r2.date AND r.reservationStatus != 'WAITING' ) @@ -46,9 +46,9 @@ interface ReservationRepository r.id, t.name, r.date, - r.reservationTime.startAt, + r.time.startAt, r.reservationStatus, - (SELECT COUNT (r2) * 1L FROM ReservationEntity r2 WHERE r2.theme = r.theme AND r2.date = r.date AND r2.reservationTime = r.reservationTime AND r2.id < r.id), + (SELECT COUNT (r2) * 1L FROM ReservationEntity r2 WHERE r2.theme = r.theme AND r2.date = r.date AND r2.time = r.time AND r2.id < r.id), p.paymentKey, p.totalAmount ) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt index ca55ce2e..f42892c3 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt @@ -22,7 +22,7 @@ class ReservationSearchSpecification( fun sameTimeId(timeId: Long?): ReservationSearchSpecification = andIfNotNull(timeId?.let { Specification { root, _, cb -> - cb.equal(root.get("reservationTime").get("id"), timeId) + cb.equal(root.get("time").get("id"), timeId) } }) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeEntity.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/TimeEntity.kt similarity index 80% rename from src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeEntity.kt rename to src/main/java/roomescape/reservation/infrastructure/persistence/TimeEntity.kt index 73479a7b..38f1f361 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeEntity.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/TimeEntity.kt @@ -4,8 +4,8 @@ import jakarta.persistence.* import java.time.LocalTime @Entity -@Table(name = "reservation_time") -class ReservationTimeEntity( +@Table(name = "times") +class TimeEntity( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/TimeRepository.kt similarity index 70% rename from src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt rename to src/main/java/roomescape/reservation/infrastructure/persistence/TimeRepository.kt index d4a03bcd..df798889 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/TimeRepository.kt @@ -3,6 +3,6 @@ package roomescape.reservation.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository import java.time.LocalTime -interface ReservationTimeRepository : JpaRepository { +interface TimeRepository : JpaRepository { fun existsByStartAt(startAt: LocalTime): Boolean } diff --git a/src/main/java/roomescape/reservation/web/ReservationResponse.kt b/src/main/java/roomescape/reservation/web/ReservationResponse.kt index 8e370416..ce9db672 100644 --- a/src/main/java/roomescape/reservation/web/ReservationResponse.kt +++ b/src/main/java/roomescape/reservation/web/ReservationResponse.kt @@ -46,7 +46,7 @@ data class MyReservationsResponse( @Schema(name = "예약 정보", description = "예약 저장 및 조회 응답에 사용됩니다.") data class ReservationResponse( - + @field:Schema(description = "예약 번호. 예약을 식별할 때 사용합니다.") val id: Long, @@ -59,7 +59,7 @@ data class ReservationResponse( @field:Schema(description = "예약 시간 정보") @field:JsonProperty("time") - val time: ReservationTimeResponse, + val time: TimeCreateResponse, @field:Schema(description = "예약한 테마 정보") @field:JsonProperty("theme") @@ -69,11 +69,11 @@ data class ReservationResponse( val status: ReservationStatus ) -fun ReservationEntity.toResponse(): ReservationResponse = ReservationResponse( +fun ReservationEntity.toCreateResponse(): ReservationResponse = ReservationResponse( id = this.id!!, date = this.date, member = this.member.toResponse(), - time = this.reservationTime.toResponse(), + time = this.time.toCreateResponse(), theme = this.theme.toResponse(), status = this.reservationStatus ) diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeController.kt b/src/main/java/roomescape/reservation/web/ReservationTimeController.kt deleted file mode 100644 index 6fb0147e..00000000 --- a/src/main/java/roomescape/reservation/web/ReservationTimeController.kt +++ /dev/null @@ -1,51 +0,0 @@ -package roomescape.reservation.web - -import jakarta.validation.Valid -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* -import roomescape.common.dto.response.CommonApiResponse -import roomescape.reservation.business.ReservationTimeService -import roomescape.reservation.docs.ReservationTimeAPI -import java.net.URI -import java.time.LocalDate - -@RestController -class ReservationTimeController( - private val reservationTimeService: ReservationTimeService -) : ReservationTimeAPI { - - @GetMapping("/times") - override fun getAllTimes(): ResponseEntity> { - val response: ReservationTimesResponse = reservationTimeService.findAllTimes() - - return ResponseEntity.ok(CommonApiResponse(response)) - } - - @PostMapping("/times") - override fun saveTime( - @Valid @RequestBody reservationTimeRequest: ReservationTimeRequest, - ): ResponseEntity> { - val response: ReservationTimeResponse = reservationTimeService.addTime(reservationTimeRequest) - - return ResponseEntity - .created(URI.create("/times/${response.id}")) - .body(CommonApiResponse(response)) - } - - @DeleteMapping("/times/{id}") - override fun removeTime(@PathVariable id: Long): ResponseEntity> { - reservationTimeService.removeTimeById(id) - - return ResponseEntity.noContent().build() - } - - @GetMapping("/times/filter") - override fun findAllAvailableReservationTimes( - @RequestParam date: LocalDate, - @RequestParam themeId: Long - ): ResponseEntity> { - val response: ReservationTimeInfosResponse = reservationTimeService.findAllAvailableTimesByDateAndTheme(date, themeId) - - return ResponseEntity.ok(CommonApiResponse(response)) - } -} diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt b/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt deleted file mode 100644 index c98deef2..00000000 --- a/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt +++ /dev/null @@ -1,58 +0,0 @@ -package roomescape.reservation.web - -import io.swagger.v3.oas.annotations.media.Schema -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity -import java.time.LocalTime - -@Schema(name = "예약 시간 저장 요청", description = "예약 시간 저장 요청시 사용됩니다.") -data class ReservationTimeRequest( - @field:Schema(description = "예약 시간. HH:mm 형식으로 입력해야 합니다.", type = "string", example = "09:00") - val startAt: LocalTime -) - -@Schema(name = "예약 시간 정보", description = "예약 시간 추가 및 조회 응답시 사용됩니다.") -data class ReservationTimeResponse( - @field:Schema(description = "예약 시간 번호. 예약 시간을 식별할 때 사용합니다.") - val id: Long, - - @field:Schema(description = "예약 시간", type = "string", example = "09:00") - val startAt: LocalTime -) - -fun ReservationTimeEntity.toResponse(): ReservationTimeResponse = ReservationTimeResponse( - this.id!!, this.startAt -) - -@Schema(name = "예약 시간 정보 목록 응답", description = "모든 예약 시간 조회 응답시 사용됩니다.") -data class ReservationTimesResponse( - @field:Schema(description = "모든 시간 목록") - val times: List -) - -fun List.toResponses(): ReservationTimesResponse = ReservationTimesResponse( - this.map { it.toResponse() } -) - -@Schema(name = "특정 테마, 날짜에 대한 시간 정보 응답", description = "특정 날짜와 테마에 대해, 예약 가능 여부를 포함한 시간 정보를 저장합니다.") -data class ReservationTimeInfoResponse( - @field:Schema(description = "예약 시간 번호. 예약 시간을 식별할 때 사용합니다.") - val id: Long, - - @field:Schema(description = "예약 시간", type = "string", example = "09:00") - val startAt: LocalTime, - - @field:Schema(description = "이미 예약이 완료된 시간인지 여부") - val alreadyBooked: Boolean -) - -fun ReservationTimeEntity.toInfoResponse(alreadyBooked: Boolean): ReservationTimeInfoResponse = ReservationTimeInfoResponse( - id = this.id!!, - startAt = this.startAt, - alreadyBooked = alreadyBooked -) - -@Schema(name = "예약 시간 정보 목록 응답", description = "특정 테마, 날짜에 대한 모든 예약 가능 시간 정보를 저장합니다.") -data class ReservationTimeInfosResponse( - @field:Schema(description = "특정 테마, 날짜에 대한 예약 가능 여부를 포함한 시간 목록") - val times: List -) diff --git a/src/main/java/roomescape/reservation/web/TimeController.kt b/src/main/java/roomescape/reservation/web/TimeController.kt new file mode 100644 index 00000000..8c8043ca --- /dev/null +++ b/src/main/java/roomescape/reservation/web/TimeController.kt @@ -0,0 +1,51 @@ +package roomescape.reservation.web + +import jakarta.validation.Valid +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import roomescape.common.dto.response.CommonApiResponse +import roomescape.reservation.business.TimeService +import roomescape.reservation.docs.TimeAPI +import java.net.URI +import java.time.LocalDate + +@RestController +class TimeController( + private val timeService: TimeService +) : TimeAPI { + + @GetMapping("/times") + override fun findAll(): ResponseEntity> { + val response: TimeRetrieveListResponse = timeService.findAll() + + return ResponseEntity.ok(CommonApiResponse(response)) + } + + @PostMapping("/times") + override fun create( + @Valid @RequestBody timeCreateRequest: TimeCreateRequest, + ): ResponseEntity> { + val response: TimeCreateResponse = timeService.create(timeCreateRequest) + + return ResponseEntity + .created(URI.create("/times/${response.id}")) + .body(CommonApiResponse(response)) + } + + @DeleteMapping("/times/{id}") + override fun deleteById(@PathVariable id: Long): ResponseEntity> { + timeService.deleteById(id) + + return ResponseEntity.noContent().build() + } + + @GetMapping("/times/filter") + override fun findAllWithAvailability( + @RequestParam date: LocalDate, + @RequestParam themeId: Long + ): ResponseEntity> { + val response: TimeWithAvailabilityListResponse = timeService.findAllWithAvailability(date, themeId) + + return ResponseEntity.ok(CommonApiResponse(response)) + } +} diff --git a/src/main/java/roomescape/reservation/web/TimeDTO.kt b/src/main/java/roomescape/reservation/web/TimeDTO.kt new file mode 100644 index 00000000..847fd855 --- /dev/null +++ b/src/main/java/roomescape/reservation/web/TimeDTO.kt @@ -0,0 +1,55 @@ +package roomescape.reservation.web + +import io.swagger.v3.oas.annotations.media.Schema +import roomescape.reservation.infrastructure.persistence.TimeEntity +import java.time.LocalTime + +@Schema(name = "예약 시간 저장 요청", description = "예약 시간 저장 요청시 사용됩니다.") +data class TimeCreateRequest( + @field:Schema(description = "시간", type = "string", example = "09:00") + val startAt: LocalTime +) + +@Schema(name = "예약 시간 정보", description = "예약 시간 추가 및 조회 응답시 사용됩니다.") +data class TimeCreateResponse( + @field:Schema(description = "시간 식별자") + val id: Long, + + @field:Schema(description = "시간") + val startAt: LocalTime +) + +fun TimeEntity.toCreateResponse(): TimeCreateResponse = TimeCreateResponse(this.id!!, this.startAt) + +data class TimeRetrieveResponse( + @field:Schema(description = "시간 식별자.") + val id: Long, + + @field:Schema(description = "시간") + val startAt: LocalTime +) + +fun TimeEntity.toRetrieveResponse(): TimeRetrieveResponse = TimeRetrieveResponse(this.id!!, this.startAt) + +data class TimeRetrieveListResponse( + val times: List +) + +fun List.toRetrieveListResponse(): TimeRetrieveListResponse = TimeRetrieveListResponse( + this.map { it.toRetrieveResponse() } +) + +data class TimeWithAvailabilityResponse( + @field:Schema(description = "시간 식별자") + val id: Long, + + @field:Schema(description = "시간") + val startAt: LocalTime, + + @field:Schema(description = "예약 가능 여부") + val isAvailable: Boolean +) + +data class TimeWithAvailabilityListResponse( + val times: List +) diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 01d159e6..14bf37b3 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,10 +1,10 @@ -insert into reservation_time(start_at) +insert into times(start_at) values ('15:00'); -insert into reservation_time(start_at) +insert into times(start_at) values ('16:00'); -insert into reservation_time(start_at) +insert into times(start_at) values ('17:00'); -insert into reservation_time(start_at) +insert into times(start_at) values ('18:00'); insert into theme(name, description, thumbnail) diff --git a/src/main/resources/static/js/user-reservation.js b/src/main/resources/static/js/user-reservation.js index 8123dcb4..19cfcc92 100644 --- a/src/main/resources/static/js/user-reservation.js +++ b/src/main/resources/static/js/user-reservation.js @@ -124,9 +124,9 @@ function renderAvailableTimes(times) { times.data.times.forEach(time => { const startAt = time.startAt; const timeId = time.id; - const alreadyBooked = time.alreadyBooked; + const isAvailable = time.isAvailable; - const div = createSlot('time', startAt, timeId, alreadyBooked); // createSlot('time', 시작 시간, time id, 예약 여부) + const div = createSlot('time', startAt, timeId, isAvailable); // createSlot('time', 시작 시간, time id, 예약 여부) timeSlots.appendChild(div); }); } @@ -139,7 +139,7 @@ function checkDateAndThemeAndTime() { const waitButton = document.getElementById("wait-button"); if (selectedDate && selectedThemeElement && selectedTimeElement) { - if (selectedTimeElement.getAttribute('data-time-booked') === 'true') { + if (selectedTimeElement.getAttribute('data-time-booked') === 'false') { // 선택된 시간이 이미 예약된 경우 reserveButton.classList.add("disabled"); waitButton.classList.remove("disabled"); // 예약 대기 버튼 활성화 diff --git a/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt b/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt index 4b202077..34e64291 100644 --- a/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt +++ b/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt @@ -94,7 +94,7 @@ class PaymentRepositoryTest( return ReservationFixture.create().also { entityManager.persist(it.member) entityManager.persist(it.theme) - entityManager.persist(it.reservationTime) + entityManager.persist(it.time) entityManager.persist(it) entityManager.flush() diff --git a/src/test/java/roomescape/reservation/business/ReservationServiteTest.kt b/src/test/java/roomescape/reservation/business/ReservationServiteTest.kt index fa525e5c..51c78a87 100644 --- a/src/test/java/roomescape/reservation/business/ReservationServiteTest.kt +++ b/src/test/java/roomescape/reservation/business/ReservationServiteTest.kt @@ -13,19 +13,19 @@ import roomescape.reservation.infrastructure.persistence.ReservationRepository import roomescape.theme.business.ThemeService import roomescape.util.MemberFixture import roomescape.util.ReservationFixture -import roomescape.util.ReservationTimeFixture +import roomescape.util.TimeFixture import java.time.LocalDate import java.time.LocalTime class ReservationServiteTest : FunSpec({ val reservationRepository: ReservationRepository = mockk() - val reservationTimeService: ReservationTimeService = mockk() + val timeService: TimeService = mockk() val memberService: MemberService = mockk() val themeService: ThemeService = mockk() val reservationService = ReservationService( reservationRepository, - reservationTimeService, + timeService, memberService, themeService ) @@ -65,8 +65,8 @@ class ReservationServiteTest : FunSpec({ ) every { - reservationTimeService.findTimeById(any()) - } returns ReservationTimeFixture.create() + timeService.findById(any()) + } returns TimeFixture.create() shouldThrow { reservationService.addReservation(reservationRequest, 1L) @@ -81,8 +81,8 @@ class ReservationServiteTest : FunSpec({ ) every { - reservationTimeService.findTimeById(reservationRequest.timeId) - } returns ReservationTimeFixture.create( + timeService.findById(reservationRequest.timeId) + } returns TimeFixture.create( startAt = LocalTime.now().minusMinutes(1) ) diff --git a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt index e3c8b8b4..629ec324 100644 --- a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt +++ b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt @@ -32,7 +32,7 @@ class ReservationWithPaymentServiceTest : FunSpec({ val reservationEntity: ReservationEntity = ReservationFixture.create( id = 1L, date = reservationRequest.date, - reservationTime = ReservationTimeFixture.create(id = reservationRequest.timeId), + time = TimeFixture.create(id = reservationRequest.timeId), theme = ThemeFixture.create(id = reservationRequest.themeId), member = MemberFixture.create(id = memberId), status = ReservationStatus.CONFIRMED @@ -65,7 +65,7 @@ class ReservationWithPaymentServiceTest : FunSpec({ this.id shouldBe reservationEntity.id this.date shouldBe reservationEntity.date this.member.id shouldBe reservationEntity.member.id - this.time.id shouldBe reservationEntity.reservationTime.id + this.time.id shouldBe reservationEntity.time.id this.theme.id shouldBe reservationEntity.theme.id this.status shouldBe ReservationStatus.CONFIRMED } diff --git a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt b/src/test/java/roomescape/reservation/business/TimeServiceTest.kt similarity index 50% rename from src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt rename to src/test/java/roomescape/reservation/business/TimeServiceTest.kt index a1bedcfe..c25f96f7 100644 --- a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt +++ b/src/test/java/roomescape/reservation/business/TimeServiceTest.kt @@ -10,17 +10,17 @@ import org.springframework.http.HttpStatus import roomescape.common.exception.ErrorType import roomescape.common.exception.RoomescapeException import roomescape.reservation.infrastructure.persistence.ReservationRepository -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository -import roomescape.reservation.web.ReservationTimeRequest -import roomescape.util.ReservationTimeFixture +import roomescape.reservation.infrastructure.persistence.TimeRepository +import roomescape.reservation.web.TimeCreateRequest +import roomescape.util.TimeFixture import java.time.LocalTime -class ReservationTimeServiceTest : FunSpec({ - val reservationTimeRepository: ReservationTimeRepository = mockk() +class TimeServiceTest : FunSpec({ + val timeRepository: TimeRepository = mockk() val reservationRepository: ReservationRepository = mockk() - val reservationTimeService = ReservationTimeService( - reservationTimeRepository = reservationTimeRepository, + val timeService = TimeService( + timeRepository = timeRepository, reservationRepository = reservationRepository ) @@ -28,13 +28,12 @@ class ReservationTimeServiceTest : FunSpec({ test("시간을 찾을 수 없으면 400 에러를 던진다.") { val id = 1L - // Mocking the behavior of reservationTimeRepository.findByIdOrNull - every { reservationTimeRepository.findByIdOrNull(id) } returns null + every { timeRepository.findByIdOrNull(id) } returns null shouldThrow { - reservationTimeService.findTimeById(id) + timeService.findById(id) }.apply { - errorType shouldBe ErrorType.RESERVATION_TIME_NOT_FOUND + errorType shouldBe ErrorType.TIME_NOT_FOUND httpStatus shouldBe HttpStatus.BAD_REQUEST } } @@ -42,13 +41,12 @@ class ReservationTimeServiceTest : FunSpec({ context("addTime") { test("중복된 시간이 있으면 409 에러를 던진다.") { - val request = ReservationTimeRequest(startAt = LocalTime.of(10, 0)) + val request = TimeCreateRequest(startAt = LocalTime.of(10, 0)) - // Mocking the behavior of reservationTimeRepository.findByStartAt - every { reservationTimeRepository.existsByStartAt(request.startAt) } returns true + every { timeRepository.existsByStartAt(request.startAt) } returns true shouldThrow { - reservationTimeService.addTime(request) + timeService.create(request) }.apply { errorType shouldBe ErrorType.TIME_DUPLICATED httpStatus shouldBe HttpStatus.CONFLICT @@ -60,29 +58,26 @@ class ReservationTimeServiceTest : FunSpec({ test("시간을 찾을 수 없으면 400 에러를 던진다.") { val id = 1L - // Mocking the behavior of reservationTimeRepository.findByIdOrNull - every { reservationTimeRepository.findByIdOrNull(id) } returns null + every { timeRepository.findByIdOrNull(id) } returns null shouldThrow { - reservationTimeService.removeTimeById(id) + timeService.deleteById(id) }.apply { - errorType shouldBe ErrorType.RESERVATION_TIME_NOT_FOUND + errorType shouldBe ErrorType.TIME_NOT_FOUND httpStatus shouldBe HttpStatus.BAD_REQUEST } } test("예약이 있는 시간이면 409 에러를 던진다.") { val id = 1L - val reservationTime = ReservationTimeFixture.create() + val time = TimeFixture.create() - // Mocking the behavior of reservationTimeRepository.findByIdOrNull - every { reservationTimeRepository.findByIdOrNull(id) } returns reservationTime - - // Mocking the behavior of reservationRepository.findByReservationTime - every { reservationRepository.findByReservationTime(reservationTime) } returns listOf(mockk()) + every { timeRepository.findByIdOrNull(id) } returns time + + every { reservationRepository.findByTime(time) } returns listOf(mockk()) shouldThrow { - reservationTimeService.removeTimeById(id) + timeService.deleteById(id) }.apply { errorType shouldBe ErrorType.TIME_IS_USED_CONFLICT httpStatus shouldBe HttpStatus.CONFLICT diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt index 40a40923..688e9d6b 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt @@ -12,7 +12,7 @@ import roomescape.reservation.web.MyReservationResponse import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.util.PaymentFixture import roomescape.util.ReservationFixture -import roomescape.util.ReservationTimeFixture +import roomescape.util.TimeFixture import roomescape.util.ThemeFixture @DataJpaTest @@ -21,13 +21,13 @@ class ReservationRepositoryTest( val reservationRepository: ReservationRepository, ) : FunSpec() { init { - context("findByReservationTime") { - val time = ReservationTimeFixture.create() + context("findByTime") { + val time = TimeFixture.create() beforeTest { listOf( - ReservationFixture.create(reservationTime = time), - ReservationFixture.create(reservationTime = ReservationTimeFixture.create( + ReservationFixture.create(time = time), + ReservationFixture.create(time = TimeFixture.create( startAt = time.startAt.plusSeconds(1) )) ).forEach { @@ -39,9 +39,9 @@ class ReservationRepositoryTest( } test("입력된 시간과 일치하는 예약을 반환한다.") { - assertSoftly(reservationRepository.findByReservationTime(time)) { + assertSoftly(reservationRepository.findByTime(time)) { it shouldHaveSize 1 - assertSoftly(it.first().reservationTime.startAt) { result -> + assertSoftly(it.first().time.startAt) { result -> result.hour shouldBe time.startAt.hour result.minute shouldBe time.startAt.minute } @@ -68,7 +68,7 @@ class ReservationRepositoryTest( ReservationFixture.create(date = date.plusDays(1), theme = theme1), ReservationFixture.create(date = date, theme = theme2), ).forEach { - entityManager.persist(it.reservationTime) + entityManager.persist(it.time) entityManager.persist(it.member) entityManager.persist(it) } @@ -192,7 +192,7 @@ class ReservationRepositoryTest( } fun persistReservation(reservation: ReservationEntity) { - entityManager.persist(reservation.reservationTime) + entityManager.persist(reservation.time) entityManager.persist(reservation.theme) entityManager.persist(reservation.member) entityManager.persist(reservation) diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt index 34f96d9f..7d97ca3e 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt @@ -10,7 +10,7 @@ import roomescape.member.infrastructure.persistence.MemberEntity import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.util.MemberFixture import roomescape.util.ReservationFixture -import roomescape.util.ReservationTimeFixture +import roomescape.util.TimeFixture import roomescape.util.ThemeFixture import java.time.LocalDate @@ -25,7 +25,7 @@ class ReservationSearchSpecificationTest( lateinit var confirmedNotPaidYesterday: ReservationEntity lateinit var waitingTomorrow: ReservationEntity lateinit var member: MemberEntity - lateinit var reservationTime: ReservationTimeEntity + lateinit var time: TimeEntity lateinit var theme: ThemeEntity "동일한 테마의 예약을 조회한다" { @@ -56,7 +56,7 @@ class ReservationSearchSpecificationTest( "동일한 예약 시간의 예약을 조회한다" { val spec = ReservationSearchSpecification() - .sameTimeId(reservationTime.id) + .sameTimeId(time.id) .build() val results: List = reservationRepository.findAll(spec) @@ -136,7 +136,7 @@ class ReservationSearchSpecificationTest( member = MemberFixture.create().also { entityManager.persist(it) } - reservationTime = ReservationTimeFixture.create().also { + time = TimeFixture.create().also { entityManager.persist(it) } theme = ThemeFixture.create().also { @@ -144,7 +144,7 @@ class ReservationSearchSpecificationTest( } confirmedNow = ReservationFixture.create( - reservationTime = reservationTime, + time = time, member = member, theme = theme, date = LocalDate.now(), @@ -154,7 +154,7 @@ class ReservationSearchSpecificationTest( } confirmedNotPaidYesterday = ReservationFixture.create( - reservationTime = reservationTime, + time = time, member = member, theme = theme, date = LocalDate.now().minusDays(1), @@ -164,7 +164,7 @@ class ReservationSearchSpecificationTest( } waitingTomorrow = ReservationFixture.create( - reservationTime = reservationTime, + time = time, member = member, theme = theme, date = LocalDate.now().plusDays(1), diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepositoryTest.kt b/src/test/java/roomescape/reservation/infrastructure/persistence/TimeRepositoryTest.kt similarity index 62% rename from src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepositoryTest.kt rename to src/test/java/roomescape/reservation/infrastructure/persistence/TimeRepositoryTest.kt index ba7045a3..d3ef18c5 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepositoryTest.kt +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/TimeRepositoryTest.kt @@ -4,30 +4,30 @@ import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import jakarta.persistence.EntityManager import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest -import roomescape.util.ReservationTimeFixture +import roomescape.util.TimeFixture import java.time.LocalTime @DataJpaTest -class ReservationTimeRepositoryTest( +class TimeRepositoryTest( val entityManager: EntityManager, - val reservationTimeRepository: ReservationTimeRepository, + val timeRepository: TimeRepository, ) : FunSpec({ context("existsByStartAt") { val startAt = LocalTime.of(10, 0) beforeTest { - entityManager.persist(ReservationTimeFixture.create(startAt = startAt)) + entityManager.persist(TimeFixture.create(startAt = startAt)) entityManager.flush() entityManager.clear() } test("동일한 시간이 있으면 true 반환") { - reservationTimeRepository.existsByStartAt(startAt) shouldBe true + timeRepository.existsByStartAt(startAt) shouldBe true } test("동일한 시간이 없으면 false 반환") { - reservationTimeRepository.existsByStartAt(startAt.plusSeconds(1)) shouldBe false + timeRepository.existsByStartAt(startAt.plusSeconds(1)) shouldBe false } } }) diff --git a/src/test/java/roomescape/reservation/web/ReservationControllerTest.kt b/src/test/java/roomescape/reservation/web/ReservationControllerTest.kt index f4fbfffe..e37a8245 100644 --- a/src/test/java/roomescape/reservation/web/ReservationControllerTest.kt +++ b/src/test/java/roomescape/reservation/web/ReservationControllerTest.kt @@ -28,7 +28,7 @@ import roomescape.payment.infrastructure.client.TossPaymentClient import roomescape.payment.infrastructure.persistence.PaymentEntity import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity +import roomescape.reservation.infrastructure.persistence.TimeEntity import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.util.* import java.time.LocalDate @@ -503,7 +503,7 @@ class ReservationControllerTest( val reservation = ReservationFixture.create( date = reservationRequest.date, theme = entityManager.find(ThemeEntity::class.java, reservationRequest.themeId), - reservationTime = entityManager.find(ReservationTimeEntity::class.java, reservationRequest.timeId), + time = entityManager.find(TimeEntity::class.java, reservationRequest.timeId), member = member, status = ReservationStatus.WAITING ) @@ -675,7 +675,7 @@ class ReservationControllerTest( return ReservationFixture.create( date = date, theme = ThemeFixture.create(name = themeName), - reservationTime = ReservationTimeFixture.create(startAt = time), + time = TimeFixture.create(startAt = time), member = member, status = status ).also { it -> @@ -683,7 +683,7 @@ class ReservationControllerTest( if (member.id == null) { entityManager.persist(member) } - entityManager.persist(it.reservationTime) + entityManager.persist(it.time) entityManager.persist(it.theme) entityManager.persist(it) entityManager.flush() @@ -710,14 +710,14 @@ class ReservationControllerTest( transactionTemplate.executeWithoutResult { repeat(10) { index -> val theme = ThemeFixture.create(name = "theme$index") - val time = ReservationTimeFixture.create(startAt = LocalTime.now().plusMinutes(index.toLong())) + val time = TimeFixture.create(startAt = LocalTime.now().plusMinutes(index.toLong())) entityManager.persist(theme) entityManager.persist(time) val reservation = ReservationFixture.create( date = LocalDate.now().plusDays(index.toLong()), theme = theme, - reservationTime = time, + time = time, member = members[index % members.size], status = ReservationStatus.CONFIRMED ) @@ -733,7 +733,7 @@ class ReservationControllerTest( fun createRequest( theme: ThemeEntity = ThemeFixture.create(), - time: ReservationTimeEntity = ReservationTimeFixture.create(), + time: TimeEntity = TimeFixture.create(), ): ReservationRequest { lateinit var reservationRequest: ReservationRequest diff --git a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.kt b/src/test/java/roomescape/reservation/web/TimeControllerTest.kt similarity index 82% rename from src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.kt rename to src/test/java/roomescape/reservation/web/TimeControllerTest.kt index 71b4040a..57f6cfbc 100644 --- a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.kt +++ b/src/test/java/roomescape/reservation/web/TimeControllerTest.kt @@ -13,28 +13,28 @@ import org.springframework.http.MediaType import org.springframework.test.web.servlet.MockMvc import roomescape.common.config.JacksonConfig import roomescape.common.exception.ErrorType -import roomescape.reservation.business.ReservationTimeService +import roomescape.reservation.business.TimeService import roomescape.reservation.infrastructure.persistence.ReservationRepository -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository +import roomescape.reservation.infrastructure.persistence.TimeEntity +import roomescape.reservation.infrastructure.persistence.TimeRepository import roomescape.util.ReservationFixture -import roomescape.util.ReservationTimeFixture +import roomescape.util.TimeFixture import roomescape.util.RoomescapeApiTest import roomescape.util.ThemeFixture import java.time.LocalDate import java.time.LocalTime -@WebMvcTest(ReservationTimeController::class) +@WebMvcTest(TimeController::class) @Import(JacksonConfig::class) -class ReservationTimeControllerTest( +class TimeControllerTest( val mockMvc: MockMvc, ) : RoomescapeApiTest() { @SpykBean - private lateinit var reservationTimeService: ReservationTimeService + private lateinit var timeService: TimeService @MockkBean - private lateinit var reservationTimeRepository: ReservationTimeRepository + private lateinit var timeRepository: TimeRepository @MockkBean private lateinit var reservationRepository: ReservationRepository @@ -50,10 +50,10 @@ class ReservationTimeControllerTest( Then("정상 응답") { every { - reservationTimeRepository.findAll() + timeRepository.findAll() } returns listOf( - ReservationTimeFixture.create(id = 1L), - ReservationTimeFixture.create(id = 2L) + TimeFixture.create(id = 1L), + TimeFixture.create(id = 2L) ) runGetTest( @@ -95,7 +95,7 @@ class ReservationTimeControllerTest( loginAsAdmin() } val time = LocalTime.of(10, 0) - val request = ReservationTimeRequest(startAt = time) + val request = TimeCreateRequest(startAt = time) Then("시간 형식이 HH:mm이 아니거나, 범위를 벗어나면 400 응답") { listOf( @@ -115,8 +115,8 @@ class ReservationTimeControllerTest( Then("정상 응답") { every { - reservationTimeService.addTime(request) - } returns ReservationTimeResponse(id = 1, startAt = time) + timeService.create(request) + } returns TimeCreateResponse(id = 1, startAt = time) runPostTest( mockMvc = mockMvc, @@ -135,7 +135,7 @@ class ReservationTimeControllerTest( Then("동일한 시간이 존재하면 409 응답") { every { - reservationTimeRepository.existsByStartAt(time) + timeRepository.existsByStartAt(time) } returns true runPostTest( @@ -160,7 +160,7 @@ class ReservationTimeControllerTest( runPostTest( mockMvc = mockMvc, endpoint = endpoint, - body = ReservationTimeFixture.create(), + body = TimeFixture.create(), log = true ) { status { is3xxRedirection() } @@ -180,7 +180,7 @@ class ReservationTimeControllerTest( Then("정상 응답") { every { - reservationTimeService.removeTimeById(1L) + timeService.deleteById(1L) } returns Unit runDeleteTest( @@ -195,7 +195,7 @@ class ReservationTimeControllerTest( Then("없는 시간을 조회하면 400 응답") { val id = 1L every { - reservationTimeRepository.findByIdOrNull(id) + timeRepository.findByIdOrNull(id) } returns null runDeleteTest( @@ -206,7 +206,7 @@ class ReservationTimeControllerTest( status { isBadRequest() } content { contentType(MediaType.APPLICATION_JSON) - jsonPath("$.errorType") { value(ErrorType.RESERVATION_TIME_NOT_FOUND.name) } + jsonPath("$.errorType") { value(ErrorType.TIME_NOT_FOUND.name) } } } } @@ -214,11 +214,11 @@ class ReservationTimeControllerTest( Then("예약이 있는 시간을 삭제하면 409 응답") { val id = 1L every { - reservationTimeRepository.findByIdOrNull(id) - } returns ReservationTimeFixture.create(id = id) + timeRepository.findByIdOrNull(id) + } returns TimeFixture.create(id = id) every { - reservationRepository.findByReservationTime(any()) + reservationRepository.findByTime(any()) } returns listOf(ReservationFixture.create()) runDeleteTest( @@ -258,13 +258,13 @@ class ReservationTimeControllerTest( val themeId = 1L When("저장된 예약 시간이 있으면") { - val times: List = listOf( - ReservationTimeFixture.create(id = 1L, startAt = LocalTime.of(10, 0)), - ReservationTimeFixture.create(id = 2L, startAt = LocalTime.of(11, 0)) + val times: List = listOf( + TimeFixture.create(id = 1L, startAt = LocalTime.of(10, 0)), + TimeFixture.create(id = 2L, startAt = LocalTime.of(11, 0)) ) every { - reservationTimeRepository.findAll() + timeRepository.findAll() } returns times Then("그 시간과, 해당 날짜와 테마에 대한 예약 여부가 담긴 목록을 응답") { @@ -276,7 +276,7 @@ class ReservationTimeControllerTest( id = 1L, date = date, theme = ThemeFixture.create(id = themeId), - reservationTime = times[0] + time = times[0] ) ) @@ -289,15 +289,15 @@ class ReservationTimeControllerTest( content { contentType(MediaType.APPLICATION_JSON) } - }.andReturn().readValue(ReservationTimeInfosResponse::class.java) + }.andReturn().readValue(TimeWithAvailabilityListResponse::class.java) assertSoftly(response.times) { this shouldHaveSize times.size this[0].id shouldBe times[0].id - this[0].alreadyBooked shouldBe true + this[0].isAvailable shouldBe false this[1].id shouldBe times[1].id - this[1].alreadyBooked shouldBe false + this[1].isAvailable shouldBe true } } } diff --git a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt index 0f05cdfa..7966162f 100644 --- a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt +++ b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt @@ -3,11 +3,11 @@ package roomescape.theme.util import jakarta.persistence.EntityManager import roomescape.member.infrastructure.persistence.MemberEntity import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity +import roomescape.reservation.infrastructure.persistence.TimeEntity import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.util.MemberFixture import roomescape.util.ReservationFixture -import roomescape.util.ReservationTimeFixture +import roomescape.util.TimeFixture import roomescape.util.ThemeFixture import java.time.LocalDate import java.time.LocalTime @@ -23,7 +23,7 @@ object TestThemeCreateUtil { val member: MemberEntity = MemberFixture.create().also { entityManager.persist(it) } for (i in 1..reservedCount) { - val time: ReservationTimeEntity = ReservationTimeFixture.create( + val time: TimeEntity = TimeFixture.create( startAt = LocalTime.now().plusMinutes(i.toLong()) ).also { entityManager.persist(it) } @@ -31,7 +31,7 @@ object TestThemeCreateUtil { date = date, theme = themeEntity, member = member, - reservationTime = time, + time = time, status = ReservationStatus.CONFIRMED ).also { entityManager.persist(it) } } diff --git a/src/test/java/roomescape/util/Fixtures.kt b/src/test/java/roomescape/util/Fixtures.kt index d337b001..0ce3a9f1 100644 --- a/src/test/java/roomescape/util/Fixtures.kt +++ b/src/test/java/roomescape/util/Fixtures.kt @@ -12,7 +12,7 @@ import roomescape.payment.web.PaymentCancelRequest import roomescape.payment.web.PaymentCancelResponse import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity +import roomescape.reservation.infrastructure.persistence.TimeEntity import roomescape.reservation.web.ReservationRequest import roomescape.reservation.web.WaitingRequest import roomescape.theme.infrastructure.persistence.ThemeEntity @@ -54,11 +54,11 @@ object MemberFixture { ) } -object ReservationTimeFixture { +object TimeFixture { fun create( id: Long? = null, startAt: LocalTime = LocalTime.now().plusHours(1), - ): ReservationTimeEntity = ReservationTimeEntity(id, startAt) + ): TimeEntity = TimeEntity(id, startAt) } object ThemeFixture { @@ -75,10 +75,10 @@ object ReservationFixture { id: Long? = null, date: LocalDate = LocalDate.now().plusWeeks(1), theme: ThemeEntity = ThemeFixture.create(), - reservationTime: ReservationTimeEntity = ReservationTimeFixture.create(), + time: TimeEntity = TimeFixture.create(), member: MemberEntity = MemberFixture.create(), status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED - ): ReservationEntity = ReservationEntity(id, date, reservationTime, theme, member, status) + ): ReservationEntity = ReservationEntity(id, date, time, theme, member, status) fun createRequest( date: LocalDate = LocalDate.now().plusWeeks(1),