From 514066adb62da7f4f5d22bb087b6f5da0dd510f4 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 01:50:31 +0900 Subject: [PATCH 01/40] =?UTF-8?q?refactor:=20Member=20->=20MemberEntity=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/auth/service/AuthService.kt | 4 +- .../auth/web/support/AuthInterceptors.kt | 4 +- .../member/business/MemberService.kt | 6 +-- .../{Member.kt => MemberEntity.kt} | 2 +- .../persistence/MemberRepository.kt | 4 +- .../java/roomescape/member/web/MemberDTO.kt | 6 +-- .../reservation/domain/Reservation.java | 12 ++--- .../service/ReservationService.java | 6 +-- .../auth/business/AuthServiceTest.kt | 4 +- .../payment/business/PaymentServiceTest.java | 8 +-- .../controller/ReservationControllerTest.java | 50 +++++++++---------- .../ReservationTimeControllerTest.java | 6 +-- .../reservation/domain/ReservationTest.java | 10 ++-- .../ReservationSearchSpecificationTest.java | 4 +- .../service/ReservationServiceTest.java | 26 +++++----- .../service/ReservationTimeServiceTest.java | 4 +- .../ReservationWithPaymentServiceTest.java | 10 ++-- .../theme/util/TestThemeCreateUtil.kt | 4 +- src/test/java/roomescape/util/Fixtures.kt | 10 ++-- .../java/roomescape/util/RoomescapeApiTest.kt | 6 +-- 20 files changed, 93 insertions(+), 93 deletions(-) rename src/main/java/roomescape/member/infrastructure/persistence/{Member.kt => MemberEntity.kt} (95%) diff --git a/src/main/java/roomescape/auth/service/AuthService.kt b/src/main/java/roomescape/auth/service/AuthService.kt index ccc9c95c..b6ee6e00 100644 --- a/src/main/java/roomescape/auth/service/AuthService.kt +++ b/src/main/java/roomescape/auth/service/AuthService.kt @@ -6,7 +6,7 @@ import roomescape.auth.web.LoginCheckResponse import roomescape.auth.web.LoginRequest import roomescape.auth.web.TokenResponse import roomescape.member.business.MemberService -import roomescape.member.infrastructure.persistence.Member +import roomescape.member.infrastructure.persistence.MemberEntity @Service class AuthService( @@ -14,7 +14,7 @@ class AuthService( private val jwtHandler: JwtHandler ) { fun login(request: LoginRequest): TokenResponse { - val member: Member = memberService.findMemberByEmailAndPassword( + val member: MemberEntity = memberService.findMemberByEmailAndPassword( request.email, request.password ) diff --git a/src/main/java/roomescape/auth/web/support/AuthInterceptors.kt b/src/main/java/roomescape/auth/web/support/AuthInterceptors.kt index 20b5b53d..42c6e958 100644 --- a/src/main/java/roomescape/auth/web/support/AuthInterceptors.kt +++ b/src/main/java/roomescape/auth/web/support/AuthInterceptors.kt @@ -10,7 +10,7 @@ import roomescape.auth.infrastructure.jwt.JwtHandler import roomescape.common.exception.ErrorType import roomescape.common.exception.RoomescapeException import roomescape.member.business.MemberService -import roomescape.member.infrastructure.persistence.Member +import roomescape.member.infrastructure.persistence.MemberEntity private fun Any.isIrrelevantWith(annotationType: Class): Boolean { if (this !is HandlerMethod) { @@ -63,7 +63,7 @@ class AdminInterceptor( return true } - val member: Member? + val member: MemberEntity? try { val token: String? = request.accessTokenCookie().value diff --git a/src/main/java/roomescape/member/business/MemberService.kt b/src/main/java/roomescape/member/business/MemberService.kt index 6dc20c7c..512f947d 100644 --- a/src/main/java/roomescape/member/business/MemberService.kt +++ b/src/main/java/roomescape/member/business/MemberService.kt @@ -6,7 +6,7 @@ import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import roomescape.common.exception.ErrorType import roomescape.common.exception.RoomescapeException -import roomescape.member.infrastructure.persistence.Member +import roomescape.member.infrastructure.persistence.MemberEntity import roomescape.member.infrastructure.persistence.MemberRepository import roomescape.member.web.MembersResponse import roomescape.member.web.toResponse @@ -22,14 +22,14 @@ class MemberService( .toList() ) - fun findById(memberId: Long): Member = memberRepository.findByIdOrNull(memberId) + fun findById(memberId: Long): MemberEntity = memberRepository.findByIdOrNull(memberId) ?: throw RoomescapeException( ErrorType.MEMBER_NOT_FOUND, String.format("[memberId: %d]", memberId), HttpStatus.BAD_REQUEST ) - fun findMemberByEmailAndPassword(email: String, password: String): Member = + fun findMemberByEmailAndPassword(email: String, password: String): MemberEntity = memberRepository.findByEmailAndPassword(email, password) ?: throw RoomescapeException( ErrorType.MEMBER_NOT_FOUND, diff --git a/src/main/java/roomescape/member/infrastructure/persistence/Member.kt b/src/main/java/roomescape/member/infrastructure/persistence/MemberEntity.kt similarity index 95% rename from src/main/java/roomescape/member/infrastructure/persistence/Member.kt rename to src/main/java/roomescape/member/infrastructure/persistence/MemberEntity.kt index 1e63e863..3014948d 100644 --- a/src/main/java/roomescape/member/infrastructure/persistence/Member.kt +++ b/src/main/java/roomescape/member/infrastructure/persistence/MemberEntity.kt @@ -3,7 +3,7 @@ package roomescape.member.infrastructure.persistence import jakarta.persistence.* @Entity -class Member( +class MemberEntity( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, diff --git a/src/main/java/roomescape/member/infrastructure/persistence/MemberRepository.kt b/src/main/java/roomescape/member/infrastructure/persistence/MemberRepository.kt index c08e3920..667d9df8 100644 --- a/src/main/java/roomescape/member/infrastructure/persistence/MemberRepository.kt +++ b/src/main/java/roomescape/member/infrastructure/persistence/MemberRepository.kt @@ -2,6 +2,6 @@ package roomescape.member.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository -interface MemberRepository : JpaRepository { - fun findByEmailAndPassword(email: String, password: String): Member? +interface MemberRepository : JpaRepository { + fun findByEmailAndPassword(email: String, password: String): MemberEntity? } diff --git a/src/main/java/roomescape/member/web/MemberDTO.kt b/src/main/java/roomescape/member/web/MemberDTO.kt index e20bac35..8b8b4e32 100644 --- a/src/main/java/roomescape/member/web/MemberDTO.kt +++ b/src/main/java/roomescape/member/web/MemberDTO.kt @@ -1,9 +1,9 @@ package roomescape.member.web import io.swagger.v3.oas.annotations.media.Schema -import roomescape.member.infrastructure.persistence.Member +import roomescape.member.infrastructure.persistence.MemberEntity -fun Member.toResponse(): MemberResponse = MemberResponse( +fun MemberEntity.toResponse(): MemberResponse = MemberResponse( id = id!!, name = name ) @@ -18,7 +18,7 @@ data class MemberResponse( ) { companion object { @JvmStatic - fun fromEntity(member: Member): MemberResponse { + fun fromEntity(member: MemberEntity): MemberResponse { return MemberResponse(member.id!!, member.name) } } diff --git a/src/main/java/roomescape/reservation/domain/Reservation.java b/src/main/java/roomescape/reservation/domain/Reservation.java index 6509596f..f8dc6858 100644 --- a/src/main/java/roomescape/reservation/domain/Reservation.java +++ b/src/main/java/roomescape/reservation/domain/Reservation.java @@ -17,7 +17,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import roomescape.common.exception.ErrorType; import roomescape.common.exception.RoomescapeException; -import roomescape.member.infrastructure.persistence.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.theme.infrastructure.persistence.ThemeEntity; @Entity @@ -39,7 +39,7 @@ public class Reservation { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", nullable = false) - private Member member; + private MemberEntity member; @Enumerated(value = EnumType.STRING) private ReservationStatus reservationStatus; @@ -51,7 +51,7 @@ public class Reservation { LocalDate date, ReservationTime reservationTime, ThemeEntity theme, - Member member, + MemberEntity member, ReservationStatus status ) { this(null, date, reservationTime, theme, member, status); @@ -62,7 +62,7 @@ public class Reservation { LocalDate date, ReservationTime reservationTime, ThemeEntity theme, - Member member, + MemberEntity member, ReservationStatus status ) { validateIsNull(date, reservationTime, theme, member, status); @@ -74,7 +74,7 @@ public class Reservation { this.reservationStatus = status; } - private void validateIsNull(LocalDate date, ReservationTime reservationTime, ThemeEntity theme, Member member, + private void validateIsNull(LocalDate date, ReservationTime reservationTime, ThemeEntity theme, MemberEntity member, ReservationStatus reservationStatus) { if (date == null || reservationTime == null || theme == null || member == null || reservationStatus == null) { throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[values: %s]", this), @@ -102,7 +102,7 @@ public class Reservation { return theme; } - public Member getMember() { + public MemberEntity getMember() { return member; } diff --git a/src/main/java/roomescape/reservation/service/ReservationService.java b/src/main/java/roomescape/reservation/service/ReservationService.java index 0a3098ac..4c80e19b 100644 --- a/src/main/java/roomescape/reservation/service/ReservationService.java +++ b/src/main/java/roomescape/reservation/service/ReservationService.java @@ -12,7 +12,7 @@ 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.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.reservation.domain.Reservation; import roomescape.reservation.domain.ReservationStatus; import roomescape.reservation.domain.ReservationTime; @@ -147,7 +147,7 @@ public class ReservationService { ReservationStatus status) { ReservationTime time = reservationTimeService.findTimeById(timeId); ThemeEntity theme = themeService.findThemeById(themeId); - Member member = memberService.findById(memberId); + MemberEntity member = memberService.findById(memberId); validateDateAndTime(date, time); return new Reservation(date, time, theme, member, status); @@ -213,7 +213,7 @@ public class ReservationService { } private void validateIsMemberAdmin(Long memberId) { - Member member = memberService.findById(memberId); + MemberEntity member = memberService.findById(memberId); if (member.isAdmin()) { return; } diff --git a/src/test/java/roomescape/auth/business/AuthServiceTest.kt b/src/test/java/roomescape/auth/business/AuthServiceTest.kt index 31cdef51..f819ff3b 100644 --- a/src/test/java/roomescape/auth/business/AuthServiceTest.kt +++ b/src/test/java/roomescape/auth/business/AuthServiceTest.kt @@ -10,7 +10,7 @@ import org.springframework.data.repository.findByIdOrNull import roomescape.util.JwtFixture import roomescape.util.MemberFixture import roomescape.member.business.MemberService -import roomescape.member.infrastructure.persistence.Member +import roomescape.member.infrastructure.persistence.MemberEntity import roomescape.member.infrastructure.persistence.MemberRepository import roomescape.auth.infrastructure.jwt.JwtHandler import roomescape.auth.service.AuthService @@ -24,7 +24,7 @@ class AuthServiceTest : BehaviorSpec({ val jwtHandler: JwtHandler = JwtFixture.create() val authService = AuthService(memberService, jwtHandler) - val user: Member = MemberFixture.user() + val user: MemberEntity = MemberFixture.user() Given("로그인 요청을 받으면") { When("이메일과 비밀번호로 회원을 찾고") { diff --git a/src/test/java/roomescape/payment/business/PaymentServiceTest.java b/src/test/java/roomescape/payment/business/PaymentServiceTest.java index 57f057a8..3770c56f 100644 --- a/src/test/java/roomescape/payment/business/PaymentServiceTest.java +++ b/src/test/java/roomescape/payment/business/PaymentServiceTest.java @@ -14,7 +14,7 @@ import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql.ExecutionPhase; import roomescape.common.exception.RoomescapeException; -import roomescape.member.infrastructure.persistence.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity; @@ -56,7 +56,7 @@ class PaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - Member member = memberRepository.save(new Member(null, "member", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); @@ -78,7 +78,7 @@ class PaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - Member member = memberRepository.save(new Member(null, "member", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); @@ -115,7 +115,7 @@ class PaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - Member member = memberRepository.save(new Member(null, "member", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); diff --git a/src/test/java/roomescape/reservation/controller/ReservationControllerTest.java b/src/test/java/roomescape/reservation/controller/ReservationControllerTest.java index 5a888a55..726f164b 100644 --- a/src/test/java/roomescape/reservation/controller/ReservationControllerTest.java +++ b/src/test/java/roomescape/reservation/controller/ReservationControllerTest.java @@ -31,7 +31,7 @@ import org.springframework.test.context.jdbc.Sql.ExecutionPhase; import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.restassured.http.Header; -import roomescape.member.infrastructure.persistence.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.payment.infrastructure.client.TossPaymentClient; @@ -120,12 +120,12 @@ public class ReservationControllerTest { @DisplayName("대기중인 예약을 취소한다.") void cancelWaiting() { // given - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessTokenCookie = getAccessTokenCookieByLogin("email@email.com", "password"); ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member1 = memberRepository.save(new Member(null, "name1", "email1r@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); // when reservationRepository.save(new Reservation(LocalDate.now().plusDays(1), reservationTime, theme, member1, @@ -147,14 +147,14 @@ public class ReservationControllerTest { @DisplayName("회원은 자신이 아닌 다른 회원의 예약을 취소할 수 없다.") void cantCancelOtherMembersWaiting() { // given - Member confirmedMember = memberRepository.save( - new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity confirmedMember = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessTokenCookie = getAccessTokenCookieByLogin("email@email.com", "password"); ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member waitingMember = memberRepository.save( - new Member(null, "name1", "email1r@email.com", "password", Role.MEMBER)); + MemberEntity waitingMember = memberRepository.save( + new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); // when reservationRepository.save(new Reservation(LocalDate.now().plusDays(1), reservationTime, theme, confirmedMember, @@ -180,7 +180,7 @@ public class ReservationControllerTest { ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); // when reservationRepository.save( @@ -204,7 +204,7 @@ public class ReservationControllerTest { @DisplayName("예약 취소는 관리자만 할 수 있다.") void canRemoveMyReservation() { // given - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessTokenCookie = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); @@ -229,10 +229,10 @@ public class ReservationControllerTest { ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member confirmedMember = memberRepository.save( - new Member(null, "name1", "email@email.com", "password", Role.MEMBER)); - Member waitingMember = memberRepository.save( - new Member(null, "name1", "email1@email.com", "password", Role.MEMBER)); + MemberEntity confirmedMember = memberRepository.save( + new MemberEntity(null, "name1", "email@email.com", "password", Role.MEMBER)); + MemberEntity waitingMember = memberRepository.save( + new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); reservationRepository.save( new Reservation(LocalDate.now(), reservationTime, theme, confirmedMember, ReservationStatus.CONFIRMED)); @@ -252,13 +252,13 @@ public class ReservationControllerTest { @DisplayName("본인의 예약이 아니더라도 관리자 권한이 있으면 예약 정보를 삭제할 수 있다.") void readReservationsSizeAfterPostAndDelete() { // given - Member member = memberRepository.save(new Member(null, "name", "admin@admin.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "admin@admin.com", "password", Role.ADMIN)); String accessTokenCookie = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member anotherMember = memberRepository.save( - new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity anotherMember = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); Reservation reservation = reservationRepository.save( new Reservation(LocalDate.now(), reservationTime, theme, anotherMember, ReservationStatus.CONFIRMED)); @@ -342,7 +342,7 @@ public class ReservationControllerTest { ReservationTime time1 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(18, 30))); ReservationTime time2 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(19, 30))); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.ADMIN)); String accessToken = getAccessTokenCookieByLogin("email@email.com", "password"); // when : 예약은 2개, 예약 대기는 1개 조회되어야 한다. @@ -372,7 +372,7 @@ public class ReservationControllerTest { // when Reservation saved = reservationRepository.save(new Reservation(date, time, theme, - memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)), + memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); // then @@ -392,7 +392,7 @@ public class ReservationControllerTest { LocalDate date = LocalDate.now().plusDays(1); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); ReservationTime time = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); Reservation saved = reservationRepository.save( new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); @@ -422,7 +422,7 @@ public class ReservationControllerTest { LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessToken = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); // when : 이전 날짜의 예약을 추가하여 결제 승인 이후 DB 저장 과정에서 예외를 발생시킨다. @@ -515,8 +515,8 @@ public class ReservationControllerTest { LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); - Member member1 = memberRepository.save(new Member(null, "name1", "email1@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); String accessToken = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); reservationRepository.save(new Reservation(date, time, theme, member1, ReservationStatus.CONFIRMED)); @@ -541,7 +541,7 @@ public class ReservationControllerTest { LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); Reservation waiting = reservationRepository.save( @@ -586,7 +586,7 @@ public class ReservationControllerTest { LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String adminAccessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); @@ -602,7 +602,7 @@ public class ReservationControllerTest { } private String getAdminAccessTokenCookieByLogin(final String email, final String password) { - memberRepository.save(new Member(null, "이름", email, password, Role.ADMIN)); + memberRepository.save(new MemberEntity(null, "이름", email, password, Role.ADMIN)); Map loginParams = Map.of( "email", email, diff --git a/src/test/java/roomescape/reservation/controller/ReservationTimeControllerTest.java b/src/test/java/roomescape/reservation/controller/ReservationTimeControllerTest.java index baaa53a3..f3adec83 100644 --- a/src/test/java/roomescape/reservation/controller/ReservationTimeControllerTest.java +++ b/src/test/java/roomescape/reservation/controller/ReservationTimeControllerTest.java @@ -21,7 +21,7 @@ import org.springframework.test.context.jdbc.Sql.ExecutionPhase; import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.restassured.http.Header; -import roomescape.member.infrastructure.persistence.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.domain.Reservation; @@ -199,7 +199,7 @@ public class ReservationTimeControllerTest { } private String getAdminAccessTokenCookieByLogin(String email, String password) { - memberRepository.save(new Member(null, "이름", email, password, Role.ADMIN)); + memberRepository.save(new MemberEntity(null, "이름", email, password, Role.ADMIN)); Map loginParams = Map.of( "email", email, @@ -225,7 +225,7 @@ public class ReservationTimeControllerTest { ReservationTime reservationTime2 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); ReservationTime reservationTime3 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(18, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명1", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); reservationRepository.save( new Reservation(today.plusDays(1), reservationTime1, theme, member, ReservationStatus.CONFIRMED)); diff --git a/src/test/java/roomescape/reservation/domain/ReservationTest.java b/src/test/java/roomescape/reservation/domain/ReservationTest.java index 6f19375d..bf1bc3bd 100644 --- a/src/test/java/roomescape/reservation/domain/ReservationTest.java +++ b/src/test/java/roomescape/reservation/domain/ReservationTest.java @@ -10,7 +10,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import roomescape.member.infrastructure.persistence.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.Role; import roomescape.common.exception.RoomescapeException; import roomescape.theme.infrastructure.persistence.ThemeEntity; @@ -21,7 +21,7 @@ public class ReservationTest { @MethodSource("validateConstructorParameterBlankSource") @DisplayName("객체 생성 시, null 또는 공백이 존재하면 예외를 발생한다.") void validateConstructorParameterBlank(LocalDate date, ReservationTime reservationTime, ThemeEntity theme, - Member member) { + MemberEntity member) { // when & then Assertions.assertThatThrownBy( @@ -34,17 +34,17 @@ public class ReservationTest { Arguments.of(null, new ReservationTime(LocalTime.now().plusHours(1)), new ThemeEntity(null, "테마명", "설명", "썸네일URI"), - new Member(null, "name", "email@email.com", "password", Role.MEMBER)), + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), Arguments.of( LocalDate.now(), null, new ThemeEntity(null, "테마명", "설명", "썸네일URI"), - new Member(null, "name", "email@email.com", "password", Role.MEMBER)), + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), Arguments.of( LocalDate.now(), new ReservationTime(LocalTime.now().plusHours(1)), null, - new Member(null, "name", "email@email.com", "password", Role.MEMBER)), + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), Arguments.of( LocalDate.now(), new ReservationTime(LocalTime.now().plusHours(1)), diff --git a/src/test/java/roomescape/reservation/domain/repository/ReservationSearchSpecificationTest.java b/src/test/java/roomescape/reservation/domain/repository/ReservationSearchSpecificationTest.java index 56f33293..17b97f00 100644 --- a/src/test/java/roomescape/reservation/domain/repository/ReservationSearchSpecificationTest.java +++ b/src/test/java/roomescape/reservation/domain/repository/ReservationSearchSpecificationTest.java @@ -13,7 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.data.jpa.domain.Specification; -import roomescape.member.infrastructure.persistence.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.domain.Reservation; @@ -50,7 +50,7 @@ class ReservationSearchSpecificationTest { @BeforeEach void setUp() { LocalDateTime dateTime = LocalDateTime.now(); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); ReservationTime time = timeRepository.save(new ReservationTime(dateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "description", "thumbnail")); diff --git a/src/test/java/roomescape/reservation/service/ReservationServiceTest.java b/src/test/java/roomescape/reservation/service/ReservationServiceTest.java index b85aa741..f42ea4e7 100644 --- a/src/test/java/roomescape/reservation/service/ReservationServiceTest.java +++ b/src/test/java/roomescape/reservation/service/ReservationServiceTest.java @@ -15,7 +15,7 @@ import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql.ExecutionPhase; import roomescape.member.business.MemberService; -import roomescape.member.infrastructure.persistence.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.domain.Reservation; @@ -53,8 +53,8 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member1 = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); - Member member2 = memberRepository.save(new Member(null, "name2", "email2@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member2 = memberRepository.save(new MemberEntity(null, "name2", "email2@email.com", "password", Role.MEMBER)); LocalDate date = LocalDate.now().plusDays(1L); // when @@ -75,7 +75,7 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); LocalDate date = LocalDate.now().plusDays(1L); // when @@ -95,8 +95,8 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); - Member member1 = memberRepository.save(new Member(null, "name1", "email1@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); LocalDate date = LocalDate.now().plusDays(1L); // when @@ -119,7 +119,7 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); LocalDate beforeDate = LocalDate.now().minusDays(1L); // when & then @@ -136,7 +136,7 @@ class ReservationServiceTest { LocalDateTime beforeTime = LocalDateTime.now().minusHours(1L).withNano(0); ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(beforeTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); // when & then assertThatThrownBy(() -> reservationService.addReservation( @@ -180,9 +180,9 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member admin = memberRepository.save(new Member(null, "admin", "admin@email.com", "password", Role.ADMIN)); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); - Member member1 = memberRepository.save(new Member(null, "name1", "email1@email.com", "password", Role.MEMBER)); + MemberEntity admin = memberRepository.save(new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); reservationService.addReservation( new ReservationRequest(LocalDate.now().plusDays(1L), reservationTime.getId(), theme.getId(), @@ -203,8 +203,8 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member admin = memberRepository.save(new Member(null, "admin", "admin@email.com", "password", Role.ADMIN)); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity admin = memberRepository.save(new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); // when ReservationResponse waiting = reservationService.addWaiting( diff --git a/src/test/java/roomescape/reservation/service/ReservationTimeServiceTest.java b/src/test/java/roomescape/reservation/service/ReservationTimeServiceTest.java index 473f5698..2fa7406c 100644 --- a/src/test/java/roomescape/reservation/service/ReservationTimeServiceTest.java +++ b/src/test/java/roomescape/reservation/service/ReservationTimeServiceTest.java @@ -13,7 +13,7 @@ import org.springframework.context.annotation.Import; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql.ExecutionPhase; -import roomescape.member.infrastructure.persistence.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.domain.Reservation; @@ -75,7 +75,7 @@ class ReservationTimeServiceTest { ReservationTime reservationTime = reservationTimeRepository.save( new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Member member = memberRepository.save(new Member(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); // when reservationRepository.save(new Reservation(localDateTime.toLocalDate(), reservationTime, theme, member, diff --git a/src/test/java/roomescape/reservation/service/ReservationWithPaymentServiceTest.java b/src/test/java/roomescape/reservation/service/ReservationWithPaymentServiceTest.java index 4a7e5cdc..e30a2faa 100644 --- a/src/test/java/roomescape/reservation/service/ReservationWithPaymentServiceTest.java +++ b/src/test/java/roomescape/reservation/service/ReservationWithPaymentServiceTest.java @@ -13,7 +13,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql.ExecutionPhase; -import roomescape.member.infrastructure.persistence.Member; +import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository; @@ -59,7 +59,7 @@ class ReservationWithPaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - Member member = memberRepository.save(new Member(null, "member", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); ReservationRequest reservationRequest = new ReservationRequest(date, time.getId(), theme.getId(), "payment-key", "order-id", 10000L, "NORMAL"); @@ -95,7 +95,7 @@ class ReservationWithPaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - Member member = memberRepository.save(new Member(null, "member", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); ReservationRequest reservationRequest = new ReservationRequest(date, time.getId(), theme.getId(), "payment-key", "order-id", 10000L, "NORMAL"); @@ -123,7 +123,7 @@ class ReservationWithPaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - Member member = memberRepository.save(new Member(null, "member", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation saved = reservationRepository.save( @@ -145,7 +145,7 @@ class ReservationWithPaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - Member member = memberRepository.save(new Member(null, "member", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); ReservationRequest reservationRequest = new ReservationRequest(date, time.getId(), theme.getId(), "payment-key", "order-id", 10000L, "NORMAL"); diff --git a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt index 4111939a..6d3b0d6d 100644 --- a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt +++ b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt @@ -1,7 +1,7 @@ package roomescape.theme.util import jakarta.persistence.EntityManager -import roomescape.member.infrastructure.persistence.Member +import roomescape.member.infrastructure.persistence.MemberEntity import roomescape.reservation.domain.ReservationStatus import roomescape.reservation.domain.ReservationTime import roomescape.theme.infrastructure.persistence.ThemeEntity @@ -20,7 +20,7 @@ object TestThemeCreateUtil { date: LocalDate, ): ThemeEntity { val themeEntity: ThemeEntity = ThemeFixture.create(name = name).also { entityManager.persist(it) } - val member: Member = MemberFixture.create().also { entityManager.persist(it) } + val member: MemberEntity = MemberFixture.create().also { entityManager.persist(it) } for (i in 1..reservedCount) { val time: ReservationTime = ReservationTimeFixture.create( diff --git a/src/test/java/roomescape/util/Fixtures.kt b/src/test/java/roomescape/util/Fixtures.kt index 5236ef28..2afb8d10 100644 --- a/src/test/java/roomescape/util/Fixtures.kt +++ b/src/test/java/roomescape/util/Fixtures.kt @@ -2,7 +2,7 @@ package roomescape.util import roomescape.auth.infrastructure.jwt.JwtHandler import roomescape.auth.web.LoginRequest -import roomescape.member.infrastructure.persistence.Member +import roomescape.member.infrastructure.persistence.MemberEntity import roomescape.member.infrastructure.persistence.Role import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity import roomescape.payment.infrastructure.persistence.PaymentEntity @@ -26,9 +26,9 @@ object MemberFixture { account: String = "default", password: String = "password", role: Role = Role.ADMIN - ): Member = Member(id, name, "$account@email.com", password, role) + ): MemberEntity = MemberEntity(id, name, "$account@email.com", password, role) - fun admin(): Member = create( + fun admin(): MemberEntity = create( id = 2L, account = "admin", role = Role.ADMIN @@ -38,7 +38,7 @@ object MemberFixture { password = admin().password ) - fun user(): Member = create( + fun user(): MemberEntity = create( id = 1L, account = "user", role = Role.MEMBER @@ -71,7 +71,7 @@ object ReservationFixture { date: LocalDate = LocalDate.now().plusWeeks(1), themeEntity: ThemeEntity = ThemeFixture.create(), reservationTime: ReservationTime = ReservationTimeFixture.create(), - member: Member = MemberFixture.create(), + member: MemberEntity = MemberFixture.create(), status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED ): Reservation = Reservation(id, date, reservationTime, themeEntity, member, status) } diff --git a/src/test/java/roomescape/util/RoomescapeApiTest.kt b/src/test/java/roomescape/util/RoomescapeApiTest.kt index 803bf86e..a26299a3 100644 --- a/src/test/java/roomescape/util/RoomescapeApiTest.kt +++ b/src/test/java/roomescape/util/RoomescapeApiTest.kt @@ -18,7 +18,7 @@ import roomescape.auth.web.support.MemberIdResolver import roomescape.common.exception.ErrorType import roomescape.common.exception.RoomescapeException import roomescape.member.business.MemberService -import roomescape.member.infrastructure.persistence.Member +import roomescape.member.infrastructure.persistence.MemberEntity import roomescape.member.infrastructure.persistence.MemberRepository import roomescape.util.MemberFixture.NOT_LOGGED_IN_USERID @@ -43,8 +43,8 @@ abstract class RoomescapeApiTest : BehaviorSpec() { lateinit var jwtHandler: JwtHandler val objectMapper: ObjectMapper = jacksonObjectMapper() - val admin: Member = MemberFixture.admin() - val user: Member = MemberFixture.user() + val admin: MemberEntity = MemberFixture.admin() + val user: MemberEntity = MemberFixture.user() fun runGetTest( mockMvc: MockMvc, -- 2.47.2 From 0707aa856b9e22affb9c4f47fc5d40e63637fa69 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 02:05:12 +0900 Subject: [PATCH 02/40] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/business/PaymentService.kt | 2 +- .../persistence/PaymentEntity.kt | 2 +- .../java/roomescape/payment/web/PaymentDTO.kt | 2 +- .../ReservationService.java | 24 +++++++++---------- .../ReservationTimeService.java | 20 ++++++++-------- .../ReservationWithPaymentService.java | 8 +++---- .../persistence}/Reservation.java | 2 +- .../persistence}/ReservationRepository.java | 7 ++---- .../ReservationSearchSpecification.java | 5 +--- .../persistence}/ReservationStatus.java | 2 +- .../persistence}/ReservationTime.java | 2 +- .../ReservationTimeRepository.java | 4 +--- .../ReservationController.java | 18 +++++++------- .../ReservationTimeController.java | 12 +++++----- .../request/AdminReservationRequest.java | 2 +- .../request/ReservationRequest.java | 2 +- .../request/ReservationTimeRequest.java | 4 ++-- .../{dto => web}/request/WaitingRequest.java | 2 +- .../response/MyReservationResponse.java | 4 ++-- .../response/MyReservationsResponse.java | 2 +- .../response/ReservationResponse.java | 6 ++--- .../response/ReservationTimeInfoResponse.java | 2 +- .../ReservationTimeInfosResponse.java | 2 +- .../response/ReservationTimeResponse.java | 4 ++-- .../response/ReservationTimesResponse.java | 2 +- .../response/ReservationsResponse.java | 2 +- .../payment/business/PaymentServiceTest.java | 10 ++++---- .../ReservationServiceTest.java | 18 +++++++------- .../ReservationTimeServiceTest.java | 14 +++++------ .../ReservationWithPaymentServiceTest.java | 16 ++++++------- .../ReservationSearchSpecificationTest.java | 5 +--- .../persistence}/ReservationTest.java | 2 +- .../persistence}/ReservationTimeTest.java | 2 +- .../ReservationControllerTest.java | 18 +++++++------- .../ReservationTimeControllerTest.java | 12 +++++----- .../theme/util/TestThemeCreateUtil.kt | 4 ++-- src/test/java/roomescape/util/Fixtures.kt | 6 ++--- 37 files changed, 120 insertions(+), 131 deletions(-) rename src/main/java/roomescape/reservation/{service => business}/ReservationService.java (90%) rename src/main/java/roomescape/reservation/{service => business}/ReservationTimeService.java (83%) rename src/main/java/roomescape/reservation/{service => business}/ReservationWithPaymentService.java (88%) rename src/main/java/roomescape/reservation/{domain => infrastructure/persistence}/Reservation.java (98%) rename src/main/java/roomescape/reservation/{domain/repository => infrastructure/persistence}/ReservationRepository.java (86%) rename src/main/java/roomescape/reservation/{domain/repository => infrastructure/persistence}/ReservationSearchSpecification.java (93%) rename src/main/java/roomescape/reservation/{domain => infrastructure/persistence}/ReservationStatus.java (87%) rename src/main/java/roomescape/reservation/{domain => infrastructure/persistence}/ReservationTime.java (95%) rename src/main/java/roomescape/reservation/{domain/repository => infrastructure/persistence}/ReservationTimeRepository.java (71%) rename src/main/java/roomescape/reservation/{controller => web}/ReservationController.java (95%) rename src/main/java/roomescape/reservation/{controller => web}/ReservationTimeController.java (92%) rename src/main/java/roomescape/reservation/{dto => web}/request/AdminReservationRequest.java (93%) rename src/main/java/roomescape/reservation/{dto => web}/request/ReservationRequest.java (96%) rename src/main/java/roomescape/reservation/{dto => web}/request/ReservationTimeRequest.java (89%) rename src/main/java/roomescape/reservation/{dto => web}/request/WaitingRequest.java (94%) rename src/main/java/roomescape/reservation/{dto => web}/response/MyReservationResponse.java (91%) rename src/main/java/roomescape/reservation/{dto => web}/response/MyReservationsResponse.java (90%) rename src/main/java/roomescape/reservation/{dto => web}/response/ReservationResponse.java (87%) rename src/main/java/roomescape/reservation/{dto => web}/response/ReservationTimeInfoResponse.java (93%) rename src/main/java/roomescape/reservation/{dto => web}/response/ReservationTimeInfosResponse.java (90%) rename src/main/java/roomescape/reservation/{dto => web}/response/ReservationTimeResponse.java (83%) rename src/main/java/roomescape/reservation/{dto => web}/response/ReservationTimesResponse.java (88%) rename src/main/java/roomescape/reservation/{dto => web}/response/ReservationsResponse.java (88%) rename src/test/java/roomescape/reservation/{service => business}/ReservationServiceTest.java (94%) rename src/test/java/roomescape/reservation/{service => business}/ReservationTimeServiceTest.java (86%) rename src/test/java/roomescape/reservation/{service => business}/ReservationWithPaymentServiceTest.java (92%) rename src/test/java/roomescape/reservation/{domain/repository => infrastructure/persistence}/ReservationSearchSpecificationTest.java (96%) rename src/test/java/roomescape/reservation/{domain => infrastructure/persistence}/ReservationTest.java (97%) rename src/test/java/roomescape/reservation/{domain => infrastructure/persistence}/ReservationTimeTest.java (88%) rename src/test/java/roomescape/reservation/{controller => web}/ReservationControllerTest.java (97%) rename src/test/java/roomescape/reservation/{controller => web}/ReservationTimeControllerTest.java (94%) diff --git a/src/main/java/roomescape/payment/business/PaymentService.kt b/src/main/java/roomescape/payment/business/PaymentService.kt index 1b4e6deb..9d092ed6 100644 --- a/src/main/java/roomescape/payment/business/PaymentService.kt +++ b/src/main/java/roomescape/payment/business/PaymentService.kt @@ -13,7 +13,7 @@ import roomescape.payment.web.PaymentApprove import roomescape.payment.web.PaymentCancel import roomescape.payment.web.ReservationPaymentResponse import roomescape.payment.web.toReservationPaymentResponse -import roomescape.reservation.domain.Reservation +import roomescape.reservation.infrastructure.persistence.Reservation import java.time.OffsetDateTime @Service diff --git a/src/main/java/roomescape/payment/infrastructure/persistence/PaymentEntity.kt b/src/main/java/roomescape/payment/infrastructure/persistence/PaymentEntity.kt index 8de5d4da..bcc52d20 100644 --- a/src/main/java/roomescape/payment/infrastructure/persistence/PaymentEntity.kt +++ b/src/main/java/roomescape/payment/infrastructure/persistence/PaymentEntity.kt @@ -1,7 +1,7 @@ package roomescape.payment.infrastructure.persistence import jakarta.persistence.* -import roomescape.reservation.domain.Reservation +import roomescape.reservation.infrastructure.persistence.Reservation import java.time.OffsetDateTime @Entity diff --git a/src/main/java/roomescape/payment/web/PaymentDTO.kt b/src/main/java/roomescape/payment/web/PaymentDTO.kt index 8b4b12e2..2f549b36 100644 --- a/src/main/java/roomescape/payment/web/PaymentDTO.kt +++ b/src/main/java/roomescape/payment/web/PaymentDTO.kt @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.databind.annotation.JsonDeserialize import roomescape.payment.infrastructure.client.PaymentCancelResponseDeserializer import roomescape.payment.infrastructure.persistence.PaymentEntity -import roomescape.reservation.dto.response.ReservationResponse +import roomescape.reservation.web.response.ReservationResponse import java.time.OffsetDateTime class PaymentApprove { diff --git a/src/main/java/roomescape/reservation/service/ReservationService.java b/src/main/java/roomescape/reservation/business/ReservationService.java similarity index 90% rename from src/main/java/roomescape/reservation/service/ReservationService.java rename to src/main/java/roomescape/reservation/business/ReservationService.java index 4c80e19b..b6be3a21 100644 --- a/src/main/java/roomescape/reservation/service/ReservationService.java +++ b/src/main/java/roomescape/reservation/business/ReservationService.java @@ -1,4 +1,4 @@ -package roomescape.reservation.service; +package roomescape.reservation.business; import java.time.LocalDate; import java.time.LocalDateTime; @@ -13,17 +13,17 @@ import roomescape.common.exception.ErrorType; import roomescape.common.exception.RoomescapeException; import roomescape.member.business.MemberService; import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; -import roomescape.reservation.domain.ReservationTime; -import roomescape.reservation.domain.repository.ReservationRepository; -import roomescape.reservation.domain.repository.ReservationSearchSpecification; -import roomescape.reservation.dto.request.AdminReservationRequest; -import roomescape.reservation.dto.request.ReservationRequest; -import roomescape.reservation.dto.request.WaitingRequest; -import roomescape.reservation.dto.response.MyReservationsResponse; -import roomescape.reservation.dto.response.ReservationResponse; -import roomescape.reservation.dto.response.ReservationsResponse; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; +import roomescape.reservation.infrastructure.persistence.ReservationSearchSpecification; +import roomescape.reservation.web.request.AdminReservationRequest; +import roomescape.reservation.web.request.ReservationRequest; +import roomescape.reservation.web.request.WaitingRequest; +import roomescape.reservation.web.response.MyReservationsResponse; +import roomescape.reservation.web.response.ReservationResponse; +import roomescape.reservation.web.response.ReservationsResponse; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.business.ThemeService; diff --git a/src/main/java/roomescape/reservation/service/ReservationTimeService.java b/src/main/java/roomescape/reservation/business/ReservationTimeService.java similarity index 83% rename from src/main/java/roomescape/reservation/service/ReservationTimeService.java rename to src/main/java/roomescape/reservation/business/ReservationTimeService.java index 276a0daa..19716136 100644 --- a/src/main/java/roomescape/reservation/service/ReservationTimeService.java +++ b/src/main/java/roomescape/reservation/business/ReservationTimeService.java @@ -1,4 +1,4 @@ -package roomescape.reservation.service; +package roomescape.reservation.business; import java.time.LocalDate; import java.util.List; @@ -9,15 +9,15 @@ import org.springframework.transaction.annotation.Transactional; import roomescape.common.exception.ErrorType; import roomescape.common.exception.RoomescapeException; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationTime; -import roomescape.reservation.domain.repository.ReservationRepository; -import roomescape.reservation.domain.repository.ReservationTimeRepository; -import roomescape.reservation.dto.request.ReservationTimeRequest; -import roomescape.reservation.dto.response.ReservationTimeInfoResponse; -import roomescape.reservation.dto.response.ReservationTimeInfosResponse; -import roomescape.reservation.dto.response.ReservationTimeResponse; -import roomescape.reservation.dto.response.ReservationTimesResponse; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; +import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; +import roomescape.reservation.web.request.ReservationTimeRequest; +import roomescape.reservation.web.response.ReservationTimeInfoResponse; +import roomescape.reservation.web.response.ReservationTimeInfosResponse; +import roomescape.reservation.web.response.ReservationTimeResponse; +import roomescape.reservation.web.response.ReservationTimesResponse; @Service @Transactional diff --git a/src/main/java/roomescape/reservation/service/ReservationWithPaymentService.java b/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java similarity index 88% rename from src/main/java/roomescape/reservation/service/ReservationWithPaymentService.java rename to src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java index 853e6e30..e1bb4c74 100644 --- a/src/main/java/roomescape/reservation/service/ReservationWithPaymentService.java +++ b/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java @@ -1,4 +1,4 @@ -package roomescape.reservation.service; +package roomescape.reservation.business; import java.time.OffsetDateTime; @@ -9,9 +9,9 @@ import roomescape.payment.business.PaymentService; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; import roomescape.payment.web.ReservationPaymentResponse; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.dto.request.ReservationRequest; -import roomescape.reservation.dto.response.ReservationResponse; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.web.request.ReservationRequest; +import roomescape.reservation.web.response.ReservationResponse; @Service @Transactional diff --git a/src/main/java/roomescape/reservation/domain/Reservation.java b/src/main/java/roomescape/reservation/infrastructure/persistence/Reservation.java similarity index 98% rename from src/main/java/roomescape/reservation/domain/Reservation.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/Reservation.java index f8dc6858..be474891 100644 --- a/src/main/java/roomescape/reservation/domain/Reservation.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/Reservation.java @@ -1,4 +1,4 @@ -package roomescape.reservation.domain; +package roomescape.reservation.infrastructure.persistence; import java.time.LocalDate; diff --git a/src/main/java/roomescape/reservation/domain/repository/ReservationRepository.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java similarity index 86% rename from src/main/java/roomescape/reservation/domain/repository/ReservationRepository.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java index af83b3dc..987dd6b4 100644 --- a/src/main/java/roomescape/reservation/domain/repository/ReservationRepository.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java @@ -1,4 +1,4 @@ -package roomescape.reservation.domain.repository; +package roomescape.reservation.infrastructure.persistence; import java.util.List; @@ -8,10 +8,7 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; -import roomescape.reservation.domain.ReservationTime; -import roomescape.reservation.dto.response.MyReservationResponse; +import roomescape.reservation.web.response.MyReservationResponse; public interface ReservationRepository extends JpaRepository, JpaSpecificationExecutor { diff --git a/src/main/java/roomescape/reservation/domain/repository/ReservationSearchSpecification.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.java similarity index 93% rename from src/main/java/roomescape/reservation/domain/repository/ReservationSearchSpecification.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.java index 69eb914a..888d62f2 100644 --- a/src/main/java/roomescape/reservation/domain/repository/ReservationSearchSpecification.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.java @@ -1,12 +1,9 @@ -package roomescape.reservation.domain.repository; +package roomescape.reservation.infrastructure.persistence; import java.time.LocalDate; import org.springframework.data.jpa.domain.Specification; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; - public class ReservationSearchSpecification { private Specification spec; diff --git a/src/main/java/roomescape/reservation/domain/ReservationStatus.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationStatus.java similarity index 87% rename from src/main/java/roomescape/reservation/domain/ReservationStatus.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationStatus.java index d8978397..d5f10221 100644 --- a/src/main/java/roomescape/reservation/domain/ReservationStatus.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationStatus.java @@ -1,4 +1,4 @@ -package roomescape.reservation.domain; +package roomescape.reservation.infrastructure.persistence; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/roomescape/reservation/domain/ReservationTime.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTime.java similarity index 95% rename from src/main/java/roomescape/reservation/domain/ReservationTime.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTime.java index e54a39b0..fa9ef589 100644 --- a/src/main/java/roomescape/reservation/domain/ReservationTime.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTime.java @@ -1,4 +1,4 @@ -package roomescape.reservation.domain; +package roomescape.reservation.infrastructure.persistence; import java.time.LocalTime; diff --git a/src/main/java/roomescape/reservation/domain/repository/ReservationTimeRepository.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.java similarity index 71% rename from src/main/java/roomescape/reservation/domain/repository/ReservationTimeRepository.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.java index 791077d2..8b6a1c0b 100644 --- a/src/main/java/roomescape/reservation/domain/repository/ReservationTimeRepository.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.java @@ -1,12 +1,10 @@ -package roomescape.reservation.domain.repository; +package roomescape.reservation.infrastructure.persistence; import java.time.LocalTime; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; -import roomescape.reservation.domain.ReservationTime; - public interface ReservationTimeRepository extends JpaRepository { List findByStartAt(LocalTime startAt); diff --git a/src/main/java/roomescape/reservation/controller/ReservationController.java b/src/main/java/roomescape/reservation/web/ReservationController.java similarity index 95% rename from src/main/java/roomescape/reservation/controller/ReservationController.java rename to src/main/java/roomescape/reservation/web/ReservationController.java index f5df5f57..90303267 100644 --- a/src/main/java/roomescape/reservation/controller/ReservationController.java +++ b/src/main/java/roomescape/reservation/web/ReservationController.java @@ -1,4 +1,4 @@ -package roomescape.reservation.controller; +package roomescape.reservation.web; import java.time.LocalDate; @@ -33,14 +33,14 @@ import roomescape.common.exception.RoomescapeException; import roomescape.payment.infrastructure.client.TossPaymentClient; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; -import roomescape.reservation.dto.request.AdminReservationRequest; -import roomescape.reservation.dto.request.ReservationRequest; -import roomescape.reservation.dto.request.WaitingRequest; -import roomescape.reservation.dto.response.MyReservationsResponse; -import roomescape.reservation.dto.response.ReservationResponse; -import roomescape.reservation.dto.response.ReservationsResponse; -import roomescape.reservation.service.ReservationService; -import roomescape.reservation.service.ReservationWithPaymentService; +import roomescape.reservation.web.request.AdminReservationRequest; +import roomescape.reservation.web.request.ReservationRequest; +import roomescape.reservation.web.request.WaitingRequest; +import roomescape.reservation.web.response.MyReservationsResponse; +import roomescape.reservation.web.response.ReservationResponse; +import roomescape.reservation.web.response.ReservationsResponse; +import roomescape.reservation.business.ReservationService; +import roomescape.reservation.business.ReservationWithPaymentService; @RestController @Tag(name = "3. 예약 API", description = "예약 및 대기 정보를 추가 / 조회 / 삭제할 때 사용합니다.") diff --git a/src/main/java/roomescape/reservation/controller/ReservationTimeController.java b/src/main/java/roomescape/reservation/web/ReservationTimeController.java similarity index 92% rename from src/main/java/roomescape/reservation/controller/ReservationTimeController.java rename to src/main/java/roomescape/reservation/web/ReservationTimeController.java index 18d5abb5..bd494779 100644 --- a/src/main/java/roomescape/reservation/controller/ReservationTimeController.java +++ b/src/main/java/roomescape/reservation/web/ReservationTimeController.java @@ -1,4 +1,4 @@ -package roomescape.reservation.controller; +package roomescape.reservation.web; import java.time.LocalDate; @@ -27,11 +27,11 @@ import roomescape.auth.web.support.Admin; import roomescape.auth.web.support.LoginRequired; import roomescape.common.dto.response.RoomescapeApiResponse; import roomescape.common.dto.response.RoomescapeErrorResponse; -import roomescape.reservation.dto.request.ReservationTimeRequest; -import roomescape.reservation.dto.response.ReservationTimeInfosResponse; -import roomescape.reservation.dto.response.ReservationTimeResponse; -import roomescape.reservation.dto.response.ReservationTimesResponse; -import roomescape.reservation.service.ReservationTimeService; +import roomescape.reservation.web.request.ReservationTimeRequest; +import roomescape.reservation.web.response.ReservationTimeInfosResponse; +import roomescape.reservation.web.response.ReservationTimeResponse; +import roomescape.reservation.web.response.ReservationTimesResponse; +import roomescape.reservation.business.ReservationTimeService; @RestController @Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.") diff --git a/src/main/java/roomescape/reservation/dto/request/AdminReservationRequest.java b/src/main/java/roomescape/reservation/web/request/AdminReservationRequest.java similarity index 93% rename from src/main/java/roomescape/reservation/dto/request/AdminReservationRequest.java rename to src/main/java/roomescape/reservation/web/request/AdminReservationRequest.java index 5b2ea0e1..af07eab7 100644 --- a/src/main/java/roomescape/reservation/dto/request/AdminReservationRequest.java +++ b/src/main/java/roomescape/reservation/web/request/AdminReservationRequest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.request; +package roomescape.reservation.web.request; import java.time.LocalDate; diff --git a/src/main/java/roomescape/reservation/dto/request/ReservationRequest.java b/src/main/java/roomescape/reservation/web/request/ReservationRequest.java similarity index 96% rename from src/main/java/roomescape/reservation/dto/request/ReservationRequest.java rename to src/main/java/roomescape/reservation/web/request/ReservationRequest.java index e15b00fb..88805c05 100644 --- a/src/main/java/roomescape/reservation/dto/request/ReservationRequest.java +++ b/src/main/java/roomescape/reservation/web/request/ReservationRequest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.request; +package roomescape.reservation.web.request; import java.time.LocalDate; diff --git a/src/main/java/roomescape/reservation/dto/request/ReservationTimeRequest.java b/src/main/java/roomescape/reservation/web/request/ReservationTimeRequest.java similarity index 89% rename from src/main/java/roomescape/reservation/dto/request/ReservationTimeRequest.java rename to src/main/java/roomescape/reservation/web/request/ReservationTimeRequest.java index dd2f24c5..74c60b84 100644 --- a/src/main/java/roomescape/reservation/dto/request/ReservationTimeRequest.java +++ b/src/main/java/roomescape/reservation/web/request/ReservationTimeRequest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.request; +package roomescape.reservation.web.request; import java.time.LocalTime; @@ -9,7 +9,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import roomescape.common.exception.ErrorType; import roomescape.common.exception.RoomescapeException; -import roomescape.reservation.domain.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTime; @Schema(name = "예약 시간 저장 요청", description = "예약 시간 저장 요청시 사용됩니다.") public record ReservationTimeRequest( diff --git a/src/main/java/roomescape/reservation/dto/request/WaitingRequest.java b/src/main/java/roomescape/reservation/web/request/WaitingRequest.java similarity index 94% rename from src/main/java/roomescape/reservation/dto/request/WaitingRequest.java rename to src/main/java/roomescape/reservation/web/request/WaitingRequest.java index 0568a670..da794d3f 100644 --- a/src/main/java/roomescape/reservation/dto/request/WaitingRequest.java +++ b/src/main/java/roomescape/reservation/web/request/WaitingRequest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.request; +package roomescape.reservation.web.request; import java.time.LocalDate; diff --git a/src/main/java/roomescape/reservation/dto/response/MyReservationResponse.java b/src/main/java/roomescape/reservation/web/response/MyReservationResponse.java similarity index 91% rename from src/main/java/roomescape/reservation/dto/response/MyReservationResponse.java rename to src/main/java/roomescape/reservation/web/response/MyReservationResponse.java index 8667c371..ba7dfe16 100644 --- a/src/main/java/roomescape/reservation/dto/response/MyReservationResponse.java +++ b/src/main/java/roomescape/reservation/web/response/MyReservationResponse.java @@ -1,10 +1,10 @@ -package roomescape.reservation.dto.response; +package roomescape.reservation.web.response; import java.time.LocalDate; import java.time.LocalTime; import io.swagger.v3.oas.annotations.media.Schema; -import roomescape.reservation.domain.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; @Schema(name = "회원의 예약 및 대기 응답", description = "회원의 예약 및 대기 정보 응답시 사용됩니다.") public record MyReservationResponse( diff --git a/src/main/java/roomescape/reservation/dto/response/MyReservationsResponse.java b/src/main/java/roomescape/reservation/web/response/MyReservationsResponse.java similarity index 90% rename from src/main/java/roomescape/reservation/dto/response/MyReservationsResponse.java rename to src/main/java/roomescape/reservation/web/response/MyReservationsResponse.java index a32ef460..6d9b70e0 100644 --- a/src/main/java/roomescape/reservation/dto/response/MyReservationsResponse.java +++ b/src/main/java/roomescape/reservation/web/response/MyReservationsResponse.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.response; +package roomescape.reservation.web.response; import java.util.List; diff --git a/src/main/java/roomescape/reservation/dto/response/ReservationResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationResponse.java similarity index 87% rename from src/main/java/roomescape/reservation/dto/response/ReservationResponse.java rename to src/main/java/roomescape/reservation/web/response/ReservationResponse.java index f1fa1704..a6aa290c 100644 --- a/src/main/java/roomescape/reservation/dto/response/ReservationResponse.java +++ b/src/main/java/roomescape/reservation/web/response/ReservationResponse.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.response; +package roomescape.reservation.web.response; import java.time.LocalDate; @@ -6,8 +6,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import roomescape.member.web.MemberResponse; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.theme.web.ThemeResponse; @Schema(name = "예약 정보", description = "예약 저장 및 조회 응답에 사용됩니다.") diff --git a/src/main/java/roomescape/reservation/dto/response/ReservationTimeInfoResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationTimeInfoResponse.java similarity index 93% rename from src/main/java/roomescape/reservation/dto/response/ReservationTimeInfoResponse.java rename to src/main/java/roomescape/reservation/web/response/ReservationTimeInfoResponse.java index 1105bf03..6912ef81 100644 --- a/src/main/java/roomescape/reservation/dto/response/ReservationTimeInfoResponse.java +++ b/src/main/java/roomescape/reservation/web/response/ReservationTimeInfoResponse.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.response; +package roomescape.reservation.web.response; import java.time.LocalTime; diff --git a/src/main/java/roomescape/reservation/dto/response/ReservationTimeInfosResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationTimeInfosResponse.java similarity index 90% rename from src/main/java/roomescape/reservation/dto/response/ReservationTimeInfosResponse.java rename to src/main/java/roomescape/reservation/web/response/ReservationTimeInfosResponse.java index ef02deeb..97ee2ef9 100644 --- a/src/main/java/roomescape/reservation/dto/response/ReservationTimeInfosResponse.java +++ b/src/main/java/roomescape/reservation/web/response/ReservationTimeInfosResponse.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.response; +package roomescape.reservation.web.response; import java.util.List; diff --git a/src/main/java/roomescape/reservation/dto/response/ReservationTimeResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationTimeResponse.java similarity index 83% rename from src/main/java/roomescape/reservation/dto/response/ReservationTimeResponse.java rename to src/main/java/roomescape/reservation/web/response/ReservationTimeResponse.java index fc27d3d5..8edcae24 100644 --- a/src/main/java/roomescape/reservation/dto/response/ReservationTimeResponse.java +++ b/src/main/java/roomescape/reservation/web/response/ReservationTimeResponse.java @@ -1,9 +1,9 @@ -package roomescape.reservation.dto.response; +package roomescape.reservation.web.response; import java.time.LocalTime; import io.swagger.v3.oas.annotations.media.Schema; -import roomescape.reservation.domain.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTime; @Schema(name = "예약 시간 정보", description = "예약 시간 추가 및 조회 응답시 사용됩니다.") public record ReservationTimeResponse( diff --git a/src/main/java/roomescape/reservation/dto/response/ReservationTimesResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationTimesResponse.java similarity index 88% rename from src/main/java/roomescape/reservation/dto/response/ReservationTimesResponse.java rename to src/main/java/roomescape/reservation/web/response/ReservationTimesResponse.java index 1cbff917..196721c5 100644 --- a/src/main/java/roomescape/reservation/dto/response/ReservationTimesResponse.java +++ b/src/main/java/roomescape/reservation/web/response/ReservationTimesResponse.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.response; +package roomescape.reservation.web.response; import java.util.List; diff --git a/src/main/java/roomescape/reservation/dto/response/ReservationsResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationsResponse.java similarity index 88% rename from src/main/java/roomescape/reservation/dto/response/ReservationsResponse.java rename to src/main/java/roomescape/reservation/web/response/ReservationsResponse.java index 83386f1d..1b9811b5 100644 --- a/src/main/java/roomescape/reservation/dto/response/ReservationsResponse.java +++ b/src/main/java/roomescape/reservation/web/response/ReservationsResponse.java @@ -1,4 +1,4 @@ -package roomescape.reservation.dto.response; +package roomescape.reservation.web.response; import java.util.List; diff --git a/src/test/java/roomescape/payment/business/PaymentServiceTest.java b/src/test/java/roomescape/payment/business/PaymentServiceTest.java index 3770c56f..1731aab3 100644 --- a/src/test/java/roomescape/payment/business/PaymentServiceTest.java +++ b/src/test/java/roomescape/payment/business/PaymentServiceTest.java @@ -22,11 +22,11 @@ import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; import roomescape.payment.web.ReservationPaymentResponse; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; -import roomescape.reservation.domain.ReservationTime; -import roomescape.reservation.domain.repository.ReservationRepository; -import roomescape.reservation.domain.repository.ReservationTimeRepository; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; +import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; diff --git a/src/test/java/roomescape/reservation/service/ReservationServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationServiceTest.java similarity index 94% rename from src/test/java/roomescape/reservation/service/ReservationServiceTest.java rename to src/test/java/roomescape/reservation/business/ReservationServiceTest.java index f42ea4e7..b5136835 100644 --- a/src/test/java/roomescape/reservation/service/ReservationServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationServiceTest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.service; +package roomescape.reservation.business; import static org.assertj.core.api.Assertions.*; @@ -18,14 +18,14 @@ import roomescape.member.business.MemberService; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; -import roomescape.reservation.domain.ReservationTime; -import roomescape.reservation.domain.repository.ReservationRepository; -import roomescape.reservation.domain.repository.ReservationTimeRepository; -import roomescape.reservation.dto.request.ReservationRequest; -import roomescape.reservation.dto.request.WaitingRequest; -import roomescape.reservation.dto.response.ReservationResponse; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; +import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; +import roomescape.reservation.web.request.ReservationRequest; +import roomescape.reservation.web.request.WaitingRequest; +import roomescape.reservation.web.response.ReservationResponse; import roomescape.common.exception.RoomescapeException; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; diff --git a/src/test/java/roomescape/reservation/service/ReservationTimeServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java similarity index 86% rename from src/test/java/roomescape/reservation/service/ReservationTimeServiceTest.java rename to src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java index 2fa7406c..a6c91918 100644 --- a/src/test/java/roomescape/reservation/service/ReservationTimeServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.service; +package roomescape.reservation.business; import static org.assertj.core.api.Assertions.*; @@ -16,12 +16,12 @@ import org.springframework.test.context.jdbc.Sql.ExecutionPhase; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; -import roomescape.reservation.domain.ReservationTime; -import roomescape.reservation.domain.repository.ReservationRepository; -import roomescape.reservation.domain.repository.ReservationTimeRepository; -import roomescape.reservation.dto.request.ReservationTimeRequest; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; +import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; +import roomescape.reservation.web.request.ReservationTimeRequest; import roomescape.common.exception.RoomescapeException; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; diff --git a/src/test/java/roomescape/reservation/service/ReservationWithPaymentServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java similarity index 92% rename from src/test/java/roomescape/reservation/service/ReservationWithPaymentServiceTest.java rename to src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java index e30a2faa..8d321b7c 100644 --- a/src/test/java/roomescape/reservation/service/ReservationWithPaymentServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.service; +package roomescape.reservation.business; import static org.assertj.core.api.Assertions.*; @@ -21,13 +21,13 @@ import roomescape.payment.infrastructure.persistence.PaymentEntity; import roomescape.payment.infrastructure.persistence.PaymentRepository; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; -import roomescape.reservation.domain.ReservationTime; -import roomescape.reservation.domain.repository.ReservationRepository; -import roomescape.reservation.domain.repository.ReservationTimeRepository; -import roomescape.reservation.dto.request.ReservationRequest; -import roomescape.reservation.dto.response.ReservationResponse; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; +import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; +import roomescape.reservation.web.request.ReservationRequest; +import roomescape.reservation.web.response.ReservationResponse; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; diff --git a/src/test/java/roomescape/reservation/domain/repository/ReservationSearchSpecificationTest.java b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.java similarity index 96% rename from src/test/java/roomescape/reservation/domain/repository/ReservationSearchSpecificationTest.java rename to src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.java index 17b97f00..a9b75a04 100644 --- a/src/test/java/roomescape/reservation/domain/repository/ReservationSearchSpecificationTest.java +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.domain.repository; +package roomescape.reservation.infrastructure.persistence; import static org.assertj.core.api.Assertions.*; @@ -16,9 +16,6 @@ import org.springframework.data.jpa.domain.Specification; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; -import roomescape.reservation.domain.ReservationTime; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; diff --git a/src/test/java/roomescape/reservation/domain/ReservationTest.java b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java similarity index 97% rename from src/test/java/roomescape/reservation/domain/ReservationTest.java rename to src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java index bf1bc3bd..061b0326 100644 --- a/src/test/java/roomescape/reservation/domain/ReservationTest.java +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.domain; +package roomescape.reservation.infrastructure.persistence; import java.time.LocalDate; import java.time.LocalTime; diff --git a/src/test/java/roomescape/reservation/domain/ReservationTimeTest.java b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeTest.java similarity index 88% rename from src/test/java/roomescape/reservation/domain/ReservationTimeTest.java rename to src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeTest.java index 17e9dfaa..18260e0e 100644 --- a/src/test/java/roomescape/reservation/domain/ReservationTimeTest.java +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeTest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.domain; +package roomescape.reservation.infrastructure.persistence; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/roomescape/reservation/controller/ReservationControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationControllerTest.java similarity index 97% rename from src/test/java/roomescape/reservation/controller/ReservationControllerTest.java rename to src/test/java/roomescape/reservation/web/ReservationControllerTest.java index 726f164b..bc772916 100644 --- a/src/test/java/roomescape/reservation/controller/ReservationControllerTest.java +++ b/src/test/java/roomescape/reservation/web/ReservationControllerTest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.controller; +package roomescape.reservation.web; import static org.assertj.core.api.Assertions.*; import static org.hamcrest.Matchers.*; @@ -41,14 +41,14 @@ import roomescape.payment.infrastructure.persistence.PaymentEntity; import roomescape.payment.infrastructure.persistence.PaymentRepository; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; -import roomescape.reservation.domain.ReservationTime; -import roomescape.reservation.domain.repository.ReservationRepository; -import roomescape.reservation.domain.repository.ReservationTimeRepository; -import roomescape.reservation.dto.request.AdminReservationRequest; -import roomescape.reservation.dto.request.ReservationRequest; -import roomescape.reservation.dto.request.WaitingRequest; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; +import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; +import roomescape.reservation.web.request.AdminReservationRequest; +import roomescape.reservation.web.request.ReservationRequest; +import roomescape.reservation.web.request.WaitingRequest; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; diff --git a/src/test/java/roomescape/reservation/controller/ReservationTimeControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java similarity index 94% rename from src/test/java/roomescape/reservation/controller/ReservationTimeControllerTest.java rename to src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java index f3adec83..3aa5883b 100644 --- a/src/test/java/roomescape/reservation/controller/ReservationTimeControllerTest.java +++ b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java @@ -1,4 +1,4 @@ -package roomescape.reservation.controller; +package roomescape.reservation.web; import static org.hamcrest.Matchers.*; @@ -24,11 +24,11 @@ import io.restassured.http.Header; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.domain.Reservation; -import roomescape.reservation.domain.ReservationStatus; -import roomescape.reservation.domain.ReservationTime; -import roomescape.reservation.domain.repository.ReservationRepository; -import roomescape.reservation.domain.repository.ReservationTimeRepository; +import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; +import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; diff --git a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt index 6d3b0d6d..c3765df7 100644 --- a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt +++ b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt @@ -2,8 +2,8 @@ package roomescape.theme.util import jakarta.persistence.EntityManager import roomescape.member.infrastructure.persistence.MemberEntity -import roomescape.reservation.domain.ReservationStatus -import roomescape.reservation.domain.ReservationTime +import roomescape.reservation.infrastructure.persistence.ReservationStatus +import roomescape.reservation.infrastructure.persistence.ReservationTime import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.util.MemberFixture import roomescape.util.ReservationFixture diff --git a/src/test/java/roomescape/util/Fixtures.kt b/src/test/java/roomescape/util/Fixtures.kt index 2afb8d10..d61b70ba 100644 --- a/src/test/java/roomescape/util/Fixtures.kt +++ b/src/test/java/roomescape/util/Fixtures.kt @@ -8,9 +8,9 @@ import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity import roomescape.payment.infrastructure.persistence.PaymentEntity import roomescape.payment.web.PaymentApprove import roomescape.payment.web.PaymentCancel -import roomescape.reservation.domain.Reservation -import roomescape.reservation.domain.ReservationStatus -import roomescape.reservation.domain.ReservationTime +import roomescape.reservation.infrastructure.persistence.Reservation +import roomescape.reservation.infrastructure.persistence.ReservationStatus +import roomescape.reservation.infrastructure.persistence.ReservationTime import roomescape.theme.infrastructure.persistence.ThemeEntity import java.time.LocalDate import java.time.LocalTime -- 2.47.2 From dcf4699bdd7c6fc21a36ab0b2e2de5d8121e8bb1 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 02:42:01 +0900 Subject: [PATCH 03/40] =?UTF-8?q?refactor:=20DTO=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98=20?= =?UTF-8?q?=EB=B0=8F=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/MemberEntity.kt | 1 + .../java/roomescape/payment/web/PaymentDTO.kt | 2 +- .../business/ReservationService.java | 32 ++--- .../business/ReservationTimeService.java | 20 ++-- .../ReservationWithPaymentService.java | 4 +- .../persistence/ReservationRepository.java | 6 +- .../web/ReservationController.java | 10 +- .../reservation/web/ReservationRequest.kt | 66 ++++++++++ .../reservation/web/ReservationResponse.kt | 113 ++++++++++++++++++ .../web/ReservationTimeController.java | 6 +- .../reservation/web/ReservationTimeDTO.kt | 40 +++++++ .../web/request/AdminReservationRequest.java | 18 --- .../web/request/ReservationRequest.java | 36 ------ .../web/request/ReservationTimeRequest.java | 31 ----- .../web/request/WaitingRequest.java | 20 ---- .../web/response/MyReservationResponse.java | 33 ----- .../web/response/MyReservationsResponse.java | 11 -- .../web/response/ReservationResponse.java | 42 ------- .../response/ReservationTimeInfoResponse.java | 16 --- .../ReservationTimeInfosResponse.java | 11 -- .../web/response/ReservationTimeResponse.java | 19 --- .../response/ReservationTimesResponse.java | 11 -- .../web/response/ReservationsResponse.java | 11 -- .../java/roomescape/theme/web/ThemeDTO.kt | 2 +- .../auth/business/AuthServiceTest.kt | 10 +- .../auth/infrastructure/jwt/JwtHandlerTest.kt | 2 +- .../payment/business/PaymentServiceTest.java | 13 +- .../CanceledPaymentRepositoryTest.kt | 2 +- .../business/ReservationServiceTest.java | 54 +++++---- .../business/ReservationTimeServiceTest.java | 9 +- .../ReservationWithPaymentServiceTest.java | 28 +++-- .../ReservationSearchSpecificationTest.java | 3 +- .../persistence/ReservationTest.java | 2 +- .../web/ReservationControllerTest.java | 42 ++++--- .../web/ReservationTimeControllerTest.java | 5 +- src/test/java/roomescape/util/Fixtures.kt | 2 + 36 files changed, 360 insertions(+), 373 deletions(-) create mode 100644 src/main/java/roomescape/reservation/web/ReservationRequest.kt create mode 100644 src/main/java/roomescape/reservation/web/ReservationResponse.kt create mode 100644 src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt delete mode 100644 src/main/java/roomescape/reservation/web/request/AdminReservationRequest.java delete mode 100644 src/main/java/roomescape/reservation/web/request/ReservationRequest.java delete mode 100644 src/main/java/roomescape/reservation/web/request/ReservationTimeRequest.java delete mode 100644 src/main/java/roomescape/reservation/web/request/WaitingRequest.java delete mode 100644 src/main/java/roomescape/reservation/web/response/MyReservationResponse.java delete mode 100644 src/main/java/roomescape/reservation/web/response/MyReservationsResponse.java delete mode 100644 src/main/java/roomescape/reservation/web/response/ReservationResponse.java delete mode 100644 src/main/java/roomescape/reservation/web/response/ReservationTimeInfoResponse.java delete mode 100644 src/main/java/roomescape/reservation/web/response/ReservationTimeInfosResponse.java delete mode 100644 src/main/java/roomescape/reservation/web/response/ReservationTimeResponse.java delete mode 100644 src/main/java/roomescape/reservation/web/response/ReservationTimesResponse.java delete mode 100644 src/main/java/roomescape/reservation/web/response/ReservationsResponse.java diff --git a/src/main/java/roomescape/member/infrastructure/persistence/MemberEntity.kt b/src/main/java/roomescape/member/infrastructure/persistence/MemberEntity.kt index 3014948d..f9ec13eb 100644 --- a/src/main/java/roomescape/member/infrastructure/persistence/MemberEntity.kt +++ b/src/main/java/roomescape/member/infrastructure/persistence/MemberEntity.kt @@ -3,6 +3,7 @@ package roomescape.member.infrastructure.persistence import jakarta.persistence.* @Entity +@Table(name = "member") class MemberEntity( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/roomescape/payment/web/PaymentDTO.kt b/src/main/java/roomescape/payment/web/PaymentDTO.kt index 2f549b36..a6261cce 100644 --- a/src/main/java/roomescape/payment/web/PaymentDTO.kt +++ b/src/main/java/roomescape/payment/web/PaymentDTO.kt @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.databind.annotation.JsonDeserialize import roomescape.payment.infrastructure.client.PaymentCancelResponseDeserializer import roomescape.payment.infrastructure.persistence.PaymentEntity -import roomescape.reservation.web.response.ReservationResponse +import roomescape.reservation.web.ReservationResponse import java.time.OffsetDateTime class PaymentApprove { diff --git a/src/main/java/roomescape/reservation/business/ReservationService.java b/src/main/java/roomescape/reservation/business/ReservationService.java index b6be3a21..4f8d0933 100644 --- a/src/main/java/roomescape/reservation/business/ReservationService.java +++ b/src/main/java/roomescape/reservation/business/ReservationService.java @@ -14,18 +14,18 @@ import roomescape.common.exception.RoomescapeException; import roomescape.member.business.MemberService; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.reservation.infrastructure.persistence.Reservation; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTime; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationSearchSpecification; -import roomescape.reservation.web.request.AdminReservationRequest; -import roomescape.reservation.web.request.ReservationRequest; -import roomescape.reservation.web.request.WaitingRequest; -import roomescape.reservation.web.response.MyReservationsResponse; -import roomescape.reservation.web.response.ReservationResponse; -import roomescape.reservation.web.response.ReservationsResponse; -import roomescape.theme.infrastructure.persistence.ThemeEntity; +import roomescape.reservation.infrastructure.persistence.ReservationStatus; +import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.web.AdminReservationRequest; +import roomescape.reservation.web.MyReservationsResponse; +import roomescape.reservation.web.ReservationRequest; +import roomescape.reservation.web.ReservationResponse; +import roomescape.reservation.web.ReservationsResponse; +import roomescape.reservation.web.WaitingRequest; import roomescape.theme.business.ThemeService; +import roomescape.theme.infrastructure.persistence.ThemeEntity; @Service @Transactional @@ -77,21 +77,21 @@ public class ReservationService { } public Reservation addReservation(ReservationRequest request, Long memberId) { - validateIsReservationExist(request.themeId(), request.timeId(), request.date()); - Reservation reservation = getReservationForSave(request.timeId(), request.themeId(), request.date(), memberId, + validateIsReservationExist(request.themeId, request.timeId, request.date); + Reservation reservation = getReservationForSave(request.timeId, request.themeId, request.date, memberId, ReservationStatus.CONFIRMED); return reservationRepository.save(reservation); } public ReservationResponse addReservationByAdmin(AdminReservationRequest request) { - validateIsReservationExist(request.themeId(), request.timeId(), request.date()); - return addReservationWithoutPayment(request.themeId(), request.timeId(), request.date(), - request.memberId(), ReservationStatus.CONFIRMED_PAYMENT_REQUIRED); + validateIsReservationExist(request.themeId, request.timeId, request.date); + return addReservationWithoutPayment(request.themeId, request.timeId, request.date, + request.memberId, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED); } public ReservationResponse addWaiting(WaitingRequest request, Long memberId) { - validateMemberAlreadyReserve(request.themeId(), request.timeId(), request.date(), memberId); - return addReservationWithoutPayment(request.themeId(), request.timeId(), request.date(), memberId, + validateMemberAlreadyReserve(request.themeId, request.timeId, request.date, memberId); + return addReservationWithoutPayment(request.themeId, request.timeId, request.date, memberId, ReservationStatus.WAITING); } diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.java b/src/main/java/roomescape/reservation/business/ReservationTimeService.java index 19716136..f0062ef5 100644 --- a/src/main/java/roomescape/reservation/business/ReservationTimeService.java +++ b/src/main/java/roomescape/reservation/business/ReservationTimeService.java @@ -10,14 +10,14 @@ import org.springframework.transaction.annotation.Transactional; import roomescape.common.exception.ErrorType; import roomescape.common.exception.RoomescapeException; import roomescape.reservation.infrastructure.persistence.Reservation; -import roomescape.reservation.infrastructure.persistence.ReservationTime; import roomescape.reservation.infrastructure.persistence.ReservationRepository; +import roomescape.reservation.infrastructure.persistence.ReservationTime; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.reservation.web.request.ReservationTimeRequest; -import roomescape.reservation.web.response.ReservationTimeInfoResponse; -import roomescape.reservation.web.response.ReservationTimeInfosResponse; -import roomescape.reservation.web.response.ReservationTimeResponse; -import roomescape.reservation.web.response.ReservationTimesResponse; +import roomescape.reservation.web.ReservationTimeInfoResponse; +import roomescape.reservation.web.ReservationTimeInfosResponse; +import roomescape.reservation.web.ReservationTimeRequest; +import roomescape.reservation.web.ReservationTimeResponse; +import roomescape.reservation.web.ReservationTimesResponse; @Service @Transactional @@ -53,18 +53,20 @@ public class ReservationTimeService { public ReservationTimeResponse addTime(ReservationTimeRequest reservationTimeRequest) { validateTimeDuplication(reservationTimeRequest); - ReservationTime reservationTime = reservationTimeRepository.save(reservationTimeRequest.toTime()); + ReservationTime reservationTime = reservationTimeRepository.save( + new ReservationTime(reservationTimeRequest.startAt) + ); return ReservationTimeResponse.from(reservationTime); } private void validateTimeDuplication(ReservationTimeRequest reservationTimeRequest) { List duplicateReservationTimes = reservationTimeRepository.findByStartAt( - reservationTimeRequest.startAt()); + reservationTimeRequest.startAt); if (!duplicateReservationTimes.isEmpty()) { throw new RoomescapeException(ErrorType.TIME_DUPLICATED, - String.format("[startAt: %s]", reservationTimeRequest.startAt()), HttpStatus.CONFLICT); + String.format("[startAt: %s]", reservationTimeRequest.startAt), HttpStatus.CONFLICT); } } diff --git a/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java b/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java index e1bb4c74..9e01b26b 100644 --- a/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java +++ b/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java @@ -10,8 +10,8 @@ import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; import roomescape.payment.web.ReservationPaymentResponse; import roomescape.reservation.infrastructure.persistence.Reservation; -import roomescape.reservation.web.request.ReservationRequest; -import roomescape.reservation.web.response.ReservationResponse; +import roomescape.reservation.web.ReservationRequest; +import roomescape.reservation.web.ReservationResponse; @Service @Transactional diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java index 987dd6b4..b6dd32de 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java @@ -8,7 +8,7 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import roomescape.reservation.web.response.MyReservationResponse; +import roomescape.reservation.web.MyReservationResponse; public interface ReservationRepository extends JpaRepository, JpaSpecificationExecutor { @@ -39,13 +39,13 @@ public interface ReservationRepository extends JpaRepository, boolean isExistConfirmedReservation(@Param("id") Long reservationId); @Query(""" - SELECT new roomescape.reservation.dto.response.MyReservationResponse( + SELECT new roomescape.reservation.web.MyReservationResponse( r.id, t.name, r.date, r.reservationTime.startAt, r.reservationStatus, - (SELECT COUNT (r2) FROM Reservation 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 Reservation r2 WHERE r2.theme = r.theme AND r2.date = r.date AND r2.reservationTime = r.reservationTime AND r2.id < r.id), p.paymentKey, p.totalAmount ) diff --git a/src/main/java/roomescape/reservation/web/ReservationController.java b/src/main/java/roomescape/reservation/web/ReservationController.java index 90303267..1fe53e0d 100644 --- a/src/main/java/roomescape/reservation/web/ReservationController.java +++ b/src/main/java/roomescape/reservation/web/ReservationController.java @@ -33,12 +33,6 @@ import roomescape.common.exception.RoomescapeException; import roomescape.payment.infrastructure.client.TossPaymentClient; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; -import roomescape.reservation.web.request.AdminReservationRequest; -import roomescape.reservation.web.request.ReservationRequest; -import roomescape.reservation.web.request.WaitingRequest; -import roomescape.reservation.web.response.MyReservationsResponse; -import roomescape.reservation.web.response.ReservationResponse; -import roomescape.reservation.web.response.ReservationsResponse; import roomescape.reservation.business.ReservationService; import roomescape.reservation.business.ReservationWithPaymentService; @@ -142,7 +136,7 @@ public class ReservationController { @MemberId @Parameter(hidden = true) Long memberId, HttpServletResponse response ) { - PaymentApprove.Request paymentRequest = reservationRequest.getPaymentRequest(); + PaymentApprove.Request paymentRequest = reservationRequest.paymentRequest(); PaymentApprove.Response paymentResponse = paymentClient.confirmPayment(paymentRequest); try { @@ -265,7 +259,7 @@ public class ReservationController { ReservationResponse reservationResponse, HttpServletResponse response ) { - response.setHeader(HttpHeaders.LOCATION, "/reservations/" + reservationResponse.id()); + response.setHeader(HttpHeaders.LOCATION, "/reservations/" + reservationResponse.id); return RoomescapeApiResponse.success(reservationResponse); } } diff --git a/src/main/java/roomescape/reservation/web/ReservationRequest.kt b/src/main/java/roomescape/reservation/web/ReservationRequest.kt new file mode 100644 index 00000000..fa081bc9 --- /dev/null +++ b/src/main/java/roomescape/reservation/web/ReservationRequest.kt @@ -0,0 +1,66 @@ +package roomescape.reservation.web + +import com.fasterxml.jackson.annotation.JsonIgnore +import io.swagger.v3.oas.annotations.media.Schema +import roomescape.payment.web.PaymentApprove +import java.time.LocalDate + +@Schema(name = "관리자 예약 저장 요청", description = "관리자의 예약 저장 요청시 사용됩니다.") +@JvmRecord +data class AdminReservationRequest( + @JvmField @field:Schema(description = "예약 날짜. 지난 날짜는 지정할 수 없으며, yyyy-MM-dd 형식으로 입력해야 합니다.", type = "string", example = "2022-12-31") + val date: LocalDate, + @JvmField @field:Schema(description = "예약 시간 ID.", example = "1") + val timeId: Long, + @JvmField @field:Schema(description = "테마 ID", example = "1") + val themeId: Long, + @JvmField @field:Schema(description = "회원 ID", example = "1") + val memberId: Long +) + +@Schema(name = "회원의 예약 저장 요청", description = "회원의 예약 요청시 사용됩니다.") +@JvmRecord +data class ReservationRequest( + @JvmField + @field:Schema(description = "예약 날짜. 지난 날짜는 지정할 수 없으며, yyyy-MM-dd 형식으로 입력해야 합니다.", type = "string", example = "2022-12-31") + val date: LocalDate, + + @JvmField + @field:Schema(description = "예약 시간 ID.", example = "1") + val timeId: Long, + + @JvmField @field:Schema(description = "테마 ID", example = "1") + val themeId: Long, + + @field:Schema(description = "결제 위젯을 통해 받은 결제 키") + val paymentKey: String, + + @field:Schema(description = "결제 위젯을 통해 받은 주문번호.") + val orderId: String, + + @field:Schema(description = "결제 위젯을 통해 받은 결제 금액") + val amount: Long, + + @field:Schema(description = "결제 타입", example = "NORMAL") + val paymentType: String +) { + @get:JsonIgnore + val paymentRequest: PaymentApprove.Request + get() = PaymentApprove.Request(paymentKey, orderId, amount, paymentType) +} + +@Schema(name = "예약 대기 저장 요청", description = "회원의 예약 대기 요청시 사용됩니다.") +@JvmRecord +data class WaitingRequest( + @JvmField + @field:Schema(description = "예약 날짜. 지난 날짜는 지정할 수 없으며, yyyy-MM-dd 형식으로 입력해야 합니다.", type = "string", example = "2022-12-31") + val date: LocalDate, + + @JvmField + @field:Schema(description = "예약 시간 ID", example = "1") + val timeId: Long, + + @JvmField + @field:Schema(description = "테마 ID", example = "1") + val themeId: Long +) diff --git a/src/main/java/roomescape/reservation/web/ReservationResponse.kt b/src/main/java/roomescape/reservation/web/ReservationResponse.kt new file mode 100644 index 00000000..d3ea1ec2 --- /dev/null +++ b/src/main/java/roomescape/reservation/web/ReservationResponse.kt @@ -0,0 +1,113 @@ +package roomescape.reservation.web + +import com.fasterxml.jackson.annotation.JsonProperty +import io.swagger.v3.oas.annotations.media.Schema +import roomescape.member.web.MemberResponse +import roomescape.member.web.MemberResponse.Companion.fromEntity +import roomescape.reservation.infrastructure.persistence.Reservation +import roomescape.reservation.infrastructure.persistence.ReservationStatus +import roomescape.reservation.infrastructure.persistence.ReservationTime +import roomescape.theme.web.ThemeResponse +import java.time.LocalDate +import java.time.LocalTime + +@Schema(name = "회원의 예약 및 대기 응답", description = "회원의 예약 및 대기 정보 응답시 사용됩니다.") +@JvmRecord +data class MyReservationResponse( + @field:Schema(description = "예약 번호. 예약을 식별할 때 사용합니다.") + val id: Long, + + @field:Schema(description = "테마 이름") + val themeName: String, + + @field:Schema(description = "예약 날짜", type = "string", example = "2022-12-31") + val date: LocalDate, + + @field:Schema(description = "예약 시간", type = "string", example = "09:00") + val time: LocalTime, + + @field:Schema(description = "예약 상태", type = "string") + val status: ReservationStatus, + + @field:Schema(description = "예약 대기 상태일 때의 대기 순번. 확정된 예약은 0의 값을 가집니다.") + val rank: Long, + + @field:Schema(description = "결제 키. 결제가 완료된 예약에만 값이 존재합니다.") + val paymentKey: String?, + + @field:Schema(description = "결제 금액. 결제가 완료된 예약에만 값이 존재합니다.") + val amount: Long? +) + +@Schema(name = "회원의 예약 및 대기 목록 조회 응답", description = "회원의 예약 및 대기 목록 조회 응답시 사용됩니다.") +@JvmRecord +data class MyReservationsResponse( + @field:Schema(description = "현재 로그인한 회원의 예약 및 대기 목록") + val myReservationResponses: List +) + +@Schema(name = "예약 정보", description = "예약 저장 및 조회 응답에 사용됩니다.") +@JvmRecord +data class ReservationResponse( + @JvmField + @field:Schema(description = "예약 번호. 예약을 식별할 때 사용합니다.") + val id: Long, + + @field:Schema(description = "예약 날짜", type = "string", example = "2022-12-31") + val date: LocalDate, + + @field:Schema(description = "예약한 회원 정보") + @field:JsonProperty("member") + val member: MemberResponse, + + @field:Schema(description = "예약 시간 정보") + @field:JsonProperty("time") + val time: ReservationTimeResponse, + + @field:Schema(description = "예약한 테마 정보") + @field:JsonProperty("theme") + val theme: ThemeResponse, + + @field:Schema(description = "예약 상태", type = "string") + val status: ReservationStatus +) { + companion object { + @JvmStatic + fun from(reservation: Reservation): ReservationResponse { + return ReservationResponse( + reservation.id, + reservation.date, + fromEntity(reservation.member), + ReservationTimeResponse.Companion.from(reservation.reservationTime), + ThemeResponse.Companion.from(reservation.theme), + reservation.reservationStatus + ) + } + } +} + +@Schema(name = "예약 목록 조회 응답", description = "모든 예약 정보 조회 응답시 사용됩니다.") +@JvmRecord +data class ReservationsResponse( + @field:Schema(description = "모든 예약 및 대기 목록") + val reservations: List +) + +@Schema(name = "예약 시간 정보", description = "예약 시간 추가 및 조회 응답시 사용됩니다.") +@JvmRecord +data class ReservationTimeResponse( + @JvmField + @field:Schema(description = "예약 시간 번호. 예약 시간을 식별할 때 사용합니다.") + val id: Long, + + @field:Schema(description = "예약 시간", type = "string", example = "09:00") + val startAt: LocalTime +) { + + companion object { + @JvmStatic + fun from(reservationTime: ReservationTime): ReservationTimeResponse { + return ReservationTimeResponse(reservationTime.id, reservationTime.startAt) + } + } +} diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeController.java b/src/main/java/roomescape/reservation/web/ReservationTimeController.java index bd494779..389a182e 100644 --- a/src/main/java/roomescape/reservation/web/ReservationTimeController.java +++ b/src/main/java/roomescape/reservation/web/ReservationTimeController.java @@ -27,10 +27,6 @@ import roomescape.auth.web.support.Admin; import roomescape.auth.web.support.LoginRequired; import roomescape.common.dto.response.RoomescapeApiResponse; import roomescape.common.dto.response.RoomescapeErrorResponse; -import roomescape.reservation.web.request.ReservationTimeRequest; -import roomescape.reservation.web.response.ReservationTimeInfosResponse; -import roomescape.reservation.web.response.ReservationTimeResponse; -import roomescape.reservation.web.response.ReservationTimesResponse; import roomescape.reservation.business.ReservationTimeService; @RestController @@ -68,7 +64,7 @@ public class ReservationTimeController { HttpServletResponse response ) { ReservationTimeResponse reservationTimeResponse = reservationTimeService.addTime(reservationTimeRequest); - response.setHeader(HttpHeaders.LOCATION, "/times/" + reservationTimeResponse.id()); + response.setHeader(HttpHeaders.LOCATION, "/times/" + reservationTimeResponse.id); return RoomescapeApiResponse.success(reservationTimeResponse); } diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt b/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt new file mode 100644 index 00000000..299c727b --- /dev/null +++ b/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt @@ -0,0 +1,40 @@ +package roomescape.reservation.web + +import io.swagger.v3.oas.annotations.media.Schema +import java.time.LocalTime + +@Schema(name = "예약 시간 저장 요청", description = "예약 시간 저장 요청시 사용됩니다.") +@JvmRecord +data class ReservationTimeRequest( + @JvmField + @field:Schema(description = "예약 시간. HH:mm 형식으로 입력해야 합니다.", type = "string", example = "09:00") + val startAt: LocalTime +) + + +@Schema(name = "특정 테마, 날짜에 대한 시간 정보 응답", description = "특정 날짜와 테마에 대해, 예약 가능 여부를 포함한 시간 정보를 저장합니다.") +@JvmRecord +data class ReservationTimeInfoResponse( + @field:Schema(description = "예약 시간 번호. 예약 시간을 식별할 때 사용합니다.") + val timeId: Long, + + @field:Schema(description = "예약 시간", type = "string", example = "09:00") + val startAt: LocalTime, + + @field:Schema(description = "이미 예약이 완료된 시간인지 여부") + val alreadyBooked: Boolean +) + +@Schema(name = "예약 시간 정보 목록 응답", description = "특정 테마, 날짜에 대한 모든 예약 가능 시간 정보를 저장합니다.") +@JvmRecord +data class ReservationTimeInfosResponse( + @field:Schema(description = "특정 테마, 날짜에 대한 예약 가능 여부를 포함한 시간 목록") + val reservationTimes: List +) + +@Schema(name = "예약 시간 정보 목록 응답", description = "모든 예약 시간 조회 응답시 사용됩니다.") +@JvmRecord +data class ReservationTimesResponse( + @field:Schema(description = "모든 시간 목록") + val times: List +) diff --git a/src/main/java/roomescape/reservation/web/request/AdminReservationRequest.java b/src/main/java/roomescape/reservation/web/request/AdminReservationRequest.java deleted file mode 100644 index af07eab7..00000000 --- a/src/main/java/roomescape/reservation/web/request/AdminReservationRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package roomescape.reservation.web.request; - -import java.time.LocalDate; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(name = "관리자 예약 저장 요청", description = "관리자의 예약 저장 요청시 사용됩니다.") -public record AdminReservationRequest( - @Schema(description = "예약 날짜. 지난 날짜는 지정할 수 없으며, yyyy-MM-dd 형식으로 입력해야 합니다.", type = "string", example = "2022-12-31") - LocalDate date, - @Schema(description = "예약 시간 ID.", example = "1") - Long timeId, - @Schema(description = "테마 ID", example = "1") - Long themeId, - @Schema(description = "회원 ID", example = "1") - Long memberId -) { -} diff --git a/src/main/java/roomescape/reservation/web/request/ReservationRequest.java b/src/main/java/roomescape/reservation/web/request/ReservationRequest.java deleted file mode 100644 index 88805c05..00000000 --- a/src/main/java/roomescape/reservation/web/request/ReservationRequest.java +++ /dev/null @@ -1,36 +0,0 @@ -package roomescape.reservation.web.request; - -import java.time.LocalDate; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import roomescape.payment.web.PaymentApprove; - -@Schema(name = "회원의 예약 저장 요청", description = "회원의 예약 요청시 사용됩니다.") -public record ReservationRequest( - @NotNull(message = "예약 날짜는 null일 수 없습니다.") - @Schema(description = "예약 날짜. 지난 날짜는 지정할 수 없으며, yyyy-MM-dd 형식으로 입력해야 합니다.", type = "string", example = "2022-12-31") - LocalDate date, - @NotNull(message = "예약 요청의 timeId는 null일 수 없습니다.") - @Schema(description = "예약 시간 ID.", example = "1") - Long timeId, - @NotNull(message = "예약 요청의 themeId는 null일 수 없습니다.") - @Schema(description = "테마 ID", example = "1") - Long themeId, - @Schema(description = "결제 위젯을 통해 받은 결제 키") - String paymentKey, - @Schema(description = "결제 위젯을 통해 받은 주문번호.") - String orderId, - @Schema(description = "결제 위젯을 통해 받은 결제 금액") - Long amount, - @Schema(description = "결제 타입", example = "NORMAL") - String paymentType -) { - - @JsonIgnore - public PaymentApprove.Request getPaymentRequest() { - return new PaymentApprove.Request(paymentKey, orderId, amount, paymentType); - } -} diff --git a/src/main/java/roomescape/reservation/web/request/ReservationTimeRequest.java b/src/main/java/roomescape/reservation/web/request/ReservationTimeRequest.java deleted file mode 100644 index 74c60b84..00000000 --- a/src/main/java/roomescape/reservation/web/request/ReservationTimeRequest.java +++ /dev/null @@ -1,31 +0,0 @@ -package roomescape.reservation.web.request; - -import java.time.LocalTime; - -import org.springframework.http.HttpStatus; - -import io.micrometer.common.util.StringUtils; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import roomescape.common.exception.ErrorType; -import roomescape.common.exception.RoomescapeException; -import roomescape.reservation.infrastructure.persistence.ReservationTime; - -@Schema(name = "예약 시간 저장 요청", description = "예약 시간 저장 요청시 사용됩니다.") -public record ReservationTimeRequest( - @NotNull(message = "예약 시간은 null일 수 없습니다.") - @Schema(description = "예약 시간. HH:mm 형식으로 입력해야 합니다.", type = "string", example = "09:00") - LocalTime startAt -) { - - public ReservationTimeRequest { - if (StringUtils.isBlank(startAt.toString())) { - throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, - String.format("[values: %s]", this), HttpStatus.BAD_REQUEST); - } - } - - public ReservationTime toTime() { - return new ReservationTime(this.startAt); - } -} diff --git a/src/main/java/roomescape/reservation/web/request/WaitingRequest.java b/src/main/java/roomescape/reservation/web/request/WaitingRequest.java deleted file mode 100644 index da794d3f..00000000 --- a/src/main/java/roomescape/reservation/web/request/WaitingRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package roomescape.reservation.web.request; - -import java.time.LocalDate; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; - -@Schema(name = "예약 대기 저장 요청", description = "회원의 예약 대기 요청시 사용됩니다.") -public record WaitingRequest( - @NotNull(message = "예약 날짜는 null일 수 없습니다.") - @Schema(description = "예약 날짜. 지난 날짜는 지정할 수 없으며, yyyy-MM-dd 형식으로 입력해야 합니다.", type = "string", example = "2022-12-31") - LocalDate date, - @NotNull(message = "예약 요청의 timeId는 null일 수 없습니다.") - @Schema(description = "예약 시간 ID", example = "1") - Long timeId, - @NotNull(message = "예약 요청의 themeId는 null일 수 없습니다.") - @Schema(description = "테마 ID", example = "1") - Long themeId -) { -} diff --git a/src/main/java/roomescape/reservation/web/response/MyReservationResponse.java b/src/main/java/roomescape/reservation/web/response/MyReservationResponse.java deleted file mode 100644 index ba7dfe16..00000000 --- a/src/main/java/roomescape/reservation/web/response/MyReservationResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package roomescape.reservation.web.response; - -import java.time.LocalDate; -import java.time.LocalTime; - -import io.swagger.v3.oas.annotations.media.Schema; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; - -@Schema(name = "회원의 예약 및 대기 응답", description = "회원의 예약 및 대기 정보 응답시 사용됩니다.") -public record MyReservationResponse( - @Schema(description = "예약 번호. 예약을 식별할 때 사용합니다.") - Long id, - @Schema(description = "테마 이름") - String themeName, - @Schema(description = "예약 날짜", type = "string", example = "2022-12-31") - LocalDate date, - @Schema(description = "예약 시간", type = "string", example = "09:00") - LocalTime time, - @Schema(description = "예약 상태", type = "string") - ReservationStatus status, - @Schema(description = "예약 대기 상태일 때의 대기 순번. 확정된 예약은 0의 값을 가집니다.") - Long rank, - @Schema(description = "결제 키. 결제가 완료된 예약에만 값이 존재합니다.") - String paymentKey, - @Schema(description = "결제 금액. 결제가 완료된 예약에만 값이 존재합니다.") - Long amount -) { - - public MyReservationResponse(Long id, String themeName, LocalDate date, LocalTime time, ReservationStatus status, - Integer rank, String paymentKey, Long amount) { - this(id, themeName, date, time, status, rank.longValue(), paymentKey, amount); - } -} diff --git a/src/main/java/roomescape/reservation/web/response/MyReservationsResponse.java b/src/main/java/roomescape/reservation/web/response/MyReservationsResponse.java deleted file mode 100644 index 6d9b70e0..00000000 --- a/src/main/java/roomescape/reservation/web/response/MyReservationsResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package roomescape.reservation.web.response; - -import java.util.List; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(name = "회원의 예약 및 대기 목록 조회 응답", description = "회원의 예약 및 대기 목록 조회 응답시 사용됩니다.") -public record MyReservationsResponse( - @Schema(description = "현재 로그인한 회원의 예약 및 대기 목록") List myReservationResponses -) { -} diff --git a/src/main/java/roomescape/reservation/web/response/ReservationResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationResponse.java deleted file mode 100644 index a6aa290c..00000000 --- a/src/main/java/roomescape/reservation/web/response/ReservationResponse.java +++ /dev/null @@ -1,42 +0,0 @@ -package roomescape.reservation.web.response; - -import java.time.LocalDate; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import io.swagger.v3.oas.annotations.media.Schema; -import roomescape.member.web.MemberResponse; -import roomescape.reservation.infrastructure.persistence.Reservation; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.theme.web.ThemeResponse; - -@Schema(name = "예약 정보", description = "예약 저장 및 조회 응답에 사용됩니다.") -public record ReservationResponse( - @Schema(description = "예약 번호. 예약을 식별할 때 사용합니다.") - Long id, - @Schema(description = "예약 날짜", type = "string", example = "2022-12-31") - LocalDate date, - @JsonProperty("member") - @Schema(description = "예약한 회원 정보") - MemberResponse member, - @JsonProperty("time") - @Schema(description = "예약 시간 정보") - ReservationTimeResponse time, - @JsonProperty("theme") - @Schema(description = "예약한 테마 정보") - ThemeResponse theme, - @Schema(description = "예약 상태", type = "string") - ReservationStatus status -) { - - public static ReservationResponse from(Reservation reservation) { - return new ReservationResponse( - reservation.getId(), - reservation.getDate(), - MemberResponse.fromEntity(reservation.getMember()), - ReservationTimeResponse.from(reservation.getReservationTime()), - ThemeResponse.from(reservation.getTheme()), - reservation.getReservationStatus() - ); - } -} diff --git a/src/main/java/roomescape/reservation/web/response/ReservationTimeInfoResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationTimeInfoResponse.java deleted file mode 100644 index 6912ef81..00000000 --- a/src/main/java/roomescape/reservation/web/response/ReservationTimeInfoResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package roomescape.reservation.web.response; - -import java.time.LocalTime; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(name = "특정 테마, 날짜에 대한 시간 정보 응답", description = "특정 날짜와 테마에 대해, 예약 가능 여부를 포함한 시간 정보를 저장합니다.") -public record ReservationTimeInfoResponse( - @Schema(description = "예약 시간 번호. 예약 시간을 식별할 때 사용합니다.") - Long timeId, - @Schema(description = "예약 시간", type = "string", example = "09:00") - LocalTime startAt, - @Schema(description = "이미 예약이 완료된 시간인지 여부") - boolean alreadyBooked -) { -} diff --git a/src/main/java/roomescape/reservation/web/response/ReservationTimeInfosResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationTimeInfosResponse.java deleted file mode 100644 index 97ee2ef9..00000000 --- a/src/main/java/roomescape/reservation/web/response/ReservationTimeInfosResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package roomescape.reservation.web.response; - -import java.util.List; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(name = "예약 시간 정보 목록 응답", description = "특정 테마, 날짜에 대한 모든 예약 가능 시간 정보를 저장합니다.") -public record ReservationTimeInfosResponse( - @Schema(description = "특정 테마, 날짜에 대한 예약 가능 여부를 포함한 시간 목록") List reservationTimes -) { -} diff --git a/src/main/java/roomescape/reservation/web/response/ReservationTimeResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationTimeResponse.java deleted file mode 100644 index 8edcae24..00000000 --- a/src/main/java/roomescape/reservation/web/response/ReservationTimeResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package roomescape.reservation.web.response; - -import java.time.LocalTime; - -import io.swagger.v3.oas.annotations.media.Schema; -import roomescape.reservation.infrastructure.persistence.ReservationTime; - -@Schema(name = "예약 시간 정보", description = "예약 시간 추가 및 조회 응답시 사용됩니다.") -public record ReservationTimeResponse( - @Schema(description = "예약 시간 번호. 예약 시간을 식별할 때 사용합니다.") - Long id, - @Schema(description = "예약 시간", type = "string", example = "09:00") - LocalTime startAt -) { - - public static ReservationTimeResponse from(ReservationTime reservationTime) { - return new ReservationTimeResponse(reservationTime.getId(), reservationTime.getStartAt()); - } -} diff --git a/src/main/java/roomescape/reservation/web/response/ReservationTimesResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationTimesResponse.java deleted file mode 100644 index 196721c5..00000000 --- a/src/main/java/roomescape/reservation/web/response/ReservationTimesResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package roomescape.reservation.web.response; - -import java.util.List; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(name = "예약 시간 정보 목록 응답", description = "모든 예약 시간 조회 응답시 사용됩니다.") -public record ReservationTimesResponse( - @Schema(description = "모든 시간 목록") List times -) { -} diff --git a/src/main/java/roomescape/reservation/web/response/ReservationsResponse.java b/src/main/java/roomescape/reservation/web/response/ReservationsResponse.java deleted file mode 100644 index 1b9811b5..00000000 --- a/src/main/java/roomescape/reservation/web/response/ReservationsResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package roomescape.reservation.web.response; - -import java.util.List; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(name = "예약 목록 조회 응답", description = "모든 예약 정보 조회 응답시 사용됩니다.") -public record ReservationsResponse( - @Schema(description = "모든 예약 및 대기 목록") List reservations -) { -} diff --git a/src/main/java/roomescape/theme/web/ThemeDTO.kt b/src/main/java/roomescape/theme/web/ThemeDTO.kt index 27c4ea61..b814a43a 100644 --- a/src/main/java/roomescape/theme/web/ThemeDTO.kt +++ b/src/main/java/roomescape/theme/web/ThemeDTO.kt @@ -64,5 +64,5 @@ data class ThemesResponse( ) fun List.toResponse(): ThemesResponse = ThemesResponse( - themes = this.map { it.toResponse()} + themes = this.map { it.toResponse() } ) diff --git a/src/test/java/roomescape/auth/business/AuthServiceTest.kt b/src/test/java/roomescape/auth/business/AuthServiceTest.kt index f819ff3b..90fb95cb 100644 --- a/src/test/java/roomescape/auth/business/AuthServiceTest.kt +++ b/src/test/java/roomescape/auth/business/AuthServiceTest.kt @@ -7,15 +7,15 @@ import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk import org.springframework.data.repository.findByIdOrNull -import roomescape.util.JwtFixture -import roomescape.util.MemberFixture -import roomescape.member.business.MemberService -import roomescape.member.infrastructure.persistence.MemberEntity -import roomescape.member.infrastructure.persistence.MemberRepository import roomescape.auth.infrastructure.jwt.JwtHandler import roomescape.auth.service.AuthService import roomescape.common.exception.ErrorType import roomescape.common.exception.RoomescapeException +import roomescape.member.business.MemberService +import roomescape.member.infrastructure.persistence.MemberEntity +import roomescape.member.infrastructure.persistence.MemberRepository +import roomescape.util.JwtFixture +import roomescape.util.MemberFixture class AuthServiceTest : BehaviorSpec({ diff --git a/src/test/java/roomescape/auth/infrastructure/jwt/JwtHandlerTest.kt b/src/test/java/roomescape/auth/infrastructure/jwt/JwtHandlerTest.kt index 4626bab1..53f12279 100644 --- a/src/test/java/roomescape/auth/infrastructure/jwt/JwtHandlerTest.kt +++ b/src/test/java/roomescape/auth/infrastructure/jwt/JwtHandlerTest.kt @@ -5,9 +5,9 @@ import io.jsonwebtoken.SignatureAlgorithm import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe -import roomescape.util.JwtFixture import roomescape.common.exception.ErrorType import roomescape.common.exception.RoomescapeException +import roomescape.util.JwtFixture import java.util.* import kotlin.random.Random diff --git a/src/test/java/roomescape/payment/business/PaymentServiceTest.java b/src/test/java/roomescape/payment/business/PaymentServiceTest.java index 1731aab3..ef6a43e1 100644 --- a/src/test/java/roomescape/payment/business/PaymentServiceTest.java +++ b/src/test/java/roomescape/payment/business/PaymentServiceTest.java @@ -23,9 +23,9 @@ import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; import roomescape.payment.web.ReservationPaymentResponse; import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTime; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; @@ -56,7 +56,8 @@ class PaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); @@ -65,7 +66,7 @@ class PaymentServiceTest { ReservationPaymentResponse reservationPaymentResponse = paymentService.savePayment(paymentInfo, reservation); // then - assertThat(reservationPaymentResponse.reservation().id()).isEqualTo(reservation.getId()); + assertThat(reservationPaymentResponse.reservation().id).isEqualTo(reservation.getId()); assertThat(reservationPaymentResponse.paymentKey()).isEqualTo(paymentInfo.paymentKey); } @@ -78,7 +79,8 @@ class PaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); @@ -115,7 +117,8 @@ class PaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); diff --git a/src/test/java/roomescape/payment/infrastructure/persistence/CanceledPaymentRepositoryTest.kt b/src/test/java/roomescape/payment/infrastructure/persistence/CanceledPaymentRepositoryTest.kt index 1043a737..a764351f 100644 --- a/src/test/java/roomescape/payment/infrastructure/persistence/CanceledPaymentRepositoryTest.kt +++ b/src/test/java/roomescape/payment/infrastructure/persistence/CanceledPaymentRepositoryTest.kt @@ -11,7 +11,7 @@ import java.util.* @DataJpaTest class CanceledPaymentRepositoryTest( @Autowired val canceledPaymentRepository: CanceledPaymentRepository, -): FunSpec() { +) : FunSpec() { init { context("paymentKey로 CanceledPaymentEntity 조회") { val paymentKey = "test-payment-key" diff --git a/src/test/java/roomescape/reservation/business/ReservationServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationServiceTest.java index b5136835..c61b8dbf 100644 --- a/src/test/java/roomescape/reservation/business/ReservationServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationServiceTest.java @@ -14,22 +14,22 @@ import org.springframework.context.annotation.Import; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql.ExecutionPhase; +import roomescape.common.exception.RoomescapeException; import roomescape.member.business.MemberService; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTime; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.reservation.web.request.ReservationRequest; -import roomescape.reservation.web.request.WaitingRequest; -import roomescape.reservation.web.response.ReservationResponse; -import roomescape.common.exception.RoomescapeException; +import roomescape.reservation.web.ReservationRequest; +import roomescape.reservation.web.ReservationResponse; +import roomescape.reservation.web.WaitingRequest; +import roomescape.theme.business.ThemeService; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; -import roomescape.theme.business.ThemeService; @SpringBootTest @Sql(scripts = "/truncate.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD) @@ -53,8 +53,10 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - MemberEntity member2 = memberRepository.save(new MemberEntity(null, "name2", "email2@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member2 = memberRepository.save( + new MemberEntity(null, "name2", "email2@email.com", "password", Role.MEMBER)); LocalDate date = LocalDate.now().plusDays(1L); // when @@ -75,7 +77,8 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); LocalDate date = LocalDate.now().plusDays(1L); // when @@ -95,8 +98,10 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save( + new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); LocalDate date = LocalDate.now().plusDays(1L); // when @@ -119,7 +124,8 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); LocalDate beforeDate = LocalDate.now().minusDays(1L); // when & then @@ -136,7 +142,8 @@ class ReservationServiceTest { LocalDateTime beforeTime = LocalDateTime.now().minusHours(1L).withNano(0); ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(beforeTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); // when & then assertThatThrownBy(() -> reservationService.addReservation( @@ -180,9 +187,12 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity admin = memberRepository.save(new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); + MemberEntity admin = memberRepository.save( + new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save( + new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); reservationService.addReservation( new ReservationRequest(LocalDate.now().plusDays(1L), reservationTime.getId(), theme.getId(), @@ -193,7 +203,7 @@ class ReservationServiceTest { member1.getId()); // when & then - assertThatThrownBy(() -> reservationService.approveWaiting(waiting.id(), admin.getId())) + assertThatThrownBy(() -> reservationService.approveWaiting(waiting.id, admin.getId())) .isInstanceOf(RoomescapeException.class); } @@ -203,17 +213,19 @@ class ReservationServiceTest { // given ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity admin = memberRepository.save(new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity admin = memberRepository.save( + new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); // when ReservationResponse waiting = reservationService.addWaiting( new WaitingRequest(LocalDate.now().plusDays(1L), reservationTime.getId(), theme.getId()), member.getId()); - reservationService.approveWaiting(waiting.id(), admin.getId()); + reservationService.approveWaiting(waiting.id, admin.getId()); // then - Reservation confirmed = reservationRepository.findById(waiting.id()).get(); + Reservation confirmed = reservationRepository.findById(waiting.id).get(); assertThat(confirmed.getReservationStatus()).isEqualTo(ReservationStatus.CONFIRMED_PAYMENT_REQUIRED); } } diff --git a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java index a6c91918..0fc57aed 100644 --- a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java @@ -13,16 +13,16 @@ import org.springframework.context.annotation.Import; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql.ExecutionPhase; +import roomescape.common.exception.RoomescapeException; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTime; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.reservation.web.request.ReservationTimeRequest; -import roomescape.common.exception.RoomescapeException; +import roomescape.reservation.web.ReservationTimeRequest; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; @@ -75,7 +75,8 @@ class ReservationTimeServiceTest { ReservationTime reservationTime = reservationTimeRepository.save( new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); // when reservationRepository.save(new Reservation(localDateTime.toLocalDate(), reservationTime, theme, member, diff --git a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java index 8d321b7c..45017021 100644 --- a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java @@ -22,12 +22,12 @@ import roomescape.payment.infrastructure.persistence.PaymentRepository; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTime; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.reservation.web.request.ReservationRequest; -import roomescape.reservation.web.response.ReservationResponse; +import roomescape.reservation.web.ReservationRequest; +import roomescape.reservation.web.ReservationResponse; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; @@ -59,7 +59,8 @@ class ReservationWithPaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); ReservationRequest reservationRequest = new ReservationRequest(date, time.getId(), theme.getId(), "payment-key", "order-id", 10000L, "NORMAL"); @@ -69,7 +70,7 @@ class ReservationWithPaymentServiceTest { reservationRequest, paymentInfo, member.getId()); // then - reservationRepository.findById(reservationResponse.id()) + reservationRepository.findById(reservationResponse.id) .ifPresent(reservation -> { assertThat(reservation.getMember().getId()).isEqualTo(member.getId()); assertThat(reservation.getTheme().getId()).isEqualTo(theme.getId()); @@ -80,7 +81,7 @@ class ReservationWithPaymentServiceTest { PaymentEntity payment = paymentRepository.findByPaymentKey("payment-key"); assertThat(payment).isNotNull(); - assertThat(payment.getReservation().getId()).isEqualTo(reservationResponse.id()); + assertThat(payment.getReservation().getId()).isEqualTo(reservationResponse.id); assertThat(payment.getPaymentKey()).isEqualTo("payment-key"); assertThat(payment.getOrderId()).isEqualTo("order-id"); assertThat(payment.getTotalAmount()).isEqualTo(10000L); @@ -95,7 +96,8 @@ class ReservationWithPaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); ReservationRequest reservationRequest = new ReservationRequest(date, time.getId(), theme.getId(), "payment-key", "order-id", 10000L, "NORMAL"); @@ -105,11 +107,11 @@ class ReservationWithPaymentServiceTest { // when PaymentCancel.Request paymentCancelRequest = reservationWithPaymentService.removeReservationWithPayment( - reservationResponse.id(), member.getId()); + reservationResponse.id, member.getId()); // then assertThat(paymentCancelRequest.cancelReason).isEqualTo("고객 요청"); - assertThat(reservationRepository.findById(reservationResponse.id())).isEmpty(); + assertThat(reservationRepository.findById(reservationResponse.id)).isEmpty(); assertThat(paymentRepository.findByPaymentKey("payment-key")).isNull(); assertThat(canceledPaymentRepository.findByPaymentKey("payment-key")).isNotNull(); } @@ -123,7 +125,8 @@ class ReservationWithPaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation saved = reservationRepository.save( @@ -145,7 +148,8 @@ class ReservationWithPaymentServiceTest { LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save(new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); ReservationRequest reservationRequest = new ReservationRequest(date, time.getId(), theme.getId(), "payment-key", "order-id", 10000L, "NORMAL"); @@ -154,7 +158,7 @@ class ReservationWithPaymentServiceTest { reservationRequest, paymentInfo, member.getId()); // when - boolean result = reservationWithPaymentService.isNotPaidReservation(reservationResponse.id()); + boolean result = reservationWithPaymentService.isNotPaidReservation(reservationResponse.id); // then assertThat(result).isFalse(); diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.java b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.java index a9b75a04..4b37df53 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.java +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.java @@ -47,7 +47,8 @@ class ReservationSearchSpecificationTest { @BeforeEach void setUp() { LocalDateTime dateTime = LocalDateTime.now(); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); ReservationTime time = timeRepository.save(new ReservationTime(dateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "description", "thumbnail")); diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java index 061b0326..db467956 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java @@ -10,9 +10,9 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import roomescape.common.exception.RoomescapeException; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.Role; -import roomescape.common.exception.RoomescapeException; import roomescape.theme.infrastructure.persistence.ThemeEntity; public class ReservationTest { diff --git a/src/test/java/roomescape/reservation/web/ReservationControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationControllerTest.java index bc772916..8c7d727a 100644 --- a/src/test/java/roomescape/reservation/web/ReservationControllerTest.java +++ b/src/test/java/roomescape/reservation/web/ReservationControllerTest.java @@ -2,6 +2,7 @@ package roomescape.reservation.web; import static org.assertj.core.api.Assertions.*; import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -42,13 +43,10 @@ import roomescape.payment.infrastructure.persistence.PaymentRepository; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTime; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.reservation.web.request.AdminReservationRequest; -import roomescape.reservation.web.request.ReservationRequest; -import roomescape.reservation.web.request.WaitingRequest; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; @@ -120,12 +118,14 @@ public class ReservationControllerTest { @DisplayName("대기중인 예약을 취소한다.") void cancelWaiting() { // given - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessTokenCookie = getAccessTokenCookieByLogin("email@email.com", "password"); ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save( + new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); // when reservationRepository.save(new Reservation(LocalDate.now().plusDays(1), reservationTime, theme, member1, @@ -180,7 +180,8 @@ public class ReservationControllerTest { ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); // when reservationRepository.save( @@ -204,7 +205,8 @@ public class ReservationControllerTest { @DisplayName("예약 취소는 관리자만 할 수 있다.") void canRemoveMyReservation() { // given - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessTokenCookie = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); @@ -252,7 +254,8 @@ public class ReservationControllerTest { @DisplayName("본인의 예약이 아니더라도 관리자 권한이 있으면 예약 정보를 삭제할 수 있다.") void readReservationsSizeAfterPostAndDelete() { // given - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "admin@admin.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "admin@admin.com", "password", Role.ADMIN)); String accessTokenCookie = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); @@ -342,7 +345,8 @@ public class ReservationControllerTest { ReservationTime time1 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(18, 30))); ReservationTime time2 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(19, 30))); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.ADMIN)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.ADMIN)); String accessToken = getAccessTokenCookieByLogin("email@email.com", "password"); // when : 예약은 2개, 예약 대기는 1개 조회되어야 한다. @@ -392,7 +396,8 @@ public class ReservationControllerTest { LocalDate date = LocalDate.now().plusDays(1); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); ReservationTime time = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); Reservation saved = reservationRepository.save( new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); @@ -422,7 +427,8 @@ public class ReservationControllerTest { LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessToken = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); // when : 이전 날짜의 예약을 추가하여 결제 승인 이후 DB 저장 과정에서 예외를 발생시킨다. @@ -515,8 +521,10 @@ public class ReservationControllerTest { LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - MemberEntity member1 = memberRepository.save(new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member1 = memberRepository.save( + new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); String accessToken = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); reservationRepository.save(new Reservation(date, time, theme, member1, ReservationStatus.CONFIRMED)); @@ -541,7 +549,8 @@ public class ReservationControllerTest { LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); Reservation waiting = reservationRepository.save( @@ -586,7 +595,8 @@ public class ReservationControllerTest { LocalDate date = localDateTime.toLocalDate(); ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String adminAccessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); diff --git a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java index 3aa5883b..d809a355 100644 --- a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java +++ b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java @@ -25,9 +25,9 @@ import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTime; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; @@ -225,7 +225,8 @@ public class ReservationTimeControllerTest { ReservationTime reservationTime2 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); ReservationTime reservationTime3 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(18, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명1", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + MemberEntity member = memberRepository.save( + new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); reservationRepository.save( new Reservation(today.plusDays(1), reservationTime1, theme, member, ReservationStatus.CONFIRMED)); diff --git a/src/test/java/roomescape/util/Fixtures.kt b/src/test/java/roomescape/util/Fixtures.kt index d61b70ba..6343eab1 100644 --- a/src/test/java/roomescape/util/Fixtures.kt +++ b/src/test/java/roomescape/util/Fixtures.kt @@ -33,6 +33,7 @@ object MemberFixture { account = "admin", role = Role.ADMIN ) + fun adminLoginRequest(): LoginRequest = LoginRequest( email = admin().email, password = admin().password @@ -43,6 +44,7 @@ object MemberFixture { account = "user", role = Role.MEMBER ) + fun userLoginRequest(): LoginRequest = LoginRequest( email = user().email, password = user().password -- 2.47.2 From e885ef15d83fc2ea3071911a385dd71d98bd7e8b Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 05:01:31 +0900 Subject: [PATCH 04/40] Rename .java to .kt --- .../web/{ReservationController.java => ReservationController.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/roomescape/reservation/web/{ReservationController.java => ReservationController.kt} (100%) diff --git a/src/main/java/roomescape/reservation/web/ReservationController.java b/src/main/java/roomescape/reservation/web/ReservationController.kt similarity index 100% rename from src/main/java/roomescape/reservation/web/ReservationController.java rename to src/main/java/roomescape/reservation/web/ReservationController.kt -- 2.47.2 From eb7461e9b60be70bfbd852be75b694cf61bc64ba Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 05:01:31 +0900 Subject: [PATCH 05/40] =?UTF-8?q?refactor:=20ReservationController=20?= =?UTF-8?q?=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98=20=EB=B0=8F=20?= =?UTF-8?q?Swagger=20=EC=BD=94=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/docs/ReservationAPI.kt | 138 +++++++ .../reservation/web/ReservationController.kt | 372 +++++++----------- 2 files changed, 271 insertions(+), 239 deletions(-) create mode 100644 src/main/java/roomescape/reservation/docs/ReservationAPI.kt diff --git a/src/main/java/roomescape/reservation/docs/ReservationAPI.kt b/src/main/java/roomescape/reservation/docs/ReservationAPI.kt new file mode 100644 index 00000000..05fe2883 --- /dev/null +++ b/src/main/java/roomescape/reservation/docs/ReservationAPI.kt @@ -0,0 +1,138 @@ +package roomescape.reservation.docs + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.headers.Header +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.validation.Valid +import org.springframework.http.HttpHeaders +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestParam +import roomescape.auth.web.support.Admin +import roomescape.auth.web.support.LoginRequired +import roomescape.auth.web.support.MemberId +import roomescape.common.dto.response.CommonApiResponse +import roomescape.reservation.web.* +import java.time.LocalDate + +@Tag(name = "3. 예약 API", description = "예약 및 대기 정보를 추가 / 조회 / 삭제할 때 사용합니다.") +interface ReservationAPI { + + @Admin + @Operation(summary = "모든 예약 정보 조회", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun getAllReservations(): ResponseEntity> + + @LoginRequired + @Operation(summary = "자신의 예약 및 대기 조회", tags = ["로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun getMemberReservations( + @MemberId @Parameter(hidden = true) memberId: Long + ): ResponseEntity> + + @Admin + @Operation(summary = "관리자의 예약 검색", description = "특정 조건에 해당되는 예약 검색", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses( + ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true) + ) + fun getReservationBySearching( + @RequestParam(required = false) themeId: Long?, + @RequestParam(required = false) memberId: Long?, + @RequestParam(required = false) dateFrom: LocalDate?, + @RequestParam(required = false) dateTo: LocalDate? + ): ResponseEntity> + + @Admin + @Operation(summary = "관리자의 예약 취소", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses( + ApiResponse(responseCode = "204", description = "성공"), + ) + fun removeReservation( + @MemberId @Parameter(hidden = true) memberId: Long, + @PathVariable("id") reservationId: Long + ): ResponseEntity> + + @LoginRequired + @Operation(summary = "예약 추가", tags = ["로그인이 필요한 API"]) + @ApiResponses( + ApiResponse( + responseCode = "201", + description = "성공", + useReturnTypeSchema = true, + headers = [Header(name = HttpHeaders.LOCATION, description = "생성된 예약 정보 URL", schema = Schema(example = "/reservations/1"))] + ) + ) + fun saveReservation( + @Valid @RequestBody reservationRequest: ReservationRequest, + @MemberId @Parameter(hidden = true) memberId: Long + ): ResponseEntity> + + @Admin + @Operation(summary = "관리자 예약 추가", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses( + ApiResponse( + responseCode = "201", + description = "성공", + useReturnTypeSchema = true, + headers = [Header(name = HttpHeaders.LOCATION, description = "생성된 예약 정보 URL", schema = Schema(example = "/reservations/1"))], + ) + ) + fun saveReservationByAdmin( + @Valid @RequestBody adminReservationRequest: AdminReservationRequest, + ): ResponseEntity> + + @Admin + @Operation(summary = "모든 예약 대기 조회", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun getAllWaiting(): ResponseEntity> + + @LoginRequired + @Operation(summary = "예약 대기 신청", tags = ["로그인이 필요한 API"]) + @ApiResponses( + ApiResponse( + responseCode = "201", + description = "성공", + useReturnTypeSchema = true, + headers = [Header(name = HttpHeaders.LOCATION, description = "생성된 예약 정보 URL", schema = Schema(example = "/reservations/1"))] + ) + ) + fun saveWaiting( + @Valid @RequestBody waitingRequest: WaitingRequest, + @MemberId @Parameter(hidden = true) memberId: Long, + ): ResponseEntity> + + @LoginRequired + @Operation(summary = "예약 대기 취소", tags = ["로그인이 필요한 API"]) + @ApiResponses( + ApiResponse(responseCode = "204", description = "성공"), + ) + fun deleteWaiting( + @MemberId @Parameter(hidden = true) memberId: Long, + @PathVariable("id") @Parameter(description = "예약 ID") reservationId: Long + ): ResponseEntity> + + @Admin + @Operation(summary = "대기 중인 예약 승인", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses( + ApiResponse(responseCode = "200", description = "성공"), + ) + fun approveWaiting( + @MemberId @Parameter(hidden = true) memberId: Long, + @PathVariable("id") @Parameter(description = "예약 ID") reservationId: Long + ): ResponseEntity> + + @Admin + @Operation(summary = "대기 중인 예약 거절", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses( + ApiResponse(responseCode = "204", description = "대기 중인 예약 거절 성공"), + ) + fun denyWaiting( + @MemberId @Parameter(hidden = true) memberId: Long, + @PathVariable("id") @Parameter(description = "예약 ID") reservationId: Long + ): ResponseEntity> +} diff --git a/src/main/java/roomescape/reservation/web/ReservationController.kt b/src/main/java/roomescape/reservation/web/ReservationController.kt index 1fe53e0d..4b3d7e98 100644 --- a/src/main/java/roomescape/reservation/web/ReservationController.kt +++ b/src/main/java/roomescape/reservation/web/ReservationController.kt @@ -1,265 +1,159 @@ -package roomescape.reservation.web; +package roomescape.reservation.web -import java.time.LocalDate; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.headers.Header; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import roomescape.auth.web.support.Admin; -import roomescape.auth.web.support.LoginRequired; -import roomescape.auth.web.support.MemberId; -import roomescape.common.dto.response.RoomescapeApiResponse; -import roomescape.common.dto.response.RoomescapeErrorResponse; -import roomescape.common.exception.RoomescapeException; -import roomescape.payment.infrastructure.client.TossPaymentClient; -import roomescape.payment.web.PaymentApprove; -import roomescape.payment.web.PaymentCancel; -import roomescape.reservation.business.ReservationService; -import roomescape.reservation.business.ReservationWithPaymentService; +import io.swagger.v3.oas.annotations.Parameter +import jakarta.validation.Valid +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import roomescape.auth.web.support.MemberId +import roomescape.common.dto.response.CommonApiResponse +import roomescape.common.exception.RoomescapeException +import roomescape.payment.infrastructure.client.TossPaymentClient +import roomescape.payment.web.PaymentApprove +import roomescape.payment.web.PaymentCancel +import roomescape.reservation.business.ReservationService +import roomescape.reservation.business.ReservationWithPaymentService +import roomescape.reservation.docs.ReservationAPI +import java.net.URI +import java.time.LocalDate @RestController -@Tag(name = "3. 예약 API", description = "예약 및 대기 정보를 추가 / 조회 / 삭제할 때 사용합니다.") -public class ReservationController { +class ReservationController( + private val reservationWithPaymentService: ReservationWithPaymentService, + private val reservationService: ReservationService, + private val paymentClient: TossPaymentClient +) : ReservationAPI { + @GetMapping("/reservations") + override fun getAllReservations(): ResponseEntity> { + val response: ReservationsResponse = reservationService.findAllReservations() - private final ReservationWithPaymentService reservationWithPaymentService; - private final ReservationService reservationService; - private final TossPaymentClient paymentClient; + return ResponseEntity.ok(CommonApiResponse(response)) + } - public ReservationController(ReservationWithPaymentService reservationWithPaymentService, - ReservationService reservationService, TossPaymentClient paymentClient) { - this.reservationWithPaymentService = reservationWithPaymentService; - this.reservationService = reservationService; - this.paymentClient = paymentClient; - } + @GetMapping("/reservations-mine") + override fun getMemberReservations( + @MemberId @Parameter(hidden = true) memberId: Long + ): ResponseEntity> { + val response: MyReservationsResponse = reservationService.findMemberReservations(memberId) - @Admin - @GetMapping("/reservations") - @ResponseStatus(HttpStatus.OK) - @Operation(summary = "모든 예약 정보 조회", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true) - }) - public RoomescapeApiResponse getAllReservations() { - return RoomescapeApiResponse.success(reservationService.findAllReservations()); - } + return ResponseEntity.ok(CommonApiResponse(response)) + } - @LoginRequired - @GetMapping("/reservations-mine") - @ResponseStatus(HttpStatus.OK) - @Operation(summary = "자신의 예약 및 대기 조회", tags = "로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true) - }) - public RoomescapeApiResponse getMemberReservations( - @MemberId @Parameter(hidden = true) Long memberId) { - return RoomescapeApiResponse.success(reservationService.findMemberReservations(memberId)); - } + @GetMapping("/reservations/search") + override fun getReservationBySearching( + @RequestParam(required = false) themeId: Long?, + @RequestParam(required = false) memberId: Long?, + @RequestParam(required = false) dateFrom: LocalDate?, + @RequestParam(required = false) dateTo: LocalDate? + ): ResponseEntity> { + val response: ReservationsResponse = reservationService.findFilteredReservations(themeId, memberId, dateFrom, dateTo) - @Admin - @GetMapping("/reservations/search") - @ResponseStatus(HttpStatus.OK) - @Operation(summary = "관리자의 예약 검색", description = "특정 조건에 해당되는 예약 검색", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true), - @ApiResponse(responseCode = "400", description = "날짜 범위를 지정할 때, 종료 날짜는 시작 날짜 이전일 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))) - }) - public RoomescapeApiResponse getReservationBySearching( - @RequestParam(required = false) @Parameter(description = "테마 ID") Long themeId, - @RequestParam(required = false) @Parameter(description = "회원 ID") Long memberId, - @RequestParam(required = false) @Parameter(description = "yyyy-MM-dd 형식으로 입력해주세요", example = "2024-06-10") LocalDate dateFrom, - @RequestParam(required = false) @Parameter(description = "yyyy-MM-dd 형식으로 입력해주세요", example = "2024-06-10") LocalDate dateTo - ) { - return RoomescapeApiResponse.success( - reservationService.findFilteredReservations(themeId, memberId, dateFrom, dateTo)); - } + return ResponseEntity.ok(CommonApiResponse(response)) + } - @Admin - @DeleteMapping("/reservations/{id}") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Operation(summary = "관리자의 예약 취소", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "204", description = "성공"), - @ApiResponse(responseCode = "404", description = "예약 또는 결제 정보를 찾을 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))), - }) - public RoomescapeApiResponse removeReservation( - @MemberId @Parameter(hidden = true) Long memberId, - @NotNull(message = "reservationId는 null일 수 없습니다.") @PathVariable("id") @Parameter(description = "예약 ID") Long reservationId - ) { + @DeleteMapping("/reservations/{id}") + override fun removeReservation( + @MemberId @Parameter(hidden = true) memberId: Long, + @PathVariable("id") reservationId: Long + ): ResponseEntity> { + if (reservationWithPaymentService.isNotPaidReservation(reservationId)) { + reservationService.removeReservationById(reservationId, memberId) + return ResponseEntity.noContent().build() + } - if (reservationWithPaymentService.isNotPaidReservation(reservationId)) { - reservationService.removeReservationById(reservationId, memberId); - return RoomescapeApiResponse.success(); - } + val paymentCancelRequest = reservationWithPaymentService.removeReservationWithPayment( + reservationId, memberId) + val paymentCancelResponse = paymentClient.cancelPayment(paymentCancelRequest) + reservationWithPaymentService.updateCanceledTime(paymentCancelRequest.paymentKey, + paymentCancelResponse.canceledAt) - PaymentCancel.Request paymentCancelRequest = reservationWithPaymentService.removeReservationWithPayment( - reservationId, memberId); + return ResponseEntity.noContent().build() + } - PaymentCancel.Response paymentCancelResponse = paymentClient.cancelPayment(paymentCancelRequest); + @PostMapping("/reservations") + override fun saveReservation( + @Valid @RequestBody reservationRequest: ReservationRequest, + @MemberId @Parameter(hidden = true) memberId: Long + ): ResponseEntity> { + val paymentRequest: PaymentApprove.Request = reservationRequest.paymentRequest + val paymentResponse: PaymentApprove.Response = paymentClient.confirmPayment(paymentRequest) - reservationWithPaymentService.updateCanceledTime(paymentCancelRequest.paymentKey, - paymentCancelResponse.canceledAt); + try { + val reservationResponse: ReservationResponse = reservationWithPaymentService.addReservationWithPayment( + reservationRequest, + paymentResponse, + memberId + ) + return ResponseEntity.created(URI.create("/reservations/${reservationResponse.id}")) + .body(CommonApiResponse(reservationResponse)) + } catch (e: RoomescapeException) { + val cancelRequest = PaymentCancel.Request(paymentRequest.paymentKey, + paymentRequest.amount, e.message!!) + val paymentCancelResponse = paymentClient.cancelPayment(cancelRequest) + reservationWithPaymentService.saveCanceledPayment(paymentCancelResponse, paymentResponse.approvedAt, + paymentRequest.paymentKey) + throw e + } + } - return RoomescapeApiResponse.success(); - } + @PostMapping("/reservations/admin") + override fun saveReservationByAdmin( + @Valid @RequestBody adminReservationRequest: AdminReservationRequest + ): ResponseEntity> { + val response: ReservationResponse = + reservationService.addReservationByAdmin(adminReservationRequest) - @LoginRequired - @PostMapping("/reservations") - @ResponseStatus(HttpStatus.CREATED) - @Operation(summary = "예약 추가", tags = "로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true, - headers = @Header(name = HttpHeaders.LOCATION, description = "생성된 예약 정보 URL", schema = @Schema(example = "/reservations/1"))) - }) - public RoomescapeApiResponse saveReservation( - @Valid @RequestBody ReservationRequest reservationRequest, - @MemberId @Parameter(hidden = true) Long memberId, - HttpServletResponse response - ) { - PaymentApprove.Request paymentRequest = reservationRequest.paymentRequest(); - PaymentApprove.Response paymentResponse = paymentClient.confirmPayment(paymentRequest); + return ResponseEntity.created(URI.create("/reservations/${response.id}")) + .body(CommonApiResponse(response)) + } - try { - ReservationResponse reservationResponse = reservationWithPaymentService.addReservationWithPayment( - reservationRequest, paymentResponse, memberId); - return getCreatedReservationResponse(reservationResponse, response); - } catch (RoomescapeException e) { - PaymentCancel.Request cancelRequest = new PaymentCancel.Request(paymentRequest.paymentKey, - paymentRequest.amount, e.getMessage()); + @GetMapping("/reservations/waiting") + override fun getAllWaiting(): ResponseEntity> { + val response: ReservationsResponse = reservationService.findAllWaiting() - PaymentCancel.Response paymentCancelResponse = paymentClient.cancelPayment(cancelRequest); + return ResponseEntity.ok(CommonApiResponse(response)) + } - reservationWithPaymentService.saveCanceledPayment(paymentCancelResponse, paymentResponse.approvedAt, - paymentRequest.paymentKey); - throw e; - } - } + @PostMapping("/reservations/waiting") + override fun saveWaiting( + @Valid @RequestBody waitingRequest: WaitingRequest, + @MemberId @Parameter(hidden = true) memberId: Long, + ): ResponseEntity> { + val response: ReservationResponse = reservationService.addWaiting( + waitingRequest, + memberId + ) - @Admin - @PostMapping("/reservations/admin") - @ResponseStatus(HttpStatus.CREATED) - @Operation(summary = "관리자 예약 추가", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true, - headers = @Header(name = HttpHeaders.LOCATION, description = "생성된 예약 정보 URL", schema = @Schema(example = "/reservations/1"))), - @ApiResponse(responseCode = "409", description = "예약이 이미 존재합니다.", content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))) - }) - public RoomescapeApiResponse saveReservationByAdmin( - @Valid @RequestBody AdminReservationRequest adminReservationRequest, - HttpServletResponse response - ) { - ReservationResponse reservationResponse = reservationService.addReservationByAdmin(adminReservationRequest); - return getCreatedReservationResponse(reservationResponse, response); - } + return ResponseEntity.created(URI.create("/reservations/${response.id}")) + .body(CommonApiResponse(response)) + } - @Admin - @GetMapping("/reservations/waiting") - @ResponseStatus(HttpStatus.OK) - @Operation(summary = "모든 예약 대기 조회", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true) - }) - public RoomescapeApiResponse getAllWaiting() { - return RoomescapeApiResponse.success(reservationService.findAllWaiting()); - } + @DeleteMapping("/reservations/waiting/{id}") + override fun deleteWaiting( + @MemberId @Parameter(hidden = true) memberId: Long, + @PathVariable("id") reservationId: Long + ): ResponseEntity> { + reservationService.cancelWaiting(reservationId, memberId) - @LoginRequired - @PostMapping("/reservations/waiting") - @ResponseStatus(HttpStatus.CREATED) - @Operation(summary = "예약 대기 신청", tags = "로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true, - headers = @Header(name = HttpHeaders.LOCATION, description = "생성된 예약 정보 URL", schema = @Schema(example = "/reservations/1"))) - }) - public RoomescapeApiResponse saveWaiting( - @Valid @RequestBody WaitingRequest waitingRequest, - @MemberId @Parameter(hidden = true) Long memberId, - HttpServletResponse response - ) { - ReservationResponse reservationResponse = reservationService.addWaiting(waitingRequest, memberId); - return getCreatedReservationResponse(reservationResponse, response); - } + return ResponseEntity.noContent().build() + } - @LoginRequired - @DeleteMapping("/reservations/waiting/{id}") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Operation(summary = "예약 대기 취소", tags = "로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "204", description = "성공"), - @ApiResponse(responseCode = "404", description = "회원의 예약 대기 정보를 찾을 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))) - }) - public RoomescapeApiResponse deleteWaiting( - @MemberId @Parameter(hidden = true) Long memberId, - @NotNull(message = "reservationId는 null 또는 공백일 수 없습니다.") @PathVariable("id") @Parameter(description = "예약 ID") Long reservationId - ) { - reservationService.cancelWaiting(reservationId, memberId); - return RoomescapeApiResponse.success(); - } + @PostMapping("/reservations/waiting/{id}/approve") + override fun approveWaiting( + @MemberId @Parameter(hidden = true) memberId: Long, + @PathVariable("id") reservationId: Long + ): ResponseEntity> { + reservationService.approveWaiting(reservationId, memberId) - @Admin - @PostMapping("/reservations/waiting/{id}/approve") - @ResponseStatus(HttpStatus.OK) - @Operation(summary = "대기 중인 예약 승인", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "성공"), - @ApiResponse(responseCode = "404", description = "예약 대기 정보를 찾을 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))), - @ApiResponse(responseCode = "409", description = "확정된 예약이 존재하여 대기 중인 예약을 승인할 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))) - }) - public RoomescapeApiResponse approveWaiting( - @MemberId @Parameter(hidden = true) Long memberId, - @NotNull(message = "reservationId는 null 또는 공백일 수 없습니다.") @PathVariable("id") @Parameter(description = "예약 ID") Long reservationId - ) { - reservationService.approveWaiting(reservationId, memberId); + return ResponseEntity.ok().build() + } - return RoomescapeApiResponse.success(); - } + @PostMapping("/reservations/waiting/{id}/deny") + override fun denyWaiting( + @MemberId @Parameter(hidden = true) memberId: Long, + @PathVariable("id") reservationId: Long + ): ResponseEntity> { + reservationService.denyWaiting(reservationId, memberId) - @Admin - @PostMapping("/reservations/waiting/{id}/deny") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Operation(summary = "대기 중인 예약 거절", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "204", description = "대기 중인 예약 거절 성공"), - @ApiResponse(responseCode = "404", description = "예약 대기 정보를 찾을 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))) - }) - public RoomescapeApiResponse denyWaiting( - @MemberId @Parameter(hidden = true) Long memberId, - @NotNull(message = "reservationId는 null 또는 공백일 수 없습니다.") @PathVariable("id") @Parameter(description = "예약 ID") Long reservationId - ) { - reservationService.denyWaiting(reservationId, memberId); - - return RoomescapeApiResponse.success(); - } - - private RoomescapeApiResponse getCreatedReservationResponse( - ReservationResponse reservationResponse, - HttpServletResponse response - ) { - response.setHeader(HttpHeaders.LOCATION, "/reservations/" + reservationResponse.id); - return RoomescapeApiResponse.success(reservationResponse); - } + return ResponseEntity.noContent().build() + } } -- 2.47.2 From 9f86edfc20015155d49e49506eb6fa224f0f4991 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 05:09:04 +0900 Subject: [PATCH 06/40] Rename .java to .kt --- ...eservationTimeController.java => ReservationTimeController.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/roomescape/reservation/web/{ReservationTimeController.java => ReservationTimeController.kt} (100%) diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeController.java b/src/main/java/roomescape/reservation/web/ReservationTimeController.kt similarity index 100% rename from src/main/java/roomescape/reservation/web/ReservationTimeController.java rename to src/main/java/roomescape/reservation/web/ReservationTimeController.kt -- 2.47.2 From 6d4d2c0ade1818d61ac3b76cbd10ee0b8a674ca5 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 05:09:04 +0900 Subject: [PATCH 07/40] =?UTF-8?q?refactor:=20ReservationTimeController=20?= =?UTF-8?q?=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98=20=EB=B0=8F=20?= =?UTF-8?q?Swagger=20=EC=BD=94=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/docs/ReservationTimeAPI.kt | 58 +++++++ .../web/ReservationTimeController.kt | 150 +++++++----------- 2 files changed, 112 insertions(+), 96 deletions(-) create mode 100644 src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt diff --git a/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt b/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt new file mode 100644 index 00000000..5ed33cea --- /dev/null +++ b/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt @@ -0,0 +1,58 @@ +package roomescape.reservation.docs + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.servlet.http.HttpServletResponse +import jakarta.validation.Valid +import jakarta.validation.constraints.NotNull +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import roomescape.auth.web.support.Admin +import roomescape.auth.web.support.LoginRequired +import roomescape.common.dto.response.CommonApiResponse +import roomescape.common.dto.response.RoomescapeApiResponse +import roomescape.common.dto.response.RoomescapeApiResponse.Companion.success +import roomescape.common.dto.response.RoomescapeErrorResponse +import roomescape.reservation.web.ReservationTimeInfosResponse +import roomescape.reservation.web.ReservationTimeRequest +import roomescape.reservation.web.ReservationTimeResponse +import roomescape.reservation.web.ReservationTimesResponse +import java.time.LocalDate + +@Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.") +interface ReservationTimeAPI { + + @Admin + @Operation(summary = "모든 시간 조회", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun getAllTimes(): ResponseEntity> + + @Admin + @Operation(summary = "시간 추가", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true)) + fun saveTime( + @Valid @RequestBody reservationTimeRequest: ReservationTimeRequest, + ): ResponseEntity> + + @Admin + @Operation(summary = "시간 삭제", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true)) + fun removeTime( + @PathVariable id: Long + ): ResponseEntity> + + @LoginRequired + @Operation(summary = "예약 가능 여부를 포함한 모든 시간 조회", tags = ["로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun findAllAvailableReservationTimes( + @RequestParam date: LocalDate, + @RequestParam themeId: Long + ): ResponseEntity> +} diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeController.kt b/src/main/java/roomescape/reservation/web/ReservationTimeController.kt index 389a182e..5ccb18e3 100644 --- a/src/main/java/roomescape/reservation/web/ReservationTimeController.kt +++ b/src/main/java/roomescape/reservation/web/ReservationTimeController.kt @@ -1,108 +1,66 @@ -package roomescape.reservation.web; +package roomescape.reservation.web -import java.time.LocalDate; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import roomescape.auth.web.support.Admin; -import roomescape.auth.web.support.LoginRequired; -import roomescape.common.dto.response.RoomescapeApiResponse; -import roomescape.common.dto.response.RoomescapeErrorResponse; -import roomescape.reservation.business.ReservationTimeService; +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import jakarta.servlet.http.HttpServletResponse +import jakarta.validation.Valid +import jakarta.validation.constraints.NotNull +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import roomescape.auth.web.support.Admin +import roomescape.auth.web.support.LoginRequired +import roomescape.common.dto.response.CommonApiResponse +import roomescape.common.dto.response.RoomescapeApiResponse +import roomescape.common.dto.response.RoomescapeApiResponse.Companion.success +import roomescape.common.dto.response.RoomescapeErrorResponse +import roomescape.reservation.business.ReservationTimeService +import roomescape.reservation.docs.ReservationTimeAPI +import java.net.URI +import java.time.LocalDate @RestController -@Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.") -public class ReservationTimeController { +class ReservationTimeController( + private val reservationTimeService: ReservationTimeService +) : ReservationTimeAPI { - private final ReservationTimeService reservationTimeService; + @GetMapping("/times") + override fun getAllTimes(): ResponseEntity> { + val response: ReservationTimesResponse = reservationTimeService.findAllTimes() - public ReservationTimeController(ReservationTimeService reservationTimeService) { - this.reservationTimeService = reservationTimeService; - } + return ResponseEntity.ok(CommonApiResponse(response)) + } - @Admin - @GetMapping("/times") - @ResponseStatus(HttpStatus.OK) - @Operation(summary = "모든 시간 조회", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true) - }) - public RoomescapeApiResponse getAllTimes() { - return RoomescapeApiResponse.success(reservationTimeService.findAllTimes()); - } + @PostMapping("/times") + override fun saveTime( + @Valid @RequestBody reservationTimeRequest: ReservationTimeRequest, + ): ResponseEntity> { + val response: ReservationTimeResponse = reservationTimeService.addTime(reservationTimeRequest) - @Admin - @PostMapping("/times") - @ResponseStatus(HttpStatus.CREATED) - @Operation(summary = "시간 추가", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true), - @ApiResponse(responseCode = "409", description = "같은 시간을 추가할 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))) - }) - public RoomescapeApiResponse saveTime( - @Valid @RequestBody ReservationTimeRequest reservationTimeRequest, - HttpServletResponse response - ) { - ReservationTimeResponse reservationTimeResponse = reservationTimeService.addTime(reservationTimeRequest); - response.setHeader(HttpHeaders.LOCATION, "/times/" + reservationTimeResponse.id); + return ResponseEntity + .created(URI.create("/times/${response.id}")) + .body(CommonApiResponse(response)) + } - return RoomescapeApiResponse.success(reservationTimeResponse); - } + @DeleteMapping("/times/{id}") + override fun removeTime(@PathVariable id: Long): ResponseEntity> { + reservationTimeService.removeTimeById(id) - @Admin - @DeleteMapping("/times/{id}") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Operation(summary = "시간 삭제", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true), - @ApiResponse(responseCode = "409", description = "예약된 시간은 삭제할 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))) - }) - public RoomescapeApiResponse removeTime( - @NotNull(message = "timeId는 null 또는 공백일 수 없습니다.") @PathVariable @Parameter(description = "삭제하고자 하는 시간의 ID값") Long id - ) { - reservationTimeService.removeTimeById(id); + return ResponseEntity.noContent().build() + } - return RoomescapeApiResponse.success(); - } + @GetMapping("/times/filter") + override fun findAllAvailableReservationTimes( + @RequestParam date: LocalDate, + @RequestParam themeId: Long + ): ResponseEntity> { + val response: ReservationTimeInfosResponse = reservationTimeService.findAllAvailableTimesByDateAndTheme(date, themeId) - @LoginRequired - @GetMapping("/times/filter") - @ResponseStatus(HttpStatus.OK) - @Operation(summary = "예약 가능 여부를 포함한 모든 시간 조회", tags = "로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true) - }) - public RoomescapeApiResponse findAllAvailableReservationTimes( - @NotNull(message = "날짜는 null일 수 없습니다.") - @RequestParam - @Parameter(description = "yyyy-MM-dd 형식으로 입력해주세요.", example = "2024-06-10") - LocalDate date, - @NotNull(message = "themeId는 null일 수 없습니다.") - @RequestParam - @Parameter(description = "조회할 테마의 ID를 입력해주세요.", example = "1") - Long themeId - ) { - return RoomescapeApiResponse.success(reservationTimeService.findAllAvailableTimesByDateAndTheme(date, themeId)); - } + return ResponseEntity.ok(CommonApiResponse(response)) + } } -- 2.47.2 From b20220794c6c92075ed62dce93a22f35b4617672 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 06:02:58 +0900 Subject: [PATCH 08/40] Rename .java to .kt --- ...SearchSpecification.java => ReservationSearchSpecification.kt} | 0 ...ecificationTest.java => ReservationSearchSpecificationTest.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/roomescape/reservation/infrastructure/persistence/{ReservationSearchSpecification.java => ReservationSearchSpecification.kt} (100%) rename src/test/java/roomescape/reservation/infrastructure/persistence/{ReservationSearchSpecificationTest.java => ReservationSearchSpecificationTest.kt} (100%) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt similarity index 100% rename from src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.java b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt similarity index 100% rename from src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.java rename to src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt -- 2.47.2 From 5a919eb3ab52010a2a9e80472627563d38ef52ad Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 06:02:59 +0900 Subject: [PATCH 09/40] =?UTF-8?q?refactor:=20ReservationSearchSpecificatio?= =?UTF-8?q?n=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReservationSearchSpecification.kt | 135 ++++----- .../ReservationSearchSpecificationTest.kt | 284 +++++++++--------- .../theme/util/TestThemeCreateUtil.kt | 2 +- src/test/java/roomescape/util/Fixtures.kt | 4 +- 4 files changed, 211 insertions(+), 214 deletions(-) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt index 888d62f2..8bd9c6bf 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt @@ -1,84 +1,75 @@ -package roomescape.reservation.infrastructure.persistence; +package roomescape.reservation.infrastructure.persistence -import java.time.LocalDate; +import org.springframework.data.jpa.domain.Specification +import roomescape.member.infrastructure.persistence.MemberEntity +import roomescape.theme.infrastructure.persistence.ThemeEntity +import java.time.LocalDate -import org.springframework.data.jpa.domain.Specification; +class ReservationSearchSpecification( + private var spec: Specification = Specification { _, _, _ -> null } +) { + fun sameThemeId(themeId: Long?): ReservationSearchSpecification = andIfNotNull(themeId?.let { + Specification { root, _, cb -> + cb.equal(root.get("theme").get("id"), themeId) + } + }) -public class ReservationSearchSpecification { + fun sameMemberId(memberId: Long?): ReservationSearchSpecification = andIfNotNull(memberId?.let { + Specification { root, _, cb -> + cb.equal(root.get("member").get("id"), memberId) + } + }) - private Specification spec; + fun sameTimeId(timeId: Long?): ReservationSearchSpecification = andIfNotNull(timeId?.let { + Specification { root, _, cb -> + cb.equal(root.get("reservationTime").get("id"), timeId) + } + }) - public ReservationSearchSpecification() { - this.spec = Specification.where(null); - } + fun sameDate(date: LocalDate?): ReservationSearchSpecification = andIfNotNull(date?.let { + Specification { root, _, cb -> + cb.equal(root.get("date"), date) + } + }) - public ReservationSearchSpecification sameThemeId(Long themeId) { - if (themeId != null) { - this.spec = this.spec.and( - (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("theme").get("id"), themeId)); - } - return this; - } + fun confirmed(): ReservationSearchSpecification = andIfNotNull { root, _, cb -> + cb.or( + cb.equal( + root.get("reservationStatus"), + ReservationStatus.CONFIRMED + ), + cb.equal( + root.get("reservationStatus"), + ReservationStatus.CONFIRMED_PAYMENT_REQUIRED + ) + ) + } - public ReservationSearchSpecification sameMemberId(Long memberId) { - if (memberId != null) { - this.spec = this.spec.and( - (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("member").get("id"), memberId)); - } - return this; - } + fun waiting(): ReservationSearchSpecification = andIfNotNull { root, _, cb -> + cb.equal( + root.get("reservationStatus"), + ReservationStatus.WAITING + ) + } - public ReservationSearchSpecification sameTimeId(Long timeId) { - if (timeId != null) { - this.spec = this.spec.and( - (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("reservationTime").get("id"), - timeId)); - } - return this; - } + fun dateStartFrom(dateFrom: LocalDate?): ReservationSearchSpecification = andIfNotNull(dateFrom?.let { + Specification { root, _, cb -> + cb.greaterThanOrEqualTo(root.get("date"), dateFrom) + } + }) - public ReservationSearchSpecification sameDate(LocalDate date) { - if (date != null) { - this.spec = this.spec.and( - (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("date"), date)); - } - return this; - } + fun dateEndAt(dateTo: LocalDate?): ReservationSearchSpecification = andIfNotNull(dateTo?.let { + Specification { root, _, cb -> + cb.lessThanOrEqualTo(root.get("date"), dateTo) + } + }) - public ReservationSearchSpecification confirmed() { - this.spec = this.spec.and( - (root, query, criteriaBuilder) -> criteriaBuilder.or( - criteriaBuilder.equal(root.get("reservationStatus"), ReservationStatus.CONFIRMED), - criteriaBuilder.equal(root.get("reservationStatus"), - ReservationStatus.CONFIRMED_PAYMENT_REQUIRED) - )); - return this; - } + fun build(): Specification { + return this.spec + } - public ReservationSearchSpecification waiting() { - this.spec = this.spec.and( - (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("reservationStatus"), - ReservationStatus.WAITING)); - return this; - } - - public ReservationSearchSpecification dateStartFrom(LocalDate dateFrom) { - if (dateFrom != null) { - this.spec = this.spec.and( - (root, query, criteriaBuilder) -> criteriaBuilder.greaterThanOrEqualTo(root.get("date"), dateFrom)); - } - return this; - } - - public ReservationSearchSpecification dateEndAt(LocalDate toDate) { - if (toDate != null) { - this.spec = this.spec.and( - (root, query, criteriaBuilder) -> criteriaBuilder.lessThanOrEqualTo(root.get("date"), toDate)); - } - return this; - } - - public Specification build() { - return this.spec; - } + private fun andIfNotNull(condition: Specification?): ReservationSearchSpecification { + condition?.let { this.spec = this.spec.and(condition) } + return this + } } diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt index 4b37df53..be918324 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt @@ -1,173 +1,179 @@ -package roomescape.reservation.infrastructure.persistence; +package roomescape.reservation.infrastructure.persistence -import static org.assertj.core.api.Assertions.*; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.data.jpa.domain.Specification; - -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.member.infrastructure.persistence.MemberRepository; -import roomescape.member.infrastructure.persistence.Role; -import roomescape.theme.infrastructure.persistence.ThemeEntity; -import roomescape.theme.infrastructure.persistence.ThemeRepository; +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.collections.shouldHaveSize +import jakarta.persistence.EntityManager +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +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.ThemeFixture +import java.time.LocalDate @DataJpaTest -class ReservationSearchSpecificationTest { +class ReservationSearchSpecificationTest( + val entityManager: EntityManager, + val reservationRepository: ReservationRepository +) : StringSpec() { - @Autowired - private ReservationRepository reservationRepository; + init { + lateinit var confirmedNow: Reservation + lateinit var confirmedNotPaidYesterday: Reservation + lateinit var waitingTomorrow: Reservation + lateinit var member: MemberEntity + lateinit var reservationTime: ReservationTime + lateinit var theme: ThemeEntity - @Autowired - private ReservationTimeRepository timeRepository; + "동일한 테마의 예약을 조회한다" { + val spec = ReservationSearchSpecification() + .sameThemeId(theme.id) + .build() - @Autowired - private ThemeRepository themeRepository; + val results: List = reservationRepository.findAll(spec) - @Autowired - private MemberRepository memberRepository; + assertSoftly(results) { + this shouldHaveSize 3 + this shouldContainExactly listOf(confirmedNow, confirmedNotPaidYesterday, waitingTomorrow) + } + } - /** - * 시간은 모두 현재 시간(LocalTime.now()), 테마, 회원은 동일 확정된 예약은 오늘, 결제 대기인 예약은 어제, 대기 상태인 예약은 내일 - */ - // 현재 시간으로 확정 예약 - private Reservation reservation1; - // 확정되었으나 결제 대기인 하루 전 예약 - private Reservation reservation2; - // 대기 상태인 내일 예약 - private Reservation reservation3; + "동일한 회원의 예약을 조회한다" { + val spec = ReservationSearchSpecification() + .sameMemberId(member.id) + .build() - @BeforeEach - void setUp() { - LocalDateTime dateTime = LocalDateTime.now(); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - ReservationTime time = timeRepository.save(new ReservationTime(dateTime.toLocalTime())); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "description", "thumbnail")); + val results: List = reservationRepository.findAll(spec) - reservation1 = reservationRepository.save( - new Reservation(dateTime.toLocalDate(), time, theme, member, ReservationStatus.CONFIRMED)); - reservation2 = reservationRepository.save( - new Reservation(dateTime.toLocalDate().minusDays(1), time, theme, member, - ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); - reservation3 = reservationRepository.save( - new Reservation(dateTime.toLocalDate().plusDays(1), time, theme, member, ReservationStatus.WAITING)); - } + assertSoftly(results) { + this shouldHaveSize 3 + this shouldContainExactly listOf(confirmedNow, confirmedNotPaidYesterday, waitingTomorrow) + } + } - @Test - @DisplayName("동일한 테마의 예약을 찾는다.") - void searchByThemeId() { - // given - Long themeId = reservation1.getTheme().getId(); - Specification spec = new ReservationSearchSpecification().sameThemeId(themeId).build(); + "동일한 예약 시간의 예약을 조회한다" { + val spec = ReservationSearchSpecification() + .sameTimeId(reservationTime.id) + .build() - // when - List found = reservationRepository.findAll(spec); + val results: List = reservationRepository.findAll(spec) - // then - assertThat(found).containsExactly(reservation1, reservation2, reservation3); - } + assertSoftly(results) { + this shouldHaveSize 3 + this shouldContainExactly listOf(confirmedNow, confirmedNotPaidYesterday, waitingTomorrow) + } + } - @Test - @DisplayName("동일한 회원의 예약을 찾는다.") - void searchByMemberId() { - // given - Long memberId = reservation1.getMember().getId(); - Specification spec = new ReservationSearchSpecification().sameMemberId(memberId).build(); + "동일한 날짜의 예약을 조회한다" { + val spec = ReservationSearchSpecification() + .sameDate(LocalDate.now()) + .build() - // when - List found = reservationRepository.findAll(spec); + val results: List = reservationRepository.findAll(spec) - // then - assertThat(found).containsExactly(reservation1, reservation2, reservation3); - } + assertSoftly(results) { + this shouldHaveSize 1 + this shouldContainExactly listOf(confirmedNow) + } + } - @Test - @DisplayName("동일한 시간의 예약을 찾는다.") - void searchByTimeId() { - // given - Long timeId = reservation1.getReservationTime().getId(); - Specification spec = new ReservationSearchSpecification().sameTimeId(timeId).build(); + "확정 상태인 예약을 조회한다" { + val spec = ReservationSearchSpecification() + .confirmed() + .build() - // when - List found = reservationRepository.findAll(spec); + val results: List = reservationRepository.findAll(spec) - // then - assertThat(found).containsExactly(reservation1, reservation2, reservation3); - } + assertSoftly(results) { + this shouldHaveSize 2 + this shouldContainExactly listOf(confirmedNow, confirmedNotPaidYesterday) + } + } - @Test - @DisplayName("동일한 날짜의 예약을 찾는다.") - void searchByDate() { - // given - LocalDate date = reservation1.getDate(); - Specification spec = new ReservationSearchSpecification().sameDate(date).build(); + "대기 상태인 예약을 조회한다" { + val spec = ReservationSearchSpecification() + .waiting() + .build() - // when - List found = reservationRepository.findAll(spec); + val results: List = reservationRepository.findAll(spec) - // then - assertThat(found).containsExactly(reservation1); - } + assertSoftly(results) { + this shouldHaveSize 1 + this shouldContainExactly listOf(waitingTomorrow) + } + } - @Test - @DisplayName("확정 상태인 예약을 찾는다.") - void searchConfirmedReservation() { - // given - Specification spec = new ReservationSearchSpecification().confirmed().build(); + "예약 날짜가 오늘 이후인 예약을 조회한다" { + val spec = ReservationSearchSpecification() + .dateStartFrom(LocalDate.now()) + .build() - // when - List found = reservationRepository.findAll(spec); + val results: List = reservationRepository.findAll(spec) - // then - assertThat(found).containsExactly(reservation1, reservation2); - } + assertSoftly(results) { + this shouldHaveSize 2 + this shouldContainExactly listOf(confirmedNow, waitingTomorrow) + } + } - @Test - @DisplayName("대기 중인 예약을 찾는다.") - void searchWaitingReservation() { - // given - Specification spec = new ReservationSearchSpecification().waiting().build(); + "예약 날짜가 내일 이전인 예약을 조회한다" { + val spec = ReservationSearchSpecification() + .dateEndAt(LocalDate.now().plusDays(1)) + .build() - // when - List found = reservationRepository.findAll(spec); + val results: List = reservationRepository.findAll(spec) - // then - assertThat(found).containsExactly(reservation3); - } + assertSoftly(results) { + this shouldHaveSize 3 + this shouldContainExactly listOf(confirmedNow, confirmedNotPaidYesterday, waitingTomorrow) + } + } - @Test - @DisplayName("특정 날짜 이후의 예약을 찾는다.") - void searchDateStartFrom() { - // given : 어제 이후의 예약을 조회하면, 모든 예약이 조회되어야 한다. - LocalDate date = LocalDate.now().minusDays(1L); - Specification spec = new ReservationSearchSpecification().dateStartFrom(date).build(); + beforeTest { + member = MemberFixture.create().also { + entityManager.persist(it) + } + reservationTime = ReservationTimeFixture.create().also { + entityManager.persist(it) + } + theme = ThemeFixture.create().also { + entityManager.persist(it) + } - // when - List found = reservationRepository.findAll(spec); + confirmedNow = ReservationFixture.create( + reservationTime = reservationTime, + member = member, + theme = theme, + date = LocalDate.now(), + status = ReservationStatus.CONFIRMED + ).also { + entityManager.persist(it) + } - // then - assertThat(found).containsExactly(reservation1, reservation2, reservation3); - } + confirmedNotPaidYesterday = ReservationFixture.create( + reservationTime = reservationTime, + member = member, + theme = theme, + date = LocalDate.now().minusDays(1), + status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED + ).also { + entityManager.persist(it) + } - @Test - @DisplayName("특정 날짜 이전의 예약을 찾는다.") - void searchDateEndAt() { - // given : 내일 이전의 예약을 조회하면, 모든 예약이 조회되어야 한다. - LocalDate date = LocalDate.now().plusDays(1L); - Specification spec = new ReservationSearchSpecification().dateEndAt(date).build(); + waitingTomorrow = ReservationFixture.create( + reservationTime = reservationTime, + member = member, + theme = theme, + date = LocalDate.now().plusDays(1), + status = ReservationStatus.WAITING + ).also { + entityManager.persist(it) + } - // when - List found = reservationRepository.findAll(spec); - - // then - assertThat(found).containsExactly(reservation1, reservation2, reservation3); - } + entityManager.flush() + } + } } diff --git a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt index c3765df7..33756ae6 100644 --- a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt +++ b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt @@ -29,7 +29,7 @@ object TestThemeCreateUtil { ReservationFixture.create( date = date, - themeEntity = themeEntity, + theme = themeEntity, member = member, reservationTime = time, status = ReservationStatus.CONFIRMED diff --git a/src/test/java/roomescape/util/Fixtures.kt b/src/test/java/roomescape/util/Fixtures.kt index 6343eab1..07aca7c2 100644 --- a/src/test/java/roomescape/util/Fixtures.kt +++ b/src/test/java/roomescape/util/Fixtures.kt @@ -71,11 +71,11 @@ object ReservationFixture { fun create( id: Long? = null, date: LocalDate = LocalDate.now().plusWeeks(1), - themeEntity: ThemeEntity = ThemeFixture.create(), + theme: ThemeEntity = ThemeFixture.create(), reservationTime: ReservationTime = ReservationTimeFixture.create(), member: MemberEntity = MemberFixture.create(), status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED - ): Reservation = Reservation(id, date, reservationTime, themeEntity, member, status) + ): Reservation = Reservation(id, date, reservationTime, theme, member, status) } object JwtFixture { -- 2.47.2 From ceed888d5c250024eab040b961b05b7d9a3bc78e Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 15:48:42 +0900 Subject: [PATCH 10/40] Rename .java to .kt --- .../{ReservationTime.java => ReservationTimeEntity.kt} | 0 ...eservationTimeRepository.java => ReservationTimeRepository.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/roomescape/reservation/infrastructure/persistence/{ReservationTime.java => ReservationTimeEntity.kt} (100%) rename src/main/java/roomescape/reservation/infrastructure/persistence/{ReservationTimeRepository.java => ReservationTimeRepository.kt} (100%) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTime.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeEntity.kt similarity index 100% rename from src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTime.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeEntity.kt diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt similarity index 100% rename from src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt -- 2.47.2 From 2241f38b77602572c0fff35f1cf927ba0a91c35e Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 15:48:42 +0900 Subject: [PATCH 11/40] =?UTF-8?q?refactor:=20ReservationTime=20=EB=B0=8F?= =?UTF-8?q?=20Repository=20=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84?= =?UTF-8?q?=ED=99=98=20=EB=B0=8F=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95(->=20ReservationTimeEntity)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/ReservationService.java | 6 +- .../business/ReservationTimeService.java | 16 ++--- .../persistence/Reservation.java | 12 ++-- .../persistence/ReservationRepository.java | 2 +- .../ReservationSearchSpecification.kt | 2 +- .../persistence/ReservationTimeEntity.kt | 66 +++---------------- .../persistence/ReservationTimeRepository.kt | 13 ++-- .../reservation/web/ReservationResponse.kt | 6 +- .../payment/business/PaymentServiceTest.java | 8 +-- .../business/ReservationServiceTest.java | 26 +++++--- .../business/ReservationTimeServiceTest.java | 10 +-- .../ReservationWithPaymentServiceTest.java | 10 +-- .../ReservationSearchSpecificationTest.kt | 2 +- .../persistence/ReservationTest.java | 8 +-- .../persistence/ReservationTimeTest.java | 19 ------ .../web/ReservationControllerTest.java | 49 +++++++++----- .../web/ReservationTimeControllerTest.java | 8 +-- .../theme/util/TestThemeCreateUtil.kt | 4 +- src/test/java/roomescape/util/Fixtures.kt | 6 +- 19 files changed, 114 insertions(+), 159 deletions(-) delete mode 100644 src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeTest.java diff --git a/src/main/java/roomescape/reservation/business/ReservationService.java b/src/main/java/roomescape/reservation/business/ReservationService.java index 4f8d0933..fc1747d5 100644 --- a/src/main/java/roomescape/reservation/business/ReservationService.java +++ b/src/main/java/roomescape/reservation/business/ReservationService.java @@ -17,7 +17,7 @@ import roomescape.reservation.infrastructure.persistence.Reservation; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationSearchSpecification; import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.web.AdminReservationRequest; import roomescape.reservation.web.MyReservationsResponse; import roomescape.reservation.web.ReservationRequest; @@ -130,7 +130,7 @@ public class ReservationService { private void validateDateAndTime( LocalDate requestDate, - ReservationTime requestReservationTime + ReservationTimeEntity requestReservationTime ) { LocalDateTime now = LocalDateTime.now(); LocalDateTime request = LocalDateTime.of(requestDate, requestReservationTime.getStartAt()); @@ -145,7 +145,7 @@ public class ReservationService { private Reservation getReservationForSave(Long timeId, Long themeId, LocalDate date, Long memberId, ReservationStatus status) { - ReservationTime time = reservationTimeService.findTimeById(timeId); + ReservationTimeEntity time = reservationTimeService.findTimeById(timeId); ThemeEntity theme = themeService.findThemeById(themeId); MemberEntity member = memberService.findById(memberId); diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.java b/src/main/java/roomescape/reservation/business/ReservationTimeService.java index f0062ef5..21c77a7a 100644 --- a/src/main/java/roomescape/reservation/business/ReservationTimeService.java +++ b/src/main/java/roomescape/reservation/business/ReservationTimeService.java @@ -11,7 +11,7 @@ import roomescape.common.exception.ErrorType; import roomescape.common.exception.RoomescapeException; import roomescape.reservation.infrastructure.persistence.Reservation; import roomescape.reservation.infrastructure.persistence.ReservationRepository; -import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.reservation.web.ReservationTimeInfoResponse; import roomescape.reservation.web.ReservationTimeInfosResponse; @@ -35,7 +35,7 @@ public class ReservationTimeService { } @Transactional(readOnly = true) - public ReservationTime findTimeById(Long id) { + public ReservationTimeEntity findTimeById(Long id) { return reservationTimeRepository.findById(id) .orElseThrow(() -> new RoomescapeException(ErrorType.RESERVATION_TIME_NOT_FOUND, String.format("[reservationTimeId: %d]", id), HttpStatus.BAD_REQUEST)); @@ -53,15 +53,15 @@ public class ReservationTimeService { public ReservationTimeResponse addTime(ReservationTimeRequest reservationTimeRequest) { validateTimeDuplication(reservationTimeRequest); - ReservationTime reservationTime = reservationTimeRepository.save( - new ReservationTime(reservationTimeRequest.startAt) + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, reservationTimeRequest.startAt) ); return ReservationTimeResponse.from(reservationTime); } private void validateTimeDuplication(ReservationTimeRequest reservationTimeRequest) { - List duplicateReservationTimes = reservationTimeRepository.findByStartAt( + List duplicateReservationTimes = reservationTimeRepository.findByStartAt( reservationTimeRequest.startAt); if (!duplicateReservationTimes.isEmpty()) { @@ -71,7 +71,7 @@ public class ReservationTimeService { } public void removeTimeById(Long id) { - ReservationTime reservationTime = findTimeById(id); + ReservationTimeEntity reservationTime = findTimeById(id); List usingTimeReservations = reservationRepository.findByReservationTime(reservationTime); if (!usingTimeReservations.isEmpty()) { @@ -84,7 +84,7 @@ public class ReservationTimeService { @Transactional(readOnly = true) public ReservationTimeInfosResponse findAllAvailableTimesByDateAndTheme(LocalDate date, Long themeId) { - List allTimes = reservationTimeRepository.findAll(); + List allTimes = reservationTimeRepository.findAll(); List reservations = reservationRepository.findByThemeId(themeId); List response = allTimes.stream() @@ -95,7 +95,7 @@ public class ReservationTimeService { return new ReservationTimeInfosResponse(response); } - private boolean isReservationBooked(List reservations, LocalDate date, ReservationTime time) { + private boolean isReservationBooked(List reservations, LocalDate date, ReservationTimeEntity time) { return reservations.stream() .anyMatch(reservation -> reservation.isSameDateAndTime(date, time)); } diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/Reservation.java b/src/main/java/roomescape/reservation/infrastructure/persistence/Reservation.java index be474891..81b8583c 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/Reservation.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/Reservation.java @@ -31,7 +31,7 @@ public class Reservation { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "time_id", nullable = false) - private ReservationTime reservationTime; + private ReservationTimeEntity reservationTime; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "theme_id", nullable = false) @@ -49,7 +49,7 @@ public class Reservation { public Reservation( LocalDate date, - ReservationTime reservationTime, + ReservationTimeEntity reservationTime, ThemeEntity theme, MemberEntity member, ReservationStatus status @@ -60,7 +60,7 @@ public class Reservation { public Reservation( Long id, LocalDate date, - ReservationTime reservationTime, + ReservationTimeEntity reservationTime, ThemeEntity theme, MemberEntity member, ReservationStatus status @@ -74,7 +74,7 @@ public class Reservation { this.reservationStatus = status; } - private void validateIsNull(LocalDate date, ReservationTime reservationTime, ThemeEntity theme, MemberEntity member, + private void validateIsNull(LocalDate date, ReservationTimeEntity reservationTime, ThemeEntity theme, MemberEntity member, ReservationStatus reservationStatus) { if (date == null || reservationTime == null || theme == null || member == null || reservationStatus == null) { throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[values: %s]", this), @@ -94,7 +94,7 @@ public class Reservation { return date; } - public ReservationTime getReservationTime() { + public ReservationTimeEntity getReservationTime() { return reservationTime; } @@ -111,7 +111,7 @@ public class Reservation { } @JsonIgnore - public boolean isSameDateAndTime(LocalDate date, ReservationTime time) { + public boolean isSameDateAndTime(LocalDate date, ReservationTimeEntity time) { return this.date.equals(date) && time.getStartAt().equals(this.reservationTime.getStartAt()); } diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java index b6dd32de..3635d4ff 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java @@ -12,7 +12,7 @@ import roomescape.reservation.web.MyReservationResponse; public interface ReservationRepository extends JpaRepository, JpaSpecificationExecutor { - List findByReservationTime(ReservationTime reservationTime); + List findByReservationTime(ReservationTimeEntity reservationTime); List findByThemeId(Long themeId); diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt index 8bd9c6bf..7d18b86d 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("reservationTime").get("id"), timeId) } }) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeEntity.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeEntity.kt index fa9ef589..73479a7b 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeEntity.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeEntity.kt @@ -1,59 +1,13 @@ -package roomescape.reservation.infrastructure.persistence; +package roomescape.reservation.infrastructure.persistence -import java.time.LocalTime; - -import org.springframework.http.HttpStatus; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import roomescape.common.exception.ErrorType; -import roomescape.common.exception.RoomescapeException; +import jakarta.persistence.* +import java.time.LocalTime @Entity -public class ReservationTime { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private LocalTime startAt; - - protected ReservationTime() { - } - - public ReservationTime(final LocalTime startAt) { - this(null, startAt); - } - - public ReservationTime(final Long id, final LocalTime startAt) { - this.id = id; - this.startAt = startAt; - - validateNull(); - } - - private void validateNull() { - if (startAt == null) { - throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[values: %s]", this), - HttpStatus.BAD_REQUEST); - } - } - - public Long getId() { - return id; - } - - public LocalTime getStartAt() { - return startAt; - } - - @Override - public String toString() { - return "ReservationTime{" + - "id=" + id + - ", startAt=" + startAt + - '}'; - } -} +@Table(name = "reservation_time") +class ReservationTimeEntity( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null, + var startAt: LocalTime +) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt index 8b6a1c0b..26b533b8 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt @@ -1,11 +1,8 @@ -package roomescape.reservation.infrastructure.persistence; +package roomescape.reservation.infrastructure.persistence -import java.time.LocalTime; -import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalTime -import org.springframework.data.jpa.repository.JpaRepository; - -public interface ReservationTimeRepository extends JpaRepository { - - List findByStartAt(LocalTime startAt); +interface ReservationTimeRepository : JpaRepository { + fun findByStartAt(startAt: LocalTime): List } diff --git a/src/main/java/roomescape/reservation/web/ReservationResponse.kt b/src/main/java/roomescape/reservation/web/ReservationResponse.kt index d3ea1ec2..e7f41596 100644 --- a/src/main/java/roomescape/reservation/web/ReservationResponse.kt +++ b/src/main/java/roomescape/reservation/web/ReservationResponse.kt @@ -6,7 +6,7 @@ import roomescape.member.web.MemberResponse import roomescape.member.web.MemberResponse.Companion.fromEntity import roomescape.reservation.infrastructure.persistence.Reservation import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.reservation.infrastructure.persistence.ReservationTime +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity import roomescape.theme.web.ThemeResponse import java.time.LocalDate import java.time.LocalTime @@ -106,8 +106,8 @@ data class ReservationTimeResponse( companion object { @JvmStatic - fun from(reservationTime: ReservationTime): ReservationTimeResponse { - return ReservationTimeResponse(reservationTime.id, reservationTime.startAt) + fun from(reservationTime: ReservationTimeEntity): ReservationTimeResponse { + return ReservationTimeResponse(reservationTime.id!!, reservationTime.startAt) } } } diff --git a/src/test/java/roomescape/payment/business/PaymentServiceTest.java b/src/test/java/roomescape/payment/business/PaymentServiceTest.java index ef6a43e1..7d48ef0d 100644 --- a/src/test/java/roomescape/payment/business/PaymentServiceTest.java +++ b/src/test/java/roomescape/payment/business/PaymentServiceTest.java @@ -25,7 +25,7 @@ import roomescape.payment.web.ReservationPaymentResponse; import roomescape.reservation.infrastructure.persistence.Reservation; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; @@ -55,7 +55,7 @@ class PaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); @@ -78,7 +78,7 @@ class PaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); @@ -116,7 +116,7 @@ class PaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); diff --git a/src/test/java/roomescape/reservation/business/ReservationServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationServiceTest.java index c61b8dbf..cf6aa519 100644 --- a/src/test/java/roomescape/reservation/business/ReservationServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationServiceTest.java @@ -22,7 +22,7 @@ import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.infrastructure.persistence.Reservation; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.reservation.web.ReservationRequest; import roomescape.reservation.web.ReservationResponse; @@ -51,7 +51,8 @@ class ReservationServiceTest { @DisplayName("예약을 추가할때 이미 예약이 존재하면 예외가 발생한다.") void reservationAlreadyExistFail() { // given - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member1 = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -75,7 +76,8 @@ class ReservationServiceTest { @DisplayName("이미 예약한 멤버가 같은 테마에 대기를 신청하면 예외가 발생한다.") void requestWaitWhenAlreadyReserveFail() { // given - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -96,7 +98,8 @@ class ReservationServiceTest { @DisplayName("예약 대기를 두 번 이상 요청하면 예외가 발생한다.") void requestWaitTwiceFail() { // given - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -122,7 +125,8 @@ class ReservationServiceTest { @DisplayName("이미 지난 날짜로 예약을 생성하면 예외가 발생한다.") void beforeDateReservationFail() { // given - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -140,7 +144,8 @@ class ReservationServiceTest { void beforeTimeReservationFail() { // given LocalDateTime beforeTime = LocalDateTime.now().minusHours(1L).withNano(0); - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(beforeTime.toLocalTime())); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, beforeTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -157,7 +162,8 @@ class ReservationServiceTest { void notExistMemberReservationFail() { // given LocalDateTime beforeTime = LocalDateTime.now().minusDays(1L).withNano(0); - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(beforeTime.toLocalTime())); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, beforeTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); Long NotExistMemberId = 1L; @@ -185,7 +191,8 @@ class ReservationServiceTest { @DisplayName("대기중인 예약을 승인할 때, 기존에 예약이 존재하면 예외가 발생한다.") void confirmWaitingWhenReservationExist() { // given - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity admin = memberRepository.save( new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); @@ -211,7 +218,8 @@ class ReservationServiceTest { @DisplayName("대기중인 예약을 확정한다.") void approveWaiting() { // given - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(12, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity admin = memberRepository.save( new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); diff --git a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java index 0fc57aed..32cccb52 100644 --- a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java @@ -20,7 +20,7 @@ import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.infrastructure.persistence.Reservation; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.reservation.web.ReservationTimeRequest; import roomescape.theme.infrastructure.persistence.ThemeEntity; @@ -46,7 +46,7 @@ class ReservationTimeServiceTest { @DisplayName("중복된 예약 시간을 등록하는 경우 예외가 발생한다.") void duplicateTimeFail() { // given - reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); + reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(12, 30))); // when & then assertThatThrownBy(() -> reservationTimeService.addTime(new ReservationTimeRequest(LocalTime.of(12, 30)))) @@ -57,7 +57,7 @@ class ReservationTimeServiceTest { @DisplayName("존재하지 않는 ID로 시간을 조회하면 예외가 발생한다.") void findTimeByIdFail() { // given - ReservationTime saved = reservationTimeRepository.save(new ReservationTime(LocalTime.of(12, 30))); + ReservationTimeEntity saved = reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(12, 30))); // when Long invalidTimeId = saved.getId() + 1; @@ -72,8 +72,8 @@ class ReservationTimeServiceTest { void usingTimeDeleteFail() { // given LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); - ReservationTime reservationTime = reservationTimeRepository.save( - new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); diff --git a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java index 45017021..ebe9f602 100644 --- a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java @@ -24,7 +24,7 @@ import roomescape.payment.web.PaymentCancel; import roomescape.reservation.infrastructure.persistence.Reservation; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.reservation.web.ReservationRequest; import roomescape.reservation.web.ReservationResponse; @@ -58,7 +58,7 @@ class ReservationWithPaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); @@ -95,7 +95,7 @@ class ReservationWithPaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); @@ -124,7 +124,7 @@ class ReservationWithPaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); @@ -147,7 +147,7 @@ class ReservationWithPaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt index be918324..263be63e 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt @@ -25,7 +25,7 @@ class ReservationSearchSpecificationTest( lateinit var confirmedNotPaidYesterday: Reservation lateinit var waitingTomorrow: Reservation lateinit var member: MemberEntity - lateinit var reservationTime: ReservationTime + lateinit var reservationTime: ReservationTimeEntity lateinit var theme: ThemeEntity "동일한 테마의 예약을 조회한다" { diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java index db467956..9c0bf1e4 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java @@ -20,7 +20,7 @@ public class ReservationTest { @ParameterizedTest @MethodSource("validateConstructorParameterBlankSource") @DisplayName("객체 생성 시, null 또는 공백이 존재하면 예외를 발생한다.") - void validateConstructorParameterBlank(LocalDate date, ReservationTime reservationTime, ThemeEntity theme, + void validateConstructorParameterBlank(LocalDate date, ReservationTimeEntity reservationTime, ThemeEntity theme, MemberEntity member) { // when & then @@ -32,7 +32,7 @@ public class ReservationTest { static Stream validateConstructorParameterBlankSource() { return Stream.of( Arguments.of(null, - new ReservationTime(LocalTime.now().plusHours(1)), + new ReservationTimeEntity(null, LocalTime.now().plusHours(1)), new ThemeEntity(null, "테마명", "설명", "썸네일URI"), new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), Arguments.of( @@ -42,12 +42,12 @@ public class ReservationTest { new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), Arguments.of( LocalDate.now(), - new ReservationTime(LocalTime.now().plusHours(1)), + new ReservationTimeEntity(null, LocalTime.now().plusHours(1)), null, new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), Arguments.of( LocalDate.now(), - new ReservationTime(LocalTime.now().plusHours(1)), + new ReservationTimeEntity(null, LocalTime.now().plusHours(1)), new ThemeEntity(null, "테마명", "설명", "썸네일URI"), null) ); diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeTest.java b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeTest.java deleted file mode 100644 index 18260e0e..00000000 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package roomescape.reservation.infrastructure.persistence; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import roomescape.common.exception.RoomescapeException; - -class ReservationTimeTest { - - @Test - @DisplayName("객체 생성 시, null이 존재하면 예외를 발생한다.") - void validateConstructorParameterNull() { - - // when & then - Assertions.assertThatThrownBy(() -> new ReservationTime(null)) - .isInstanceOf(RoomescapeException.class); - } -} diff --git a/src/test/java/roomescape/reservation/web/ReservationControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationControllerTest.java index 8c7d727a..5099ec66 100644 --- a/src/test/java/roomescape/reservation/web/ReservationControllerTest.java +++ b/src/test/java/roomescape/reservation/web/ReservationControllerTest.java @@ -45,7 +45,7 @@ import roomescape.payment.web.PaymentCancel; import roomescape.reservation.infrastructure.persistence.Reservation; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; @@ -86,7 +86,7 @@ public class ReservationControllerTest { LocalTime time = LocalTime.of(17, 30); LocalDate date = LocalDate.now().plusDays(1L); - reservationTimeRepository.save(new ReservationTime(time)); + reservationTimeRepository.save(new ReservationTimeEntity(null, time)); themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); Map reservationParams = Map.of( @@ -122,7 +122,8 @@ public class ReservationControllerTest { new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessTokenCookie = getAccessTokenCookieByLogin("email@email.com", "password"); - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member1 = memberRepository.save( new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); @@ -151,7 +152,8 @@ public class ReservationControllerTest { new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessTokenCookie = getAccessTokenCookieByLogin("email@email.com", "password"); - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity waitingMember = memberRepository.save( new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); @@ -178,7 +180,8 @@ public class ReservationControllerTest { // given String accessTokenCookie = getAdminAccessTokenCookieByLogin("admin@admin.com", "12341234"); - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -209,7 +212,8 @@ public class ReservationControllerTest { new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessTokenCookie = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); Reservation reservation = reservationRepository.save( new Reservation(LocalDate.now(), reservationTime, theme, member, ReservationStatus.CONFIRMED)); @@ -229,7 +233,8 @@ public class ReservationControllerTest { // given String adminTokenCookie = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity confirmedMember = memberRepository.save( new MemberEntity(null, "name1", "email@email.com", "password", Role.MEMBER)); @@ -258,7 +263,8 @@ public class ReservationControllerTest { new MemberEntity(null, "name", "admin@admin.com", "password", Role.ADMIN)); String accessTokenCookie = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); - ReservationTime reservationTime = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); + ReservationTimeEntity reservationTime = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity anotherMember = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -341,9 +347,12 @@ public class ReservationControllerTest { // given LocalDate date = LocalDate.now().plusDays(1); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); - ReservationTime time1 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(18, 30))); - ReservationTime time2 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(19, 30))); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); + ReservationTimeEntity time1 = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(18, 30))); + ReservationTimeEntity time2 = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(19, 30))); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.ADMIN)); @@ -371,7 +380,8 @@ public class ReservationControllerTest { // given LocalDate date = LocalDate.now().plusDays(1); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); String accessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); // when @@ -395,7 +405,8 @@ public class ReservationControllerTest { String accessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); LocalDate date = LocalDate.now().plusDays(1); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -425,7 +436,8 @@ public class ReservationControllerTest { // given LocalDateTime localDateTime = LocalDateTime.now().minusHours(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -519,7 +531,8 @@ public class ReservationControllerTest { // given LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -547,7 +560,8 @@ public class ReservationControllerTest { // given LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); @@ -593,7 +607,8 @@ public class ReservationControllerTest { // given LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); - ReservationTime time = reservationTimeRepository.save(new ReservationTime(localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); diff --git a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java index d809a355..8fd946a5 100644 --- a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java +++ b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java @@ -27,7 +27,7 @@ import roomescape.member.infrastructure.persistence.Role; import roomescape.reservation.infrastructure.persistence.Reservation; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTime; +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; @@ -221,9 +221,9 @@ public class ReservationTimeControllerTest { void readReservationByDateAndThemeId() { // given LocalDate today = LocalDate.now(); - ReservationTime reservationTime1 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 0))); - ReservationTime reservationTime2 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(17, 30))); - ReservationTime reservationTime3 = reservationTimeRepository.save(new ReservationTime(LocalTime.of(18, 30))); + ReservationTimeEntity reservationTime1 = reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(17, 0))); + ReservationTimeEntity reservationTime2 = reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(17, 30))); + ReservationTimeEntity reservationTime3 = reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(18, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명1", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); diff --git a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt index 33756ae6..0f05cdfa 100644 --- a/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt +++ b/src/test/java/roomescape/theme/util/TestThemeCreateUtil.kt @@ -3,7 +3,7 @@ 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.ReservationTime +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.util.MemberFixture import roomescape.util.ReservationFixture @@ -23,7 +23,7 @@ object TestThemeCreateUtil { val member: MemberEntity = MemberFixture.create().also { entityManager.persist(it) } for (i in 1..reservedCount) { - val time: ReservationTime = ReservationTimeFixture.create( + val time: ReservationTimeEntity = ReservationTimeFixture.create( startAt = LocalTime.now().plusMinutes(i.toLong()) ).also { entityManager.persist(it) } diff --git a/src/test/java/roomescape/util/Fixtures.kt b/src/test/java/roomescape/util/Fixtures.kt index 07aca7c2..a1d4e01a 100644 --- a/src/test/java/roomescape/util/Fixtures.kt +++ b/src/test/java/roomescape/util/Fixtures.kt @@ -10,7 +10,7 @@ import roomescape.payment.web.PaymentApprove import roomescape.payment.web.PaymentCancel import roomescape.reservation.infrastructure.persistence.Reservation import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.reservation.infrastructure.persistence.ReservationTime +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity import roomescape.theme.infrastructure.persistence.ThemeEntity import java.time.LocalDate import java.time.LocalTime @@ -55,7 +55,7 @@ object ReservationTimeFixture { fun create( id: Long? = null, startAt: LocalTime = LocalTime.now().plusHours(1), - ): ReservationTime = ReservationTime(id, startAt) + ): ReservationTimeEntity = ReservationTimeEntity(id, startAt) } object ThemeFixture { @@ -72,7 +72,7 @@ object ReservationFixture { id: Long? = null, date: LocalDate = LocalDate.now().plusWeeks(1), theme: ThemeEntity = ThemeFixture.create(), - reservationTime: ReservationTime = ReservationTimeFixture.create(), + reservationTime: ReservationTimeEntity = ReservationTimeFixture.create(), member: MemberEntity = MemberFixture.create(), status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED ): Reservation = Reservation(id, date, reservationTime, theme, member, status) -- 2.47.2 From 0a0879dc55c9a266edc9358399047b298fbec48f Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 15:55:48 +0900 Subject: [PATCH 12/40] Rename .java to .kt --- .../persistence/{Reservation.java => ReservationEntity.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/roomescape/reservation/infrastructure/persistence/{Reservation.java => ReservationEntity.kt} (100%) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/Reservation.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt similarity index 100% rename from src/main/java/roomescape/reservation/infrastructure/persistence/Reservation.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt -- 2.47.2 From 06988674dd2388238ef2693ed74f5c42340bed9d Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 15:55:48 +0900 Subject: [PATCH 13/40] =?UTF-8?q?refactor:=20Reservation=20=EC=BD=94?= =?UTF-8?q?=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98=20=EB=B0=8F=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=AA=85=20=EC=88=98=EC=A0=95(->=20Reservati?= =?UTF-8?q?onEntity)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/business/PaymentService.kt | 4 +- .../persistence/PaymentEntity.kt | 4 +- .../business/ReservationService.java | 34 ++-- .../business/ReservationTimeService.java | 9 +- .../ReservationWithPaymentService.java | 4 +- .../persistence/ReservationEntity.kt | 162 +++++------------- .../persistence/ReservationRepository.java | 17 +- .../ReservationSearchSpecification.kt | 6 +- .../persistence/ReservationStatus.java | 13 -- .../reservation/web/ReservationResponse.kt | 6 +- .../persistence/ThemeRepository.kt | 4 +- .../payment/business/PaymentServiceTest.java | 26 +-- .../persistence/PaymentRepositoryTest.kt | 2 +- .../business/ReservationServiceTest.java | 4 +- .../business/ReservationTimeServiceTest.java | 10 +- .../ReservationWithPaymentServiceTest.java | 18 +- .../ReservationSearchSpecificationTest.kt | 50 +++--- .../persistence/ReservationTest.java | 55 ------ .../web/ReservationControllerTest.java | 68 ++++---- .../web/ReservationTimeControllerTest.java | 20 ++- src/test/java/roomescape/util/Fixtures.kt | 4 +- 21 files changed, 206 insertions(+), 314 deletions(-) delete mode 100644 src/main/java/roomescape/reservation/infrastructure/persistence/ReservationStatus.java delete mode 100644 src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java diff --git a/src/main/java/roomescape/payment/business/PaymentService.kt b/src/main/java/roomescape/payment/business/PaymentService.kt index 9d092ed6..8a406fad 100644 --- a/src/main/java/roomescape/payment/business/PaymentService.kt +++ b/src/main/java/roomescape/payment/business/PaymentService.kt @@ -13,7 +13,7 @@ import roomescape.payment.web.PaymentApprove import roomescape.payment.web.PaymentCancel import roomescape.payment.web.ReservationPaymentResponse import roomescape.payment.web.toReservationPaymentResponse -import roomescape.reservation.infrastructure.persistence.Reservation +import roomescape.reservation.infrastructure.persistence.ReservationEntity import java.time.OffsetDateTime @Service @@ -24,7 +24,7 @@ class PaymentService( @Transactional fun savePayment( paymentResponse: PaymentApprove.Response, - reservation: Reservation + reservation: ReservationEntity ): ReservationPaymentResponse = PaymentEntity( orderId = paymentResponse.orderId, paymentKey = paymentResponse.paymentKey, diff --git a/src/main/java/roomescape/payment/infrastructure/persistence/PaymentEntity.kt b/src/main/java/roomescape/payment/infrastructure/persistence/PaymentEntity.kt index bcc52d20..88f25dbe 100644 --- a/src/main/java/roomescape/payment/infrastructure/persistence/PaymentEntity.kt +++ b/src/main/java/roomescape/payment/infrastructure/persistence/PaymentEntity.kt @@ -1,7 +1,7 @@ package roomescape.payment.infrastructure.persistence import jakarta.persistence.* -import roomescape.reservation.infrastructure.persistence.Reservation +import roomescape.reservation.infrastructure.persistence.ReservationEntity import java.time.OffsetDateTime @Entity @@ -22,7 +22,7 @@ class PaymentEntity( @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "reservation_id", nullable = false) - var reservation: Reservation, + var reservation: ReservationEntity, @Column(nullable = false) var approvedAt: OffsetDateTime diff --git a/src/main/java/roomescape/reservation/business/ReservationService.java b/src/main/java/roomescape/reservation/business/ReservationService.java index fc1747d5..e38c0f98 100644 --- a/src/main/java/roomescape/reservation/business/ReservationService.java +++ b/src/main/java/roomescape/reservation/business/ReservationService.java @@ -13,7 +13,7 @@ import roomescape.common.exception.ErrorType; import roomescape.common.exception.RoomescapeException; import roomescape.member.business.MemberService; import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationEntity; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationSearchSpecification; import roomescape.reservation.infrastructure.persistence.ReservationStatus; @@ -50,7 +50,7 @@ public class ReservationService { @Transactional(readOnly = true) public ReservationsResponse findAllReservations() { - Specification spec = new ReservationSearchSpecification().confirmed().build(); + Specification spec = new ReservationSearchSpecification().confirmed().build(); List response = findAllReservationByStatus(spec); return new ReservationsResponse(response); @@ -58,13 +58,13 @@ public class ReservationService { @Transactional(readOnly = true) public ReservationsResponse findAllWaiting() { - Specification spec = new ReservationSearchSpecification().waiting().build(); + Specification spec = new ReservationSearchSpecification().waiting().build(); List response = findAllReservationByStatus(spec); return new ReservationsResponse(response); } - private List findAllReservationByStatus(Specification spec) { + private List findAllReservationByStatus(Specification spec) { return reservationRepository.findAll(spec) .stream() .map(ReservationResponse::from) @@ -76,9 +76,9 @@ public class ReservationService { reservationRepository.deleteById(reservationId); } - public Reservation addReservation(ReservationRequest request, Long memberId) { + public ReservationEntity addReservation(ReservationRequest request, Long memberId) { validateIsReservationExist(request.themeId, request.timeId, request.date); - Reservation reservation = getReservationForSave(request.timeId, request.themeId, request.date, memberId, + ReservationEntity reservation = getReservationForSave(request.timeId, request.themeId, request.date, memberId, ReservationStatus.CONFIRMED); return reservationRepository.save(reservation); } @@ -97,13 +97,13 @@ public class ReservationService { private ReservationResponse addReservationWithoutPayment(Long themeId, Long timeId, LocalDate date, Long memberId, ReservationStatus status) { - Reservation reservation = getReservationForSave(timeId, themeId, date, memberId, status); - Reservation saved = reservationRepository.save(reservation); + ReservationEntity reservation = getReservationForSave(timeId, themeId, date, memberId, status); + ReservationEntity saved = reservationRepository.save(reservation); return ReservationResponse.from(saved); } private void validateMemberAlreadyReserve(Long themeId, Long timeId, LocalDate date, Long memberId) { - Specification spec = new ReservationSearchSpecification() + Specification spec = new ReservationSearchSpecification() .sameMemberId(memberId) .sameThemeId(themeId) .sameTimeId(timeId) @@ -116,7 +116,7 @@ public class ReservationService { } private void validateIsReservationExist(Long themeId, Long timeId, LocalDate date) { - Specification spec = new ReservationSearchSpecification() + Specification spec = new ReservationSearchSpecification() .confirmed() .sameThemeId(themeId) .sameTimeId(timeId) @@ -143,21 +143,21 @@ public class ReservationService { } } - private Reservation getReservationForSave(Long timeId, Long themeId, LocalDate date, Long memberId, + private ReservationEntity getReservationForSave(Long timeId, Long themeId, LocalDate date, Long memberId, ReservationStatus status) { ReservationTimeEntity time = reservationTimeService.findTimeById(timeId); ThemeEntity theme = themeService.findThemeById(themeId); MemberEntity member = memberService.findById(memberId); validateDateAndTime(date, time); - return new Reservation(date, time, theme, member, status); + return new ReservationEntity(null, date, time, theme, member, status); } @Transactional(readOnly = true) public ReservationsResponse findFilteredReservations(Long themeId, Long memberId, LocalDate dateFrom, LocalDate dateTo) { validateDateForSearch(dateFrom, dateTo); - Specification spec = new ReservationSearchSpecification() + Specification spec = new ReservationSearchSpecification() .confirmed() .sameThemeId(themeId) .sameMemberId(memberId) @@ -197,8 +197,8 @@ public class ReservationService { } public void cancelWaiting(Long reservationId, Long memberId) { - Reservation waiting = reservationRepository.findById(reservationId) - .filter(Reservation::isWaiting) + ReservationEntity waiting = reservationRepository.findById(reservationId) + .filter(ReservationEntity::isWaiting) .filter(r -> r.isSameMember(memberId)) .orElseThrow(() -> throwReservationNotFound(reservationId)); reservationRepository.delete(waiting); @@ -206,8 +206,8 @@ public class ReservationService { public void denyWaiting(Long reservationId, Long memberId) { validateIsMemberAdmin(memberId); - Reservation waiting = reservationRepository.findById(reservationId) - .filter(Reservation::isWaiting) + ReservationEntity waiting = reservationRepository.findById(reservationId) + .filter(ReservationEntity::isWaiting) .orElseThrow(() -> throwReservationNotFound(reservationId)); reservationRepository.delete(waiting); } diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.java b/src/main/java/roomescape/reservation/business/ReservationTimeService.java index 21c77a7a..1d72210c 100644 --- a/src/main/java/roomescape/reservation/business/ReservationTimeService.java +++ b/src/main/java/roomescape/reservation/business/ReservationTimeService.java @@ -9,7 +9,7 @@ import org.springframework.transaction.annotation.Transactional; import roomescape.common.exception.ErrorType; import roomescape.common.exception.RoomescapeException; -import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationEntity; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; @@ -72,7 +72,7 @@ public class ReservationTimeService { public void removeTimeById(Long id) { ReservationTimeEntity reservationTime = findTimeById(id); - List usingTimeReservations = reservationRepository.findByReservationTime(reservationTime); + List usingTimeReservations = reservationRepository.findByReservationTime(reservationTime); if (!usingTimeReservations.isEmpty()) { throw new RoomescapeException(ErrorType.TIME_IS_USED_CONFLICT, String.format("[timeId: %d]", id), @@ -85,7 +85,7 @@ public class ReservationTimeService { @Transactional(readOnly = true) public ReservationTimeInfosResponse findAllAvailableTimesByDateAndTheme(LocalDate date, Long themeId) { List allTimes = reservationTimeRepository.findAll(); - List reservations = reservationRepository.findByThemeId(themeId); + List reservations = reservationRepository.findByThemeId(themeId); List response = allTimes.stream() .map(time -> new ReservationTimeInfoResponse(time.getId(), time.getStartAt(), @@ -95,7 +95,8 @@ public class ReservationTimeService { return new ReservationTimeInfosResponse(response); } - private boolean isReservationBooked(List reservations, LocalDate date, ReservationTimeEntity time) { + private boolean isReservationBooked(List reservations, LocalDate date, + ReservationTimeEntity time) { return reservations.stream() .anyMatch(reservation -> reservation.isSameDateAndTime(date, time)); } diff --git a/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java b/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java index 9e01b26b..13a78758 100644 --- a/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java +++ b/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java @@ -9,7 +9,7 @@ import roomescape.payment.business.PaymentService; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; import roomescape.payment.web.ReservationPaymentResponse; -import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationEntity; import roomescape.reservation.web.ReservationRequest; import roomescape.reservation.web.ReservationResponse; @@ -29,7 +29,7 @@ public class ReservationWithPaymentService { public ReservationResponse addReservationWithPayment(ReservationRequest request, PaymentApprove.Response paymentInfo, Long memberId) { - Reservation reservation = reservationService.addReservation(request, memberId); + ReservationEntity reservation = reservationService.addReservation(request, memberId); ReservationPaymentResponse reservationPaymentResponse = paymentService.savePayment(paymentInfo, reservation); return reservationPaymentResponse.reservation(); diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt index 81b8583c..cd8970e3 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt @@ -1,127 +1,59 @@ -package roomescape.reservation.infrastructure.persistence; +package roomescape.reservation.infrastructure.persistence -import java.time.LocalDate; - -import org.springframework.http.HttpStatus; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import roomescape.common.exception.ErrorType; -import roomescape.common.exception.RoomescapeException; -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.theme.infrastructure.persistence.ThemeEntity; +import com.fasterxml.jackson.annotation.JsonIgnore +import io.swagger.v3.oas.annotations.media.Schema +import jakarta.persistence.* +import roomescape.member.infrastructure.persistence.MemberEntity +import roomescape.theme.infrastructure.persistence.ThemeEntity +import java.time.LocalDate @Entity -public class Reservation { +@Table(name = "reservation") +class ReservationEntity( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null, - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + var date: LocalDate, - private LocalDate date; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "time_id", nullable = false) + var reservationTime: ReservationTimeEntity, - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "time_id", nullable = false) - private ReservationTimeEntity reservationTime; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "theme_id", nullable = false) + var theme: ThemeEntity, - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "theme_id", nullable = false) - private ThemeEntity theme; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + var member: MemberEntity, - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false) - private MemberEntity member; + @Enumerated(value = EnumType.STRING) + var reservationStatus: ReservationStatus +) { - @Enumerated(value = EnumType.STRING) - private ReservationStatus reservationStatus; + @JsonIgnore + fun isSameDateAndTime(date: LocalDate?, time: ReservationTimeEntity): Boolean { + return this.date == date && time.startAt == this.reservationTime.startAt + } - protected Reservation() { - } + @JsonIgnore + fun isWaiting(): Boolean = reservationStatus == ReservationStatus.WAITING - public Reservation( - LocalDate date, - ReservationTimeEntity reservationTime, - ThemeEntity theme, - MemberEntity member, - ReservationStatus status - ) { - this(null, date, reservationTime, theme, member, status); - } - - public Reservation( - Long id, - LocalDate date, - ReservationTimeEntity reservationTime, - ThemeEntity theme, - MemberEntity member, - ReservationStatus status - ) { - validateIsNull(date, reservationTime, theme, member, status); - this.id = id; - this.date = date; - this.reservationTime = reservationTime; - this.theme = theme; - this.member = member; - this.reservationStatus = status; - } - - private void validateIsNull(LocalDate date, ReservationTimeEntity reservationTime, ThemeEntity theme, MemberEntity member, - ReservationStatus reservationStatus) { - if (date == null || reservationTime == null || theme == null || member == null || reservationStatus == null) { - throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[values: %s]", this), - HttpStatus.BAD_REQUEST); - } - } - - public Long getMemberId() { - return member.getId(); - } - - public Long getId() { - return id; - } - - public LocalDate getDate() { - return date; - } - - public ReservationTimeEntity getReservationTime() { - return reservationTime; - } - - public ThemeEntity getTheme() { - return theme; - } - - public MemberEntity getMember() { - return member; - } - - public ReservationStatus getReservationStatus() { - return reservationStatus; - } - - @JsonIgnore - public boolean isSameDateAndTime(LocalDate date, ReservationTimeEntity time) { - return this.date.equals(date) && time.getStartAt().equals(this.reservationTime.getStartAt()); - } - - @JsonIgnore - public boolean isWaiting() { - return reservationStatus == ReservationStatus.WAITING; - } - - @JsonIgnore - public boolean isSameMember(Long memberId) { - return getMemberId().equals(memberId); - } + @JsonIgnore + fun isSameMember(memberId: Long): Boolean { + return this.member.id == memberId + } +} + +@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.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java index 3635d4ff..5b36ee61 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java @@ -10,15 +10,16 @@ import org.springframework.data.repository.query.Param; import roomescape.reservation.web.MyReservationResponse; -public interface ReservationRepository extends JpaRepository, JpaSpecificationExecutor { +public interface ReservationRepository + extends JpaRepository, JpaSpecificationExecutor { - List findByReservationTime(ReservationTimeEntity reservationTime); + List findByReservationTime(ReservationTimeEntity reservationTime); - List findByThemeId(Long themeId); + List findByThemeId(Long themeId); @Modifying @Query(""" - UPDATE Reservation r + UPDATE ReservationEntity r SET r.reservationStatus = :status WHERE r.id = :id """) @@ -27,13 +28,13 @@ public interface ReservationRepository extends JpaRepository, @Query(""" SELECT EXISTS ( - SELECT 1 FROM Reservation r + SELECT 1 FROM ReservationEntity r WHERE r.theme.id = r2.theme.id AND r.reservationTime.id = r2.reservationTime.id AND r.date = r2.date AND r.reservationStatus != 'WAITING' ) - FROM Reservation r2 + FROM ReservationEntity r2 WHERE r2.id = :id """) boolean isExistConfirmedReservation(@Param("id") Long reservationId); @@ -45,11 +46,11 @@ public interface ReservationRepository extends JpaRepository, r.date, r.reservationTime.startAt, r.reservationStatus, - (SELECT COUNT (r2) * 1L FROM Reservation 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.reservationTime = r.reservationTime AND r2.id < r.id), p.paymentKey, p.totalAmount ) - FROM Reservation r + FROM ReservationEntity r JOIN r.theme t LEFT JOIN PaymentEntity p ON p.reservation = r diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt index 7d18b86d..ca55ce2e 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecification.kt @@ -6,7 +6,7 @@ import roomescape.theme.infrastructure.persistence.ThemeEntity import java.time.LocalDate class ReservationSearchSpecification( - private var spec: Specification = Specification { _, _, _ -> null } + private var spec: Specification = Specification { _, _, _ -> null } ) { fun sameThemeId(themeId: Long?): ReservationSearchSpecification = andIfNotNull(themeId?.let { Specification { root, _, cb -> @@ -64,11 +64,11 @@ class ReservationSearchSpecification( } }) - fun build(): Specification { + fun build(): Specification { return this.spec } - private fun andIfNotNull(condition: Specification?): ReservationSearchSpecification { + private fun andIfNotNull(condition: Specification?): ReservationSearchSpecification { condition?.let { this.spec = this.spec.and(condition) } return this } diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationStatus.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationStatus.java deleted file mode 100644 index d5f10221..00000000 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationStatus.java +++ /dev/null @@ -1,13 +0,0 @@ -package roomescape.reservation.infrastructure.persistence; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(description = "예약 상태를 나타냅니다.", allowableValues = {"CONFIRMED", "CONFIRMED_PAYMENT_REQUIRED", "WAITING"}) -public enum ReservationStatus { - @Schema(description = "결제가 완료된 예약") - CONFIRMED, - @Schema(description = "결제가 필요한 예약") - CONFIRMED_PAYMENT_REQUIRED, - @Schema(description = "대기 중인 예약") - WAITING; -} diff --git a/src/main/java/roomescape/reservation/web/ReservationResponse.kt b/src/main/java/roomescape/reservation/web/ReservationResponse.kt index e7f41596..548b5d56 100644 --- a/src/main/java/roomescape/reservation/web/ReservationResponse.kt +++ b/src/main/java/roomescape/reservation/web/ReservationResponse.kt @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty import io.swagger.v3.oas.annotations.media.Schema import roomescape.member.web.MemberResponse import roomescape.member.web.MemberResponse.Companion.fromEntity -import roomescape.reservation.infrastructure.persistence.Reservation +import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationStatus import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity import roomescape.theme.web.ThemeResponse @@ -73,9 +73,9 @@ data class ReservationResponse( ) { companion object { @JvmStatic - fun from(reservation: Reservation): ReservationResponse { + fun from(reservation: ReservationEntity): ReservationResponse { return ReservationResponse( - reservation.id, + reservation.id!!, reservation.date, fromEntity(reservation.member), ReservationTimeResponse.Companion.from(reservation.reservationTime), diff --git a/src/main/java/roomescape/theme/infrastructure/persistence/ThemeRepository.kt b/src/main/java/roomescape/theme/infrastructure/persistence/ThemeRepository.kt index f0ea0b5a..83b02cfe 100644 --- a/src/main/java/roomescape/theme/infrastructure/persistence/ThemeRepository.kt +++ b/src/main/java/roomescape/theme/infrastructure/persistence/ThemeRepository.kt @@ -9,7 +9,7 @@ interface ThemeRepository : JpaRepository { @Query(value = """ SELECT t FROM ThemeEntity t - RIGHT JOIN Reservation r ON t.id = r.theme.id + RIGHT JOIN ReservationEntity r ON t.id = r.theme.id WHERE r.date BETWEEN :startDate AND :endDate GROUP BY r.theme.id ORDER BY COUNT(r.theme.id) DESC, t.id ASC @@ -24,7 +24,7 @@ interface ThemeRepository : JpaRepository { @Query(value = """ SELECT EXISTS( SELECT 1 - FROM Reservation r + FROM ReservationEntity r WHERE r.theme.id = :id ) """) diff --git a/src/test/java/roomescape/payment/business/PaymentServiceTest.java b/src/test/java/roomescape/payment/business/PaymentServiceTest.java index 7d48ef0d..dffdd39a 100644 --- a/src/test/java/roomescape/payment/business/PaymentServiceTest.java +++ b/src/test/java/roomescape/payment/business/PaymentServiceTest.java @@ -22,7 +22,7 @@ import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; import roomescape.payment.web.ReservationPaymentResponse; -import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationEntity; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; @@ -55,12 +55,14 @@ class PaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, - ReservationStatus.CONFIRMED)); + ReservationEntity reservation = reservationRepository.save( + new ReservationEntity(null, date, time, theme, member, + ReservationStatus.CONFIRMED)); // when ReservationPaymentResponse reservationPaymentResponse = paymentService.savePayment(paymentInfo, reservation); @@ -78,12 +80,14 @@ class PaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, - ReservationStatus.CONFIRMED)); + ReservationEntity reservation = reservationRepository.save( + new ReservationEntity(null, date, time, theme, member, + ReservationStatus.CONFIRMED)); paymentService.savePayment(paymentInfo, reservation); @@ -116,12 +120,14 @@ class PaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, - ReservationStatus.CONFIRMED)); + ReservationEntity reservation = reservationRepository.save( + new ReservationEntity(null, date, time, theme, member, + ReservationStatus.CONFIRMED)); paymentService.savePayment(paymentInfo, reservation); paymentService.cancelPaymentByAdmin(reservation.getId()); diff --git a/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt b/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt index ab3217d0..f398564d 100644 --- a/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt +++ b/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt @@ -98,6 +98,6 @@ class PaymentRepositoryTest( entityManager.flush() entityManager.clear() - }.id + }.id!! } } diff --git a/src/test/java/roomescape/reservation/business/ReservationServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationServiceTest.java index cf6aa519..d9a2a2c9 100644 --- a/src/test/java/roomescape/reservation/business/ReservationServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationServiceTest.java @@ -19,7 +19,7 @@ import roomescape.member.business.MemberService; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationEntity; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; @@ -233,7 +233,7 @@ class ReservationServiceTest { reservationService.approveWaiting(waiting.id, admin.getId()); // then - Reservation confirmed = reservationRepository.findById(waiting.id).get(); + ReservationEntity confirmed = reservationRepository.findById(waiting.id).get(); assertThat(confirmed.getReservationStatus()).isEqualTo(ReservationStatus.CONFIRMED_PAYMENT_REQUIRED); } } diff --git a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java index 32cccb52..041afa70 100644 --- a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java @@ -17,7 +17,7 @@ import roomescape.common.exception.RoomescapeException; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationEntity; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; @@ -57,7 +57,8 @@ class ReservationTimeServiceTest { @DisplayName("존재하지 않는 ID로 시간을 조회하면 예외가 발생한다.") void findTimeByIdFail() { // given - ReservationTimeEntity saved = reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(12, 30))); + ReservationTimeEntity saved = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(12, 30))); // when Long invalidTimeId = saved.getId() + 1; @@ -79,8 +80,9 @@ class ReservationTimeServiceTest { new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); // when - reservationRepository.save(new Reservation(localDateTime.toLocalDate(), reservationTime, theme, member, - ReservationStatus.CONFIRMED)); + reservationRepository.save( + new ReservationEntity(null, localDateTime.toLocalDate(), reservationTime, theme, member, + ReservationStatus.CONFIRMED)); // then assertThatThrownBy(() -> reservationTimeService.removeTimeById(reservationTime.getId())) diff --git a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java index ebe9f602..06942c89 100644 --- a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java @@ -21,7 +21,7 @@ import roomescape.payment.infrastructure.persistence.PaymentEntity; import roomescape.payment.infrastructure.persistence.PaymentRepository; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; -import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationEntity; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; @@ -58,7 +58,8 @@ class ReservationWithPaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); @@ -95,7 +96,8 @@ class ReservationWithPaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); @@ -124,13 +126,14 @@ class ReservationWithPaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - Reservation saved = reservationRepository.save( - new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); + ReservationEntity saved = reservationRepository.save( + new ReservationEntity(null, date, time, theme, member, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); // when boolean result = reservationWithPaymentService.isNotPaidReservation(saved.getId()); @@ -147,7 +150,8 @@ class ReservationWithPaymentServiceTest { OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); + ReservationTimeEntity time = reservationTimeRepository.save( + new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt index 263be63e..34f96d9f 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationSearchSpecificationTest.kt @@ -21,19 +21,19 @@ class ReservationSearchSpecificationTest( ) : StringSpec() { init { - lateinit var confirmedNow: Reservation - lateinit var confirmedNotPaidYesterday: Reservation - lateinit var waitingTomorrow: Reservation + lateinit var confirmedNow: ReservationEntity + lateinit var confirmedNotPaidYesterday: ReservationEntity + lateinit var waitingTomorrow: ReservationEntity lateinit var member: MemberEntity lateinit var reservationTime: ReservationTimeEntity lateinit var theme: ThemeEntity "동일한 테마의 예약을 조회한다" { val spec = ReservationSearchSpecification() - .sameThemeId(theme.id) - .build() + .sameThemeId(theme.id) + .build() - val results: List = reservationRepository.findAll(spec) + val results: List = reservationRepository.findAll(spec) assertSoftly(results) { this shouldHaveSize 3 @@ -43,10 +43,10 @@ class ReservationSearchSpecificationTest( "동일한 회원의 예약을 조회한다" { val spec = ReservationSearchSpecification() - .sameMemberId(member.id) - .build() + .sameMemberId(member.id) + .build() - val results: List = reservationRepository.findAll(spec) + val results: List = reservationRepository.findAll(spec) assertSoftly(results) { this shouldHaveSize 3 @@ -56,10 +56,10 @@ class ReservationSearchSpecificationTest( "동일한 예약 시간의 예약을 조회한다" { val spec = ReservationSearchSpecification() - .sameTimeId(reservationTime.id) - .build() + .sameTimeId(reservationTime.id) + .build() - val results: List = reservationRepository.findAll(spec) + val results: List = reservationRepository.findAll(spec) assertSoftly(results) { this shouldHaveSize 3 @@ -69,10 +69,10 @@ class ReservationSearchSpecificationTest( "동일한 날짜의 예약을 조회한다" { val spec = ReservationSearchSpecification() - .sameDate(LocalDate.now()) - .build() + .sameDate(LocalDate.now()) + .build() - val results: List = reservationRepository.findAll(spec) + val results: List = reservationRepository.findAll(spec) assertSoftly(results) { this shouldHaveSize 1 @@ -85,7 +85,7 @@ class ReservationSearchSpecificationTest( .confirmed() .build() - val results: List = reservationRepository.findAll(spec) + val results: List = reservationRepository.findAll(spec) assertSoftly(results) { this shouldHaveSize 2 @@ -95,10 +95,10 @@ class ReservationSearchSpecificationTest( "대기 상태인 예약을 조회한다" { val spec = ReservationSearchSpecification() - .waiting() - .build() + .waiting() + .build() - val results: List = reservationRepository.findAll(spec) + val results: List = reservationRepository.findAll(spec) assertSoftly(results) { this shouldHaveSize 1 @@ -108,10 +108,10 @@ class ReservationSearchSpecificationTest( "예약 날짜가 오늘 이후인 예약을 조회한다" { val spec = ReservationSearchSpecification() - .dateStartFrom(LocalDate.now()) - .build() + .dateStartFrom(LocalDate.now()) + .build() - val results: List = reservationRepository.findAll(spec) + val results: List = reservationRepository.findAll(spec) assertSoftly(results) { this shouldHaveSize 2 @@ -121,10 +121,10 @@ class ReservationSearchSpecificationTest( "예약 날짜가 내일 이전인 예약을 조회한다" { val spec = ReservationSearchSpecification() - .dateEndAt(LocalDate.now().plusDays(1)) - .build() + .dateEndAt(LocalDate.now().plusDays(1)) + .build() - val results: List = reservationRepository.findAll(spec) + val results: List = reservationRepository.findAll(spec) assertSoftly(results) { this shouldHaveSize 3 diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java deleted file mode 100644 index 9c0bf1e4..00000000 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package roomescape.reservation.infrastructure.persistence; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.stream.Stream; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import roomescape.common.exception.RoomescapeException; -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.member.infrastructure.persistence.Role; -import roomescape.theme.infrastructure.persistence.ThemeEntity; - -public class ReservationTest { - - @ParameterizedTest - @MethodSource("validateConstructorParameterBlankSource") - @DisplayName("객체 생성 시, null 또는 공백이 존재하면 예외를 발생한다.") - void validateConstructorParameterBlank(LocalDate date, ReservationTimeEntity reservationTime, ThemeEntity theme, - MemberEntity member) { - - // when & then - Assertions.assertThatThrownBy( - () -> new Reservation(date, reservationTime, theme, member, ReservationStatus.CONFIRMED)) - .isInstanceOf(RoomescapeException.class); - } - - static Stream validateConstructorParameterBlankSource() { - return Stream.of( - Arguments.of(null, - new ReservationTimeEntity(null, LocalTime.now().plusHours(1)), - new ThemeEntity(null, "테마명", "설명", "썸네일URI"), - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), - Arguments.of( - LocalDate.now(), - null, - new ThemeEntity(null, "테마명", "설명", "썸네일URI"), - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), - Arguments.of( - LocalDate.now(), - new ReservationTimeEntity(null, LocalTime.now().plusHours(1)), - null, - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), - Arguments.of( - LocalDate.now(), - new ReservationTimeEntity(null, LocalTime.now().plusHours(1)), - new ThemeEntity(null, "테마명", "설명", "썸네일URI"), - null) - ); - } -} diff --git a/src/test/java/roomescape/reservation/web/ReservationControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationControllerTest.java index 5099ec66..fb382f10 100644 --- a/src/test/java/roomescape/reservation/web/ReservationControllerTest.java +++ b/src/test/java/roomescape/reservation/web/ReservationControllerTest.java @@ -42,7 +42,7 @@ import roomescape.payment.infrastructure.persistence.PaymentEntity; import roomescape.payment.infrastructure.persistence.PaymentRepository; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; -import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationEntity; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; @@ -129,10 +129,11 @@ public class ReservationControllerTest { new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); // when - reservationRepository.save(new Reservation(LocalDate.now().plusDays(1), reservationTime, theme, member1, - ReservationStatus.CONFIRMED)); - Reservation waiting = reservationRepository.save( - new Reservation(LocalDate.now().plusDays(1), reservationTime, theme, member, + reservationRepository.save( + new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, member1, + ReservationStatus.CONFIRMED)); + ReservationEntity waiting = reservationRepository.save( + new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, member, ReservationStatus.WAITING)); // then @@ -159,10 +160,11 @@ public class ReservationControllerTest { new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); // when - reservationRepository.save(new Reservation(LocalDate.now().plusDays(1), reservationTime, theme, confirmedMember, - ReservationStatus.CONFIRMED)); - Reservation waiting = reservationRepository.save( - new Reservation(LocalDate.now().plusDays(1), reservationTime, theme, waitingMember, + reservationRepository.save( + new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, confirmedMember, + ReservationStatus.CONFIRMED)); + ReservationEntity waiting = reservationRepository.save( + new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, waitingMember, ReservationStatus.WAITING)); // then @@ -188,11 +190,13 @@ public class ReservationControllerTest { // when reservationRepository.save( - new Reservation(LocalDate.now(), reservationTime, theme, member, ReservationStatus.CONFIRMED)); - reservationRepository.save(new Reservation(LocalDate.now().plusDays(1), reservationTime, theme, member, - ReservationStatus.CONFIRMED)); - reservationRepository.save(new Reservation(LocalDate.now().plusDays(2), reservationTime, theme, member, - ReservationStatus.CONFIRMED)); + new ReservationEntity(null, LocalDate.now(), reservationTime, theme, member, ReservationStatus.CONFIRMED)); + reservationRepository.save( + new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, member, + ReservationStatus.CONFIRMED)); + reservationRepository.save( + new ReservationEntity(null, LocalDate.now().plusDays(2), reservationTime, theme, member, + ReservationStatus.CONFIRMED)); // then RestAssured.given().log().all() @@ -215,8 +219,8 @@ public class ReservationControllerTest { ReservationTimeEntity reservationTime = reservationTimeRepository.save( new ReservationTimeEntity(null, LocalTime.of(17, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Reservation reservation = reservationRepository.save( - new Reservation(LocalDate.now(), reservationTime, theme, member, ReservationStatus.CONFIRMED)); + ReservationEntity reservation = reservationRepository.save( + new ReservationEntity(null, LocalDate.now(), reservationTime, theme, member, ReservationStatus.CONFIRMED)); // when & then RestAssured.given().log().all() @@ -242,9 +246,11 @@ public class ReservationControllerTest { new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); reservationRepository.save( - new Reservation(LocalDate.now(), reservationTime, theme, confirmedMember, ReservationStatus.CONFIRMED)); - Reservation waiting = reservationRepository.save( - new Reservation(LocalDate.now(), reservationTime, theme, waitingMember, ReservationStatus.WAITING)); + new ReservationEntity(null, LocalDate.now(), reservationTime, theme, confirmedMember, + ReservationStatus.CONFIRMED)); + ReservationEntity waiting = reservationRepository.save( + new ReservationEntity(null, LocalDate.now(), reservationTime, theme, waitingMember, + ReservationStatus.WAITING)); // when & then RestAssured.given().log().all() @@ -269,8 +275,9 @@ public class ReservationControllerTest { MemberEntity anotherMember = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - Reservation reservation = reservationRepository.save( - new Reservation(LocalDate.now(), reservationTime, theme, anotherMember, ReservationStatus.CONFIRMED)); + ReservationEntity reservation = reservationRepository.save( + new ReservationEntity(null, LocalDate.now(), reservationTime, theme, anotherMember, + ReservationStatus.CONFIRMED)); // when & then RestAssured.given().log().all() @@ -359,10 +366,10 @@ public class ReservationControllerTest { String accessToken = getAccessTokenCookieByLogin("email@email.com", "password"); // when : 예약은 2개, 예약 대기는 1개 조회되어야 한다. - reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); + reservationRepository.save(new ReservationEntity(null, date, time, theme, member, ReservationStatus.CONFIRMED)); reservationRepository.save( - new Reservation(date, time1, theme, member, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); - reservationRepository.save(new Reservation(date, time2, theme, member, ReservationStatus.WAITING)); + new ReservationEntity(null, date, time1, theme, member, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); + reservationRepository.save(new ReservationEntity(null, date, time2, theme, member, ReservationStatus.WAITING)); // then RestAssured.given().log().all() @@ -385,7 +392,7 @@ public class ReservationControllerTest { String accessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); // when - Reservation saved = reservationRepository.save(new Reservation(date, time, theme, + ReservationEntity saved = reservationRepository.save(new ReservationEntity(null, date, time, theme, memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); @@ -410,8 +417,8 @@ public class ReservationControllerTest { MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - Reservation saved = reservationRepository.save( - new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); + ReservationEntity saved = reservationRepository.save( + new ReservationEntity(null, date, time, theme, member, ReservationStatus.CONFIRMED)); PaymentEntity savedPaymentEntity = paymentRepository.save( new PaymentEntity(null, "pk", "oi", 1000L, saved, OffsetDateTime.now().minusHours(1L))); @@ -540,7 +547,8 @@ public class ReservationControllerTest { new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); String accessToken = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); - reservationRepository.save(new Reservation(date, time, theme, member1, ReservationStatus.CONFIRMED)); + reservationRepository.save( + new ReservationEntity(null, date, time, theme, member1, ReservationStatus.CONFIRMED)); // when & then RestAssured.given().log().all() @@ -567,8 +575,8 @@ public class ReservationControllerTest { new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); String accessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); - Reservation waiting = reservationRepository.save( - new Reservation(date, time, theme, member, ReservationStatus.WAITING)); + ReservationEntity waiting = reservationRepository.save( + new ReservationEntity(null, date, time, theme, member, ReservationStatus.WAITING)); // when RestAssured.given().log().all() diff --git a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java index 8fd946a5..4848d971 100644 --- a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java +++ b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java @@ -24,7 +24,7 @@ import io.restassured.http.Header; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.infrastructure.persistence.Reservation; +import roomescape.reservation.infrastructure.persistence.ReservationEntity; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; @@ -221,19 +221,25 @@ public class ReservationTimeControllerTest { void readReservationByDateAndThemeId() { // given LocalDate today = LocalDate.now(); - ReservationTimeEntity reservationTime1 = reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(17, 0))); - ReservationTimeEntity reservationTime2 = reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(17, 30))); - ReservationTimeEntity reservationTime3 = reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(18, 30))); + ReservationTimeEntity reservationTime1 = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 0))); + ReservationTimeEntity reservationTime2 = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(17, 30))); + ReservationTimeEntity reservationTime3 = reservationTimeRepository.save( + new ReservationTimeEntity(null, LocalTime.of(18, 30))); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명1", "설명", "썸네일URL")); MemberEntity member = memberRepository.save( new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); reservationRepository.save( - new Reservation(today.plusDays(1), reservationTime1, theme, member, ReservationStatus.CONFIRMED)); + new ReservationEntity(null, today.plusDays(1), reservationTime1, theme, member, + ReservationStatus.CONFIRMED)); reservationRepository.save( - new Reservation(today.plusDays(1), reservationTime2, theme, member, ReservationStatus.CONFIRMED)); + new ReservationEntity(null, today.plusDays(1), reservationTime2, theme, member, + ReservationStatus.CONFIRMED)); reservationRepository.save( - new Reservation(today.plusDays(1), reservationTime3, theme, member, ReservationStatus.CONFIRMED)); + new ReservationEntity(null, today.plusDays(1), reservationTime3, theme, member, + ReservationStatus.CONFIRMED)); // when & then RestAssured.given().log().all() diff --git a/src/test/java/roomescape/util/Fixtures.kt b/src/test/java/roomescape/util/Fixtures.kt index a1d4e01a..7b6c3026 100644 --- a/src/test/java/roomescape/util/Fixtures.kt +++ b/src/test/java/roomescape/util/Fixtures.kt @@ -8,7 +8,7 @@ import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity import roomescape.payment.infrastructure.persistence.PaymentEntity import roomescape.payment.web.PaymentApprove import roomescape.payment.web.PaymentCancel -import roomescape.reservation.infrastructure.persistence.Reservation +import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationStatus import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity import roomescape.theme.infrastructure.persistence.ThemeEntity @@ -75,7 +75,7 @@ object ReservationFixture { reservationTime: ReservationTimeEntity = ReservationTimeFixture.create(), member: MemberEntity = MemberFixture.create(), status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED - ): Reservation = Reservation(id, date, reservationTime, theme, member, status) + ): ReservationEntity = ReservationEntity(id, date, reservationTime, theme, member, status) } object JwtFixture { -- 2.47.2 From 403ba3c40b19f5b89940588f5829446878c06daf Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 16:00:16 +0900 Subject: [PATCH 14/40] Rename .java to .kt --- .../{ReservationRepository.java => ReservationRepository.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/roomescape/reservation/infrastructure/persistence/{ReservationRepository.java => ReservationRepository.kt} (100%) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt similarity index 100% rename from src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.java rename to src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt -- 2.47.2 From 8a09eb045f593c9c2b42d65ca3db977cf176a88b Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 16:00:16 +0900 Subject: [PATCH 15/40] =?UTF-8?q?refactor:=20ReservationRepository=20?= =?UTF-8?q?=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/ReservationRepository.kt | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt index 5b36ee61..9b676727 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt @@ -1,32 +1,31 @@ -package roomescape.reservation.infrastructure.persistence; +package roomescape.reservation.infrastructure.persistence -import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.JpaSpecificationExecutor +import org.springframework.data.jpa.repository.Modifying +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param +import roomescape.reservation.web.MyReservationResponse -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; +interface ReservationRepository + : JpaRepository, JpaSpecificationExecutor +{ + fun findByReservationTime(reservationTime: ReservationTimeEntity): List -import roomescape.reservation.web.MyReservationResponse; + fun findByThemeId(themeId: Long): List -public interface ReservationRepository - extends JpaRepository, JpaSpecificationExecutor { - - List findByReservationTime(ReservationTimeEntity reservationTime); - - List findByThemeId(Long themeId); - - @Modifying - @Query(""" + @Modifying + @Query(""" UPDATE ReservationEntity r SET r.reservationStatus = :status WHERE r.id = :id """) - int updateStatusByReservationId(@Param(value = "id") Long reservationId, - @Param(value = "status") ReservationStatus statusForChange); + fun updateStatusByReservationId( + @Param(value = "id") reservationId: Long, + @Param(value = "status") statusForChange: ReservationStatus + ): Int - @Query(""" + @Query(""" SELECT EXISTS ( SELECT 1 FROM ReservationEntity r WHERE r.theme.id = r2.theme.id @@ -37,9 +36,9 @@ public interface ReservationRepository FROM ReservationEntity r2 WHERE r2.id = :id """) - boolean isExistConfirmedReservation(@Param("id") Long reservationId); + fun isExistConfirmedReservation(@Param("id") reservationId: Long): Boolean - @Query(""" + @Query(""" SELECT new roomescape.reservation.web.MyReservationResponse( r.id, t.name, @@ -56,5 +55,5 @@ public interface ReservationRepository ON p.reservation = r WHERE r.member.id = :memberId """) - List findMyReservations(Long memberId); + fun findMyReservations(memberId: Long): List } -- 2.47.2 From d89e662d233f315a05b6b287d8209b0ea8eeaef2 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 16:28:43 +0900 Subject: [PATCH 16/40] Rename .java to .kt --- .../{ReservationTimeService.java => ReservationTimeService.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/roomescape/reservation/business/{ReservationTimeService.java => ReservationTimeService.kt} (100%) diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.java b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt similarity index 100% rename from src/main/java/roomescape/reservation/business/ReservationTimeService.java rename to src/main/java/roomescape/reservation/business/ReservationTimeService.kt -- 2.47.2 From b0290e65ffca5dfc758f65c3503e2b9fe38e3360 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 16:28:43 +0900 Subject: [PATCH 17/40] =?UTF-8?q?refactor:=20ReservationTimeService=20?= =?UTF-8?q?=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/ReservationTimeService.kt | 164 ++++++++---------- .../persistence/ReservationEntity.kt | 2 +- .../reservation/web/ReservationResponse.kt | 4 + .../business/ReservationTimeServiceTest.java | 4 +- 4 files changed, 82 insertions(+), 92 deletions(-) diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt index 1d72210c..b9559fd2 100644 --- a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt +++ b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt @@ -1,103 +1,87 @@ -package roomescape.reservation.business; +package roomescape.reservation.business -import java.time.LocalDate; -import java.util.List; - -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.ReservationTimeInfoResponse; -import roomescape.reservation.web.ReservationTimeInfosResponse; -import roomescape.reservation.web.ReservationTimeRequest; -import roomescape.reservation.web.ReservationTimeResponse; -import roomescape.reservation.web.ReservationTimesResponse; +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 @Service -@Transactional -public class ReservationTimeService { +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 + ) - private final ReservationTimeRepository reservationTimeRepository; - private final ReservationRepository reservationRepository; - public ReservationTimeService( - ReservationTimeRepository reservationTimeRepository, - ReservationRepository reservationRepository - ) { - this.reservationTimeRepository = reservationTimeRepository; - this.reservationRepository = reservationRepository; - } + @Transactional(readOnly = true) + fun findAllTimes(): ReservationTimesResponse { + val response = reservationTimeRepository.findAll() + .map { it.toResponse() } - @Transactional(readOnly = true) - public ReservationTimeEntity findTimeById(Long id) { - return reservationTimeRepository.findById(id) - .orElseThrow(() -> new RoomescapeException(ErrorType.RESERVATION_TIME_NOT_FOUND, - String.format("[reservationTimeId: %d]", id), HttpStatus.BAD_REQUEST)); - } + return ReservationTimesResponse(response) + } - @Transactional(readOnly = true) - public ReservationTimesResponse findAllTimes() { - List response = reservationTimeRepository.findAll() - .stream() - .map(ReservationTimeResponse::from) - .toList(); + @Transactional + fun addTime(reservationTimeRequest: ReservationTimeRequest): ReservationTimeResponse { + validateIsDuplicatedTimeExists(reservationTimeRequest) - return new ReservationTimesResponse(response); - } + return ReservationTimeEntity(startAt = reservationTimeRequest.startAt) + .also { reservationTimeRepository.save(it) } + .toResponse() + } - public ReservationTimeResponse addTime(ReservationTimeRequest reservationTimeRequest) { - validateTimeDuplication(reservationTimeRequest); - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, reservationTimeRequest.startAt) - ); + private fun validateIsDuplicatedTimeExists(reservationTimeRequest: ReservationTimeRequest) { + reservationTimeRepository.findByStartAt(reservationTimeRequest.startAt) + .also { + if (it.isNotEmpty()) { + throw RoomescapeException( + ErrorType.TIME_DUPLICATED, "[startAt: $it]", HttpStatus.CONFLICT + ) + } + } + } - return ReservationTimeResponse.from(reservationTime); - } + @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) + } + } - private void validateTimeDuplication(ReservationTimeRequest reservationTimeRequest) { - List duplicateReservationTimes = reservationTimeRepository.findByStartAt( - reservationTimeRequest.startAt); + @Transactional(readOnly = true) + fun findAllAvailableTimesByDateAndTheme(date: LocalDate, themeId: Long): ReservationTimeInfosResponse { + val allTimes = reservationTimeRepository.findAll() + val reservations: List = reservationRepository.findByThemeId(themeId) - if (!duplicateReservationTimes.isEmpty()) { - throw new RoomescapeException(ErrorType.TIME_DUPLICATED, - String.format("[startAt: %s]", reservationTimeRequest.startAt), HttpStatus.CONFLICT); - } - } - - public void removeTimeById(Long id) { - ReservationTimeEntity reservationTime = findTimeById(id); - List usingTimeReservations = reservationRepository.findByReservationTime(reservationTime); - - if (!usingTimeReservations.isEmpty()) { - throw new RoomescapeException(ErrorType.TIME_IS_USED_CONFLICT, String.format("[timeId: %d]", id), - HttpStatus.CONFLICT); - } - - reservationTimeRepository.deleteById(id); - } - - @Transactional(readOnly = true) - public ReservationTimeInfosResponse findAllAvailableTimesByDateAndTheme(LocalDate date, Long themeId) { - List allTimes = reservationTimeRepository.findAll(); - List reservations = reservationRepository.findByThemeId(themeId); - - List response = allTimes.stream() - .map(time -> new ReservationTimeInfoResponse(time.getId(), time.getStartAt(), - isReservationBooked(reservations, date, time))) - .toList(); - - return new ReservationTimeInfosResponse(response); - } - - private boolean isReservationBooked(List reservations, LocalDate date, - ReservationTimeEntity time) { - return reservations.stream() - .anyMatch(reservation -> reservation.isSameDateAndTime(date, time)); - } + return ReservationTimeInfosResponse(allTimes + .map { time -> + ReservationTimeInfoResponse( + time.id!!, + time.startAt, + reservations.any { reservation -> reservation.hasSameDateTime(date, time) } + ) + } + ) + } } diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt index cd8970e3..211c8a77 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt @@ -33,7 +33,7 @@ class ReservationEntity( ) { @JsonIgnore - fun isSameDateAndTime(date: LocalDate?, time: ReservationTimeEntity): Boolean { + fun hasSameDateTime(date: LocalDate?, time: ReservationTimeEntity): Boolean { return this.date == date && time.startAt == this.reservationTime.startAt } diff --git a/src/main/java/roomescape/reservation/web/ReservationResponse.kt b/src/main/java/roomescape/reservation/web/ReservationResponse.kt index 548b5d56..e325369e 100644 --- a/src/main/java/roomescape/reservation/web/ReservationResponse.kt +++ b/src/main/java/roomescape/reservation/web/ReservationResponse.kt @@ -111,3 +111,7 @@ data class ReservationTimeResponse( } } } + +fun ReservationTimeEntity.toResponse(): ReservationTimeResponse = ReservationTimeResponse( + this.id!!, this.startAt +) diff --git a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java index 041afa70..2db88ab0 100644 --- a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java +++ b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java @@ -61,7 +61,8 @@ class ReservationTimeServiceTest { new ReservationTimeEntity(null, LocalTime.of(12, 30))); // when - Long invalidTimeId = saved.getId() + 1; + assert saved.getId() != null; + long invalidTimeId = saved.getId() + 1; // when & then assertThatThrownBy(() -> reservationTimeService.findTimeById(invalidTimeId)) @@ -85,6 +86,7 @@ class ReservationTimeServiceTest { ReservationStatus.CONFIRMED)); // then + assert reservationTime.getId() != null; assertThatThrownBy(() -> reservationTimeService.removeTimeById(reservationTime.getId())) .isInstanceOf(RoomescapeException.class); } -- 2.47.2 From a577df0b6aa88748baad355c267458c9819a5241 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 16:37:15 +0900 Subject: [PATCH 18/40] Rename .java to .kt --- ...ervationTimeServiceTest.java => ReservationTimeServiceTest.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/java/roomescape/reservation/business/{ReservationTimeServiceTest.java => ReservationTimeServiceTest.kt} (100%) diff --git a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt similarity index 100% rename from src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.java rename to src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt -- 2.47.2 From 4e7b850e8dc8de3c03d695b6cd9e6f5c1a5eb6e7 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 16:37:15 +0900 Subject: [PATCH 19/40] =?UTF-8?q?refactor:=20ReservationTimeService=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=ED=8B=80=EB=A6=B0=20?= =?UTF-8?q?=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/ReservationTimeService.kt | 7 +- .../reservation/web/ReservationTimeDTO.kt | 5 + .../business/ReservationTimeServiceTest.kt | 157 +++++++++--------- 3 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt index b9559fd2..9b2ff06b 100644 --- a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt +++ b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt @@ -28,12 +28,9 @@ class ReservationTimeService( @Transactional(readOnly = true) - fun findAllTimes(): ReservationTimesResponse { - val response = reservationTimeRepository.findAll() - .map { it.toResponse() } + fun findAllTimes(): ReservationTimesResponse = reservationTimeRepository.findAll() + .toResponses() - return ReservationTimesResponse(response) - } @Transactional fun addTime(reservationTimeRequest: ReservationTimeRequest): ReservationTimeResponse { diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt b/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt index 299c727b..e4d09e5d 100644 --- a/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt +++ b/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt @@ -1,6 +1,7 @@ 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 = "예약 시간 저장 요청시 사용됩니다.") @@ -38,3 +39,7 @@ data class ReservationTimesResponse( @field:Schema(description = "모든 시간 목록") val times: List ) + +fun List.toResponses(): ReservationTimesResponse = ReservationTimesResponse( + this.map { it.toResponse() } +) diff --git a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt index 2db88ab0..cb4a9342 100644 --- a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt +++ b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt @@ -1,93 +1,92 @@ -package roomescape.reservation.business; +package roomescape.reservation.business -import static org.assertj.core.api.Assertions.*; +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import org.springframework.data.repository.findByIdOrNull +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 java.time.LocalTime -import java.time.LocalDateTime; -import java.time.LocalTime; +class ReservationTimeServiceTest : FunSpec({ + val reservationTimeRepository: ReservationTimeRepository = mockk() + val reservationRepository: ReservationRepository = mockk() -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.Sql.ExecutionPhase; + val reservationTimeService = ReservationTimeService( + reservationTimeRepository = reservationTimeRepository, + reservationRepository = reservationRepository + ) -import roomescape.common.exception.RoomescapeException; -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.member.infrastructure.persistence.MemberRepository; -import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.infrastructure.persistence.ReservationEntity; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.reservation.web.ReservationTimeRequest; -import roomescape.theme.infrastructure.persistence.ThemeEntity; -import roomescape.theme.infrastructure.persistence.ThemeRepository; + context("findTimeById") { + test("시간을 찾을 수 없으면 400 에러를 던진다.") { + val id = 1L -@SpringBootTest -@Import(ReservationTimeService.class) -@Sql(scripts = "/truncate.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD) -class ReservationTimeServiceTest { + // Mocking the behavior of reservationTimeRepository.findByIdOrNull + every { reservationTimeRepository.findByIdOrNull(id) } returns null - @Autowired - private ReservationTimeService reservationTimeService; - @Autowired - private ReservationTimeRepository reservationTimeRepository; - @Autowired - private ReservationRepository reservationRepository; - @Autowired - private ThemeRepository themeRepository; - @Autowired - private MemberRepository memberRepository; + shouldThrow { + reservationTimeService.findTimeById(id) + }.apply { + errorType shouldBe ErrorType.RESERVATION_TIME_NOT_FOUND + httpStatus shouldBe HttpStatus.BAD_REQUEST + } + } + } - @Test - @DisplayName("중복된 예약 시간을 등록하는 경우 예외가 발생한다.") - void duplicateTimeFail() { - // given - reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(12, 30))); + context("addTime") { + test("중복된 시간이 있으면 409 에러를 던진다.") { + val request = ReservationTimeRequest(startAt = LocalTime.of(10, 0)) - // when & then - assertThatThrownBy(() -> reservationTimeService.addTime(new ReservationTimeRequest(LocalTime.of(12, 30)))) - .isInstanceOf(RoomescapeException.class); - } + // Mocking the behavior of reservationTimeRepository.findByStartAt + every { reservationTimeRepository.findByStartAt(request.startAt) } returns listOf(mockk()) - @Test - @DisplayName("존재하지 않는 ID로 시간을 조회하면 예외가 발생한다.") - void findTimeByIdFail() { - // given - ReservationTimeEntity saved = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(12, 30))); + shouldThrow { + reservationTimeService.addTime(request) + }.apply { + errorType shouldBe ErrorType.TIME_DUPLICATED + httpStatus shouldBe HttpStatus.CONFLICT + } + } + } - // when - assert saved.getId() != null; - long invalidTimeId = saved.getId() + 1; + context("removeTimeById") { + test("시간을 찾을 수 없으면 400 에러를 던진다.") { + val id = 1L - // when & then - assertThatThrownBy(() -> reservationTimeService.findTimeById(invalidTimeId)) - .isInstanceOf(RoomescapeException.class); - } + // Mocking the behavior of reservationTimeRepository.findByIdOrNull + every { reservationTimeRepository.findByIdOrNull(id) } returns null - @Test - @DisplayName("삭제하려는 시간에 예약이 존재하면 예외를 발생한다.") - void usingTimeDeleteFail() { - // given - LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + shouldThrow { + reservationTimeService.removeTimeById(id) + }.apply { + errorType shouldBe ErrorType.RESERVATION_TIME_NOT_FOUND + httpStatus shouldBe HttpStatus.BAD_REQUEST + } + } - // when - reservationRepository.save( - new ReservationEntity(null, localDateTime.toLocalDate(), reservationTime, theme, member, - ReservationStatus.CONFIRMED)); + test("예약이 있는 시간이면 409 에러를 던진다.") { + val id = 1L + val reservationTime = ReservationTimeFixture.create() - // then - assert reservationTime.getId() != null; - assertThatThrownBy(() -> reservationTimeService.removeTimeById(reservationTime.getId())) - .isInstanceOf(RoomescapeException.class); - } -} + // 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()) + + shouldThrow { + reservationTimeService.removeTimeById(id) + }.apply { + errorType shouldBe ErrorType.TIME_IS_USED_CONFLICT + httpStatus shouldBe HttpStatus.CONFLICT + } + } + } +}) -- 2.47.2 From 3127b19bc4fea52578638f5a86e2fa7194358e85 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 16:59:32 +0900 Subject: [PATCH 20/40] =?UTF-8?q?refactor:=20=EC=A4=91=EB=B3=B5=EB=90=9C?= =?UTF-8?q?=20=EC=8B=9C=EA=B0=84=EC=9D=84=20=ED=99=95=EC=9D=B8=ED=95=A0=20?= =?UTF-8?q?=EB=95=8C=20findByStartAt=20=EB=8C=80=EC=8B=A0=20existsByStartA?= =?UTF-8?q?t=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/ReservationTimeService.kt | 27 +++++++-------- .../persistence/ReservationTimeRepository.kt | 2 +- .../business/ReservationTimeServiceTest.kt | 2 +- .../ReservationTimeRepositoryTest.kt | 33 +++++++++++++++++++ 4 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepositoryTest.kt diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt index 9b2ff06b..2cfd3acb 100644 --- a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt +++ b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt @@ -12,6 +12,7 @@ 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( @@ -28,30 +29,24 @@ class ReservationTimeService( @Transactional(readOnly = true) - fun findAllTimes(): ReservationTimesResponse = reservationTimeRepository.findAll() - .toResponses() - + fun findAllTimes(): ReservationTimesResponse = reservationTimeRepository.findAll() + .toResponses() @Transactional fun addTime(reservationTimeRequest: ReservationTimeRequest): ReservationTimeResponse { - validateIsDuplicatedTimeExists(reservationTimeRequest) + val startAt: LocalTime = reservationTimeRequest.startAt - return ReservationTimeEntity(startAt = reservationTimeRequest.startAt) + if (reservationTimeRepository.existsByStartAt(startAt)) { + throw RoomescapeException( + ErrorType.TIME_DUPLICATED, "[startAt: $startAt]", HttpStatus.CONFLICT + ) + } + + return ReservationTimeEntity(startAt = startAt) .also { reservationTimeRepository.save(it) } .toResponse() } - private fun validateIsDuplicatedTimeExists(reservationTimeRequest: ReservationTimeRequest) { - reservationTimeRepository.findByStartAt(reservationTimeRequest.startAt) - .also { - if (it.isNotEmpty()) { - throw RoomescapeException( - ErrorType.TIME_DUPLICATED, "[startAt: $it]", HttpStatus.CONFLICT - ) - } - } - } - @Transactional fun removeTimeById(id: Long) { val reservationTime: ReservationTimeEntity = findTimeById(id) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt index 26b533b8..d4a03bcd 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepository.kt @@ -4,5 +4,5 @@ import org.springframework.data.jpa.repository.JpaRepository import java.time.LocalTime interface ReservationTimeRepository : JpaRepository { - fun findByStartAt(startAt: LocalTime): List + fun existsByStartAt(startAt: LocalTime): Boolean } diff --git a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt index cb4a9342..a1bedcfe 100644 --- a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt +++ b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt @@ -45,7 +45,7 @@ class ReservationTimeServiceTest : FunSpec({ val request = ReservationTimeRequest(startAt = LocalTime.of(10, 0)) // Mocking the behavior of reservationTimeRepository.findByStartAt - every { reservationTimeRepository.findByStartAt(request.startAt) } returns listOf(mockk()) + every { reservationTimeRepository.existsByStartAt(request.startAt) } returns true shouldThrow { reservationTimeService.addTime(request) diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepositoryTest.kt b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepositoryTest.kt new file mode 100644 index 00000000..ba7045a3 --- /dev/null +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationTimeRepositoryTest.kt @@ -0,0 +1,33 @@ +package roomescape.reservation.infrastructure.persistence + +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 java.time.LocalTime + +@DataJpaTest +class ReservationTimeRepositoryTest( + val entityManager: EntityManager, + val reservationTimeRepository: ReservationTimeRepository, +) : FunSpec({ + + context("existsByStartAt") { + val startAt = LocalTime.of(10, 0) + + beforeTest { + entityManager.persist(ReservationTimeFixture.create(startAt = startAt)) + entityManager.flush() + entityManager.clear() + } + + test("동일한 시간이 있으면 true 반환") { + reservationTimeRepository.existsByStartAt(startAt) shouldBe true + } + + test("동일한 시간이 없으면 false 반환") { + reservationTimeRepository.existsByStartAt(startAt.plusSeconds(1)) shouldBe false + } + } +}) -- 2.47.2 From 0ac7539734a0a2cd59cccf6b0d83d6564b2c0221 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 18:31:23 +0900 Subject: [PATCH 21/40] =?UTF-8?q?refactor:=20=EB=82=A0=EC=A7=9C,=20?= =?UTF-8?q?=ED=85=8C=EB=A7=88=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=98=88?= =?UTF-8?q?=EC=95=BD=20=EC=8B=9C=EA=B0=84=EC=9D=84=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=A0=20=EB=95=8C=20=EC=BF=BC=EB=A6=AC=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=82=A0=EC=A7=9C,=20=ED=85=8C=EB=A7=88=EB=A5=BC=20=EB=AA=A8?= =?UTF-8?q?=EB=91=90=20=EC=9E=85=EB=A0=A5=EB=B0=9B=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/ReservationTimeService.kt | 15 +++++---------- .../persistence/ReservationEntity.kt | 6 ------ .../persistence/ReservationRepository.kt | 6 +++--- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt index 2cfd3acb..5f940834 100644 --- a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt +++ b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt @@ -64,16 +64,11 @@ class ReservationTimeService( @Transactional(readOnly = true) fun findAllAvailableTimesByDateAndTheme(date: LocalDate, themeId: Long): ReservationTimeInfosResponse { val allTimes = reservationTimeRepository.findAll() - val reservations: List = reservationRepository.findByThemeId(themeId) + val reservations: List = reservationRepository.findByDateAndThemeId(date, themeId) - return ReservationTimeInfosResponse(allTimes - .map { time -> - ReservationTimeInfoResponse( - time.id!!, - time.startAt, - reservations.any { reservation -> reservation.hasSameDateTime(date, time) } - ) - } - ) + 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/infrastructure/persistence/ReservationEntity.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt index 211c8a77..f513d5c2 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt @@ -31,12 +31,6 @@ class ReservationEntity( @Enumerated(value = EnumType.STRING) var reservationStatus: ReservationStatus ) { - - @JsonIgnore - fun hasSameDateTime(date: LocalDate?, time: ReservationTimeEntity): Boolean { - return this.date == date && time.startAt == this.reservationTime.startAt - } - @JsonIgnore fun isWaiting(): Boolean = reservationStatus == ReservationStatus.WAITING diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt index 9b676727..85267cd1 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt @@ -6,13 +6,13 @@ import org.springframework.data.jpa.repository.Modifying import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.query.Param import roomescape.reservation.web.MyReservationResponse +import java.time.LocalDate interface ReservationRepository - : JpaRepository, JpaSpecificationExecutor -{ + : JpaRepository, JpaSpecificationExecutor { fun findByReservationTime(reservationTime: ReservationTimeEntity): List - fun findByThemeId(themeId: Long): List + fun findByDateAndThemeId(date: LocalDate, themeId: Long): List @Modifying @Query(""" -- 2.47.2 From 0307eefce2dd720ed85f37c64ddb6409fdf961e4 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 18:32:08 +0900 Subject: [PATCH 22/40] =?UTF-8?q?fix:=20=EC=9E=98=EB=AA=BB=20=EB=B6=84?= =?UTF-8?q?=EB=A5=98=EB=90=9C=20DTO=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/web/ReservationResponse.kt | 23 -------- .../reservation/web/ReservationTimeDTO.kt | 54 ++++++++++++++----- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/main/java/roomescape/reservation/web/ReservationResponse.kt b/src/main/java/roomescape/reservation/web/ReservationResponse.kt index e325369e..0503367b 100644 --- a/src/main/java/roomescape/reservation/web/ReservationResponse.kt +++ b/src/main/java/roomescape/reservation/web/ReservationResponse.kt @@ -6,7 +6,6 @@ import roomescape.member.web.MemberResponse import roomescape.member.web.MemberResponse.Companion.fromEntity import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity import roomescape.theme.web.ThemeResponse import java.time.LocalDate import java.time.LocalTime @@ -93,25 +92,3 @@ data class ReservationsResponse( val reservations: List ) -@Schema(name = "예약 시간 정보", description = "예약 시간 추가 및 조회 응답시 사용됩니다.") -@JvmRecord -data class ReservationTimeResponse( - @JvmField - @field:Schema(description = "예약 시간 번호. 예약 시간을 식별할 때 사용합니다.") - val id: Long, - - @field:Schema(description = "예약 시간", type = "string", example = "09:00") - val startAt: LocalTime -) { - - companion object { - @JvmStatic - fun from(reservationTime: ReservationTimeEntity): ReservationTimeResponse { - return ReservationTimeResponse(reservationTime.id!!, reservationTime.startAt) - } - } -} - -fun ReservationTimeEntity.toResponse(): ReservationTimeResponse = ReservationTimeResponse( - this.id!!, this.startAt -) diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt b/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt index e4d09e5d..e0b06678 100644 --- a/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt +++ b/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt @@ -12,25 +12,27 @@ data class ReservationTimeRequest( val startAt: LocalTime ) - -@Schema(name = "특정 테마, 날짜에 대한 시간 정보 응답", description = "특정 날짜와 테마에 대해, 예약 가능 여부를 포함한 시간 정보를 저장합니다.") +@Schema(name = "예약 시간 정보", description = "예약 시간 추가 및 조회 응답시 사용됩니다.") @JvmRecord -data class ReservationTimeInfoResponse( +data class ReservationTimeResponse( + @JvmField @field:Schema(description = "예약 시간 번호. 예약 시간을 식별할 때 사용합니다.") - val timeId: Long, + val id: Long, @field:Schema(description = "예약 시간", type = "string", example = "09:00") - val startAt: LocalTime, + val startAt: LocalTime +) { - @field:Schema(description = "이미 예약이 완료된 시간인지 여부") - val alreadyBooked: Boolean -) + companion object { + @JvmStatic + fun from(reservationTime: ReservationTimeEntity): ReservationTimeResponse { + return ReservationTimeResponse(reservationTime.id!!, reservationTime.startAt) + } + } +} -@Schema(name = "예약 시간 정보 목록 응답", description = "특정 테마, 날짜에 대한 모든 예약 가능 시간 정보를 저장합니다.") -@JvmRecord -data class ReservationTimeInfosResponse( - @field:Schema(description = "특정 테마, 날짜에 대한 예약 가능 여부를 포함한 시간 목록") - val reservationTimes: List +fun ReservationTimeEntity.toResponse(): ReservationTimeResponse = ReservationTimeResponse( + this.id!!, this.startAt ) @Schema(name = "예약 시간 정보 목록 응답", description = "모든 예약 시간 조회 응답시 사용됩니다.") @@ -43,3 +45,29 @@ data class ReservationTimesResponse( fun List.toResponses(): ReservationTimesResponse = ReservationTimesResponse( this.map { it.toResponse() } ) + +@Schema(name = "특정 테마, 날짜에 대한 시간 정보 응답", description = "특정 날짜와 테마에 대해, 예약 가능 여부를 포함한 시간 정보를 저장합니다.") +@JvmRecord +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 = "특정 테마, 날짜에 대한 모든 예약 가능 시간 정보를 저장합니다.") +@JvmRecord +data class ReservationTimeInfosResponse( + @field:Schema(description = "특정 테마, 날짜에 대한 예약 가능 여부를 포함한 시간 목록") + val times: List +) -- 2.47.2 From e7a060bd372449c3fcf9e78fb8f2e505a4e1da6d Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 18:32:40 +0900 Subject: [PATCH 23/40] =?UTF-8?q?fix:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=97=90=EC=84=9C=EC=9D=98=20=EC=9D=BC=EB=B6=80=20=EC=98=A4?= =?UTF-8?q?=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/theme/web/ThemeControllerTest.kt | 13 +++++++------ src/test/java/roomescape/util/RoomescapeApiTest.kt | 12 ++++-------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/test/java/roomescape/theme/web/ThemeControllerTest.kt b/src/test/java/roomescape/theme/web/ThemeControllerTest.kt index af3ea616..46893438 100644 --- a/src/test/java/roomescape/theme/web/ThemeControllerTest.kt +++ b/src/test/java/roomescape/theme/web/ThemeControllerTest.kt @@ -201,12 +201,13 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() { ) every { - themeRepository.existsByName(request.name) - } returns false - - every { - themeRepository.save(any()) - } returns theme + themeService.save(request) + } returns ThemeResponse( + id = theme.id!!, + name = theme.name, + description = theme.description, + thumbnail = theme.thumbnail + ) Then("201 응답을 받는다.") { runPostTest( diff --git a/src/test/java/roomescape/util/RoomescapeApiTest.kt b/src/test/java/roomescape/util/RoomescapeApiTest.kt index a26299a3..e8a0088d 100644 --- a/src/test/java/roomescape/util/RoomescapeApiTest.kt +++ b/src/test/java/roomescape/util/RoomescapeApiTest.kt @@ -1,7 +1,6 @@ package roomescape.util import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.ninjasquad.springmockk.MockkBean import com.ninjasquad.springmockk.SpykBean import io.kotest.core.spec.style.BehaviorSpec @@ -15,6 +14,7 @@ import roomescape.auth.infrastructure.jwt.JwtHandler import roomescape.auth.web.support.AdminInterceptor import roomescape.auth.web.support.LoginInterceptor import roomescape.auth.web.support.MemberIdResolver +import roomescape.common.config.JacksonConfig import roomescape.common.exception.ErrorType import roomescape.common.exception.RoomescapeException import roomescape.member.business.MemberService @@ -42,7 +42,7 @@ abstract class RoomescapeApiTest : BehaviorSpec() { @MockkBean lateinit var jwtHandler: JwtHandler - val objectMapper: ObjectMapper = jacksonObjectMapper() + val objectMapper: ObjectMapper = JacksonConfig().objectMapper() val admin: MemberEntity = MemberFixture.admin() val user: MemberEntity = MemberFixture.user() @@ -71,9 +71,7 @@ abstract class RoomescapeApiTest : BehaviorSpec() { } }.apply { log.takeIf { it }?.let { this.andDo { print() } } - }.andExpect { - assert - } + }.andExpect(assert) fun runDeleteTest( mockMvc: MockMvc, @@ -84,9 +82,7 @@ abstract class RoomescapeApiTest : BehaviorSpec() { header(HttpHeaders.COOKIE, "accessToken=token") }.apply { log.takeIf { it }?.let { this.andDo { print() } } - }.andExpect { - assert - } + }.andExpect(assert) fun loginAsAdmin() { every { -- 2.47.2 From b15b8b7ae84b2493284488b848359d0f17d95f04 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 18:32:55 +0900 Subject: [PATCH 24/40] Rename .java to .kt --- ...onTimeControllerTest.java => ReservationTimeControllerTest.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/java/roomescape/reservation/web/{ReservationTimeControllerTest.java => ReservationTimeControllerTest.kt} (100%) diff --git a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.kt similarity index 100% rename from src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.java rename to src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.kt -- 2.47.2 From 5c6c52cf41a23871e4dbaf0a9965be00107e8d9e Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 18:32:55 +0900 Subject: [PATCH 25/40] =?UTF-8?q?test:=20ReservationTimeController?= =?UTF-8?q?=EC=9D=98=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/ReservationTimeControllerTest.kt | 488 ++++++++++-------- 1 file changed, 270 insertions(+), 218 deletions(-) diff --git a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.kt b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.kt index 4848d971..71b4040a 100644 --- a/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.kt +++ b/src/test/java/roomescape/reservation/web/ReservationTimeControllerTest.kt @@ -1,254 +1,306 @@ -package roomescape.reservation.web; +package roomescape.reservation.web -import static org.hamcrest.Matchers.*; +import com.ninjasquad.springmockk.MockkBean +import com.ninjasquad.springmockk.SpykBean +import io.kotest.assertions.assertSoftly +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.shouldBe +import io.mockk.every +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.context.annotation.Import +import org.springframework.data.repository.findByIdOrNull +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.infrastructure.persistence.ReservationRepository +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity +import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository +import roomescape.util.ReservationFixture +import roomescape.util.ReservationTimeFixture +import roomescape.util.RoomescapeApiTest +import roomescape.util.ThemeFixture +import java.time.LocalDate +import java.time.LocalTime -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.Map; -import java.util.stream.Stream; +@WebMvcTest(ReservationTimeController::class) +@Import(JacksonConfig::class) +class ReservationTimeControllerTest( + val mockMvc: MockMvc, +) : RoomescapeApiTest() { -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.Sql.ExecutionPhase; + @SpykBean + private lateinit var reservationTimeService: ReservationTimeService -import io.restassured.RestAssured; -import io.restassured.http.ContentType; -import io.restassured.http.Header; -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.member.infrastructure.persistence.MemberRepository; -import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.infrastructure.persistence.ReservationEntity; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.theme.infrastructure.persistence.ThemeEntity; -import roomescape.theme.infrastructure.persistence.ThemeRepository; + @MockkBean + private lateinit var reservationTimeRepository: ReservationTimeRepository -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@Sql(scripts = "/truncate.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD) -public class ReservationTimeControllerTest { + @MockkBean + private lateinit var reservationRepository: ReservationRepository - @Autowired - private ReservationTimeRepository reservationTimeRepository; + init { + Given("등록된 모든 시간을 조회할 때") { + val endpoint = "/times" - @Autowired - private ThemeRepository themeRepository; + When("관리자인 경우") { + beforeTest { + loginAsAdmin() + } - @Autowired - private ReservationRepository reservationRepository; + Then("정상 응답") { + every { + reservationTimeRepository.findAll() + } returns listOf( + ReservationTimeFixture.create(id = 1L), + ReservationTimeFixture.create(id = 2L) + ) - @Autowired - private MemberRepository memberRepository; + runGetTest( + mockMvc = mockMvc, + endpoint = endpoint, + log = true + ) { + status { isOk() } + content { + contentType(MediaType.APPLICATION_JSON) + jsonPath("$.data.times[0].id") { value(1) } + jsonPath("$.data.times[1].id") { value(2) } + } + } + } + } - @LocalServerPort - private int port; + When("관리자가 아닌 경우") { + loginAsUser() - private final Map params = Map.of( - "startAt", "17:00" - ); + Then("로그인 페이지로 이동") { + runGetTest( + mockMvc = mockMvc, + endpoint = endpoint, + log = true + ) { + status { is3xxRedirection() } + header { string("Location", "/login") } + } + } + } + } - @Test - @DisplayName("처음으로 등록하는 시간의 id는 1이다.") - void firstPost() { - String adminAccessTokenCookie = getAdminAccessTokenCookieByLogin("email@email.com", "password"); + Given("시간을 추가할 때") { + val endpoint = "/times" - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .header(new Header("Cookie", adminAccessTokenCookie)) - .body(params) - .when().post("/times") - .then().log().all() - .statusCode(201) - .body("data.id", is(1)) - .header("Location", "/times/1"); - } + When("관리자인 경우") { + beforeTest { + loginAsAdmin() + } + val time = LocalTime.of(10, 0) + val request = ReservationTimeRequest(startAt = time) - @Test - @DisplayName("아무 시간도 등록 하지 않은 경우, 시간 목록 조회 결과 개수는 0개이다.") - void readEmptyTimes() { - String adminAccessTokenCookie = getAdminAccessTokenCookieByLogin("email@email.com", "password"); + Then("시간 형식이 HH:mm이 아니거나, 범위를 벗어나면 400 응답") { + listOf( + "{\"startAt\": \"23:30:30\"}", + "{\"startAt\": \"24:59\"}", + ).forEach { + runPostTest( + mockMvc = mockMvc, + endpoint = endpoint, + body = it, + log = true + ) { + status { isBadRequest() } + } + } + } - RestAssured.given().log().all() - .port(port) - .header(new Header("Cookie", adminAccessTokenCookie)) - .when().get("/times") - .then().log().all() - .statusCode(200) - .body("data.times.size()", is(0)); - } + Then("정상 응답") { + every { + reservationTimeService.addTime(request) + } returns ReservationTimeResponse(id = 1, startAt = time) - @Test - @DisplayName("하나의 시간만 등록한 경우, 시간 목록 조회 결과 개수는 1개이다.") - void readTimesSizeAfterFirstPost() { - String adminAccessTokenCookie = getAdminAccessTokenCookieByLogin("email@email.com", "password"); + runPostTest( + mockMvc = mockMvc, + endpoint = endpoint, + body = request, + log = true + ) { + status { isCreated() } + content { + contentType(MediaType.APPLICATION_JSON) + jsonPath("$.data.id") { value(1) } + jsonPath("$.data.startAt") { value("10:00") } + } + } + } - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .header(new Header("Cookie", adminAccessTokenCookie)) - .body(params) - .when().post("/times") - .then().log().all() - .statusCode(201) - .body("data.id", is(1)) - .header("Location", "/times/1"); + Then("동일한 시간이 존재하면 409 응답") { + every { + reservationTimeRepository.existsByStartAt(time) + } returns true - RestAssured.given().log().all() - .port(port) - .header(new Header("Cookie", adminAccessTokenCookie)) - .when().get("/times") - .then().log().all() - .statusCode(200) - .body("data.times.size()", is(1)); - } + runPostTest( + mockMvc = mockMvc, + endpoint = endpoint, + body = request, + log = true + ) { + status { isConflict() } + content { + contentType(MediaType.APPLICATION_JSON) + jsonPath("$.errorType") { value(ErrorType.TIME_DUPLICATED.name) } + } + } + } + } - @Test - @DisplayName("하나의 시간만 등록한 경우, 시간 삭제 뒤 시간 목록 조회 결과 개수는 0개이다.") - void readTimesSizeAfterPostAndDelete() { - String adminAccessTokenCookie = getAdminAccessTokenCookieByLogin("email@email.com", "password"); + When("관리자가 아닌 경우") { + loginAsUser() - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .header(new Header("Cookie", adminAccessTokenCookie)) - .body(params) - .when().post("/times") - .then().log().all() - .statusCode(201) - .body("data.id", is(1)) - .header("Location", "/times/1"); + Then("로그인 페이지로 이동") { + runPostTest( + mockMvc = mockMvc, + endpoint = endpoint, + body = ReservationTimeFixture.create(), + log = true + ) { + status { is3xxRedirection() } + header { string("Location", "/login") } + } + } + } + } - RestAssured.given().log().all() - .port(port) - .header(new Header("Cookie", adminAccessTokenCookie)) - .when().delete("/times/1") - .then().log().all() - .statusCode(204); + Given("시간을 삭제할 때") { + val endpoint = "/times/1" - RestAssured.given().log().all() - .port(port) - .header(new Header("Cookie", adminAccessTokenCookie)) - .when().get("/times") - .then().log().all() - .statusCode(200) - .body("data.times.size()", is(0)); - } + When("관리자인 경우") { + beforeTest { + loginAsAdmin() + } - @ParameterizedTest - @MethodSource("validateRequestDataFormatSource") - @DisplayName("예약 시간 생성 시, 시간 요청 데이터에 시간 포맷이 아닌 값이 입력되어오면 400 에러를 발생한다.") - void validateRequestDataFormat(Map request) { - String adminAccessTokenCookie = getAdminAccessTokenCookieByLogin("email@email.com", "password"); + Then("정상 응답") { + every { + reservationTimeService.removeTimeById(1L) + } returns Unit - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .header(new Header("Cookie", adminAccessTokenCookie)) - .port(port) - .body(request) - .when().post("/times") - .then().log().all() - .statusCode(400); - } + runDeleteTest( + mockMvc = mockMvc, + endpoint = endpoint, + log = true + ) { + status { isNoContent() } + } + } - static Stream> validateRequestDataFormatSource() { - return Stream.of( - Map.of( - "startAt", "24:59" - ), - Map.of( - "startAt", "hihi") - ); - } + Then("없는 시간을 조회하면 400 응답") { + val id = 1L + every { + reservationTimeRepository.findByIdOrNull(id) + } returns null - @ParameterizedTest - @MethodSource("validateBlankRequestSource") - @DisplayName("예약 시간 생성 시, 요청 값에 공백 또는 null이 포함되어 있으면 400 에러를 발생한다.") - void validateBlankRequest(Map request) { - String adminAccessTokenCookie = getAdminAccessTokenCookieByLogin("email@email.com", "password"); + runDeleteTest( + mockMvc = mockMvc, + endpoint = "/times/$id", + log = true + ) { + status { isBadRequest() } + content { + contentType(MediaType.APPLICATION_JSON) + jsonPath("$.errorType") { value(ErrorType.RESERVATION_TIME_NOT_FOUND.name) } + } + } + } - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .header(new Header("Cookie", adminAccessTokenCookie)) - .port(port) - .body(request) - .when().post("/times") - .then().log().all() - .statusCode(400); - } + Then("예약이 있는 시간을 삭제하면 409 응답") { + val id = 1L + every { + reservationTimeRepository.findByIdOrNull(id) + } returns ReservationTimeFixture.create(id = id) - static Stream> validateBlankRequestSource() { - return Stream.of( - Map.of( - ), - Map.of( - "startAt", "" - ), - Map.of( - "startAt", " " - ) - ); - } + every { + reservationRepository.findByReservationTime(any()) + } returns listOf(ReservationFixture.create()) - private String getAdminAccessTokenCookieByLogin(String email, String password) { - memberRepository.save(new MemberEntity(null, "이름", email, password, Role.ADMIN)); + runDeleteTest( + mockMvc = mockMvc, + endpoint = "/times/$id", + log = true + ) { + status { isConflict() } + content { + contentType(MediaType.APPLICATION_JSON) + jsonPath("$.errorType") { value(ErrorType.TIME_IS_USED_CONFLICT.name) } + } + } + } + } - Map loginParams = Map.of( - "email", email, - "password", password - ); + When("관리자가 아닌 경우") { + loginAsUser() - String accessToken = RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .body(loginParams) - .when().post("/login") - .then().log().all().extract().cookie("accessToken"); + Then("로그인 페이지로 이동") { + runDeleteTest( + mockMvc = mockMvc, + endpoint = endpoint, + log = true + ) { + status { is3xxRedirection() } + header { string("Location", "/login") } + } + } + } + } - return "accessToken=" + accessToken; - } + Given("날짜, 테마가 주어졌을 때") { + loginAsUser() - @Test - @DisplayName("특정 날짜의 특정 테마 예약 현황을 조회한다.") - void readReservationByDateAndThemeId() { - // given - LocalDate today = LocalDate.now(); - ReservationTimeEntity reservationTime1 = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 0))); - ReservationTimeEntity reservationTime2 = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - ReservationTimeEntity reservationTime3 = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(18, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명1", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + val date: LocalDate = LocalDate.now() + val themeId = 1L - reservationRepository.save( - new ReservationEntity(null, today.plusDays(1), reservationTime1, theme, member, - ReservationStatus.CONFIRMED)); - reservationRepository.save( - new ReservationEntity(null, today.plusDays(1), reservationTime2, theme, member, - ReservationStatus.CONFIRMED)); - reservationRepository.save( - new ReservationEntity(null, today.plusDays(1), reservationTime3, theme, member, - ReservationStatus.CONFIRMED)); + When("저장된 예약 시간이 있으면") { + val times: List = listOf( + ReservationTimeFixture.create(id = 1L, startAt = LocalTime.of(10, 0)), + ReservationTimeFixture.create(id = 2L, startAt = LocalTime.of(11, 0)) + ) - // when & then - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .header("Cookie", getAdminAccessTokenCookieByLogin("a@a.a", "a")) - .when().get("/times/filter?date={date}&themeId={themeId}", today.plusDays(1).toString(), theme.getId()) - .then().log().all() - .statusCode(200) - .body("data.reservationTimes.size()", is(3)); - } + every { + reservationTimeRepository.findAll() + } returns times + + Then("그 시간과, 해당 날짜와 테마에 대한 예약 여부가 담긴 목록을 응답") { + + every { + reservationRepository.findByDateAndThemeId(date, themeId) + } returns listOf( + ReservationFixture.create( + id = 1L, + date = date, + theme = ThemeFixture.create(id = themeId), + reservationTime = times[0] + ) + ) + + val response = runGetTest( + mockMvc = mockMvc, + endpoint = "/times/filter?date=$date&themeId=$themeId", + log = true + ) { + status { isOk() } + content { + contentType(MediaType.APPLICATION_JSON) + } + }.andReturn().readValue(ReservationTimeInfosResponse::class.java) + + assertSoftly(response.times) { + this shouldHaveSize times.size + this[0].id shouldBe times[0].id + this[0].alreadyBooked shouldBe true + + this[1].id shouldBe times[1].id + this[1].alreadyBooked shouldBe false + } + } + } + } + } } -- 2.47.2 From 976ca4951e8a7f5575fd0d1690d742378a79f281 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 18 Jul 2025 18:33:22 +0900 Subject: [PATCH 26/40] =?UTF-8?q?chore:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20Im?= =?UTF-8?q?port=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/docs/ReservationTimeAPI.kt | 14 +++----------- .../reservation/web/ReservationTimeController.kt | 15 --------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt b/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt index 5ed33cea..3b1535e2 100644 --- a/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt +++ b/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt @@ -1,25 +1,17 @@ package roomescape.reservation.docs import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.media.Content -import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses import io.swagger.v3.oas.annotations.tags.Tag -import jakarta.servlet.http.HttpServletResponse import jakarta.validation.Valid -import jakarta.validation.constraints.NotNull -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestBody +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.common.dto.response.RoomescapeApiResponse -import roomescape.common.dto.response.RoomescapeApiResponse.Companion.success -import roomescape.common.dto.response.RoomescapeErrorResponse import roomescape.reservation.web.ReservationTimeInfosResponse import roomescape.reservation.web.ReservationTimeRequest import roomescape.reservation.web.ReservationTimeResponse diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeController.kt b/src/main/java/roomescape/reservation/web/ReservationTimeController.kt index 5ccb18e3..6fb0147e 100644 --- a/src/main/java/roomescape/reservation/web/ReservationTimeController.kt +++ b/src/main/java/roomescape/reservation/web/ReservationTimeController.kt @@ -1,24 +1,9 @@ package roomescape.reservation.web -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.media.Content -import io.swagger.v3.oas.annotations.media.Schema -import io.swagger.v3.oas.annotations.responses.ApiResponse -import io.swagger.v3.oas.annotations.responses.ApiResponses -import jakarta.servlet.http.HttpServletResponse import jakarta.validation.Valid -import jakarta.validation.constraints.NotNull -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import roomescape.auth.web.support.Admin -import roomescape.auth.web.support.LoginRequired import roomescape.common.dto.response.CommonApiResponse -import roomescape.common.dto.response.RoomescapeApiResponse -import roomescape.common.dto.response.RoomescapeApiResponse.Companion.success -import roomescape.common.dto.response.RoomescapeErrorResponse import roomescape.reservation.business.ReservationTimeService import roomescape.reservation.docs.ReservationTimeAPI import java.net.URI -- 2.47.2 From 658207214caff7b92fcc6ef812190d170c701ed8 Mon Sep 17 00:00:00 2001 From: pricelees Date: Sat, 19 Jul 2025 22:16:59 +0900 Subject: [PATCH 27/40] =?UTF-8?q?fix:=20=ED=9A=8C=EC=9B=90=EC=9D=98=20?= =?UTF-8?q?=EC=98=88=EC=95=BD=20=ED=99=95=EC=A0=95=20=EC=97=AC=EB=B6=80?= =?UTF-8?q?=EB=A5=BC=20=ED=99=95=EC=9D=B8=ED=95=98=EB=8A=94=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=EC=97=90=EC=84=9C,=20=EC=9E=85=EB=A0=A5=EB=90=9C=20id?= =?UTF-8?q?=EA=B0=80=20=EC=97=86=EC=9C=BC=EB=A9=B4=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EB=A5=BC=20=EB=8D=98=EC=A7=80=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0(->=20false=20=EB=B0=98=ED=99=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/ReservationRepository.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt index 85267cd1..c14602b1 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt @@ -27,14 +27,11 @@ interface ReservationRepository @Query(""" SELECT EXISTS ( - SELECT 1 FROM ReservationEntity r - WHERE r.theme.id = r2.theme.id - AND r.reservationTime.id = r2.reservationTime.id - AND r.date = r2.date - AND r.reservationStatus != 'WAITING' + SELECT 1 + FROM ReservationEntity r + WHERE r.id = :id + AND r.reservationStatus != 'WAITING' ) - FROM ReservationEntity r2 - WHERE r2.id = :id """) fun isExistConfirmedReservation(@Param("id") reservationId: Long): Boolean -- 2.47.2 From 7751f8072124c952f85a223cb461bbc4a1de65e0 Mon Sep 17 00:00:00 2001 From: pricelees Date: Sat, 19 Jul 2025 22:17:15 +0900 Subject: [PATCH 28/40] =?UTF-8?q?test:=20ReservationRepository=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/ReservationRepositoryTest.kt | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt new file mode 100644 index 00000000..bfc85aba --- /dev/null +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt @@ -0,0 +1,200 @@ +package roomescape.reservation.infrastructure.persistence + +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.shouldBe +import jakarta.persistence.EntityManager +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.data.repository.findByIdOrNull +import roomescape.payment.infrastructure.persistence.PaymentEntity +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.ThemeFixture + +@DataJpaTest +class ReservationRepositoryTest( + val entityManager: EntityManager, + val reservationRepository: ReservationRepository, +) : FunSpec() { + init { + context("findByReservationTime") { + val time = ReservationTimeFixture.create() + + beforeTest { + listOf( + ReservationFixture.create(reservationTime = time), + ReservationFixture.create(reservationTime = ReservationTimeFixture.create( + startAt = time.startAt.plusSeconds(1) + )) + ).forEach { + persistReservation(it) + } + + entityManager.flush() + entityManager.clear() + } + + test("입력된 시간과 일치하는 예약을 반환한다.") { + assertSoftly(reservationRepository.findByReservationTime(time)) { + it shouldHaveSize 1 + assertSoftly(it.first().reservationTime.startAt) { result -> + result.hour shouldBe time.startAt.hour + result.minute shouldBe time.startAt.minute + } + } + } + } + + context("findByDateAndThemeId") { + val date = ReservationFixture.create().date + lateinit var theme1: ThemeEntity + lateinit var theme2: ThemeEntity + + beforeTest { + theme1 = ThemeFixture.create(name = "theme1").also { + entityManager.persist(it) + } + + theme2 = ThemeFixture.create(name = "theme2").also { + entityManager.persist(it) + } + + listOf( + ReservationFixture.create(date = date, theme = theme1), + ReservationFixture.create(date = date.plusDays(1), theme = theme1), + ReservationFixture.create(date = date, theme = theme2), + ).forEach { + entityManager.persist(it.reservationTime) + entityManager.persist(it.member) + entityManager.persist(it) + } + } + + test("입력된 날짜와 테마 ID에 해당하는 예약을 반환한다.") { + assertSoftly(reservationRepository.findByDateAndThemeId(date, theme1.id!!)) { + it shouldHaveSize 1 + it.first().theme shouldBe theme1 + } + } + } + + context("updateStatusByReservationId") { + lateinit var reservation: ReservationEntity + + beforeTest { + reservation = ReservationFixture.create().also { + persistReservation(it) + } + + entityManager.flush() + entityManager.clear() + } + + test("예약 상태를 업데이트한다.") { + ReservationStatus.entries.forEach { + val reservationId = reservation.id!! + val updatedRows = reservationRepository.updateStatusByReservationId(reservationId, it) + updatedRows shouldBe 1 + + entityManager.flush() + entityManager.clear() + + reservationRepository.findByIdOrNull(reservationId)?.also { updated -> + updated.reservationStatus shouldBe it + } + } + } + } + + context("isExistConfirmedReservation") { + lateinit var waiting: ReservationEntity + lateinit var confirmed: ReservationEntity + lateinit var confirmedPaymentRequired: ReservationEntity + + beforeTest { + waiting = ReservationFixture.create(status = ReservationStatus.WAITING).also { + persistReservation(it) + } + + confirmed = ReservationFixture.create(status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED).also { + persistReservation(it) + } + + confirmedPaymentRequired = ReservationFixture.create(status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED).also { + persistReservation(it) + } + + entityManager.flush() + entityManager.clear() + } + + test("예약이 없으면 false를 반환한다.") { + val maxId: Long = listOf(waiting, confirmed, confirmedPaymentRequired) + .maxOfOrNull { it.id ?: 0L } ?: 0L + reservationRepository.isExistConfirmedReservation(maxId + 1L) shouldBe false + } + + test("예약이 대기중이면 false를 반환한다.") { + reservationRepository.isExistConfirmedReservation(waiting.id!!) shouldBe false + } + + test("예약이 결제 완료 상태이면 true를 반환한다.") { + reservationRepository.isExistConfirmedReservation(confirmed.id!!) shouldBe true + } + + test("예약이 결제 대기 상태이면 true를 반환한다.") { + reservationRepository.isExistConfirmedReservation(confirmedPaymentRequired.id!!) shouldBe true + } + } + + context("findMyReservations") { + lateinit var reservation: ReservationEntity + + beforeTest { + reservation = ReservationFixture.create() + persistReservation(reservation) + } + + test("결제 정보를 포함한 회원의 예약 목록을 반환한다.") { + val payment: PaymentEntity = PaymentFixture.create( + reservationId = reservation.id!! + ).also { + entityManager.persist(it) + entityManager.flush() + entityManager.clear() + } + + val result: List = reservationRepository.findMyReservations(reservation.member.id!!) + + result shouldHaveSize 1 + assertSoftly(result.first()) { + it.id shouldBe reservation.id + it.paymentKey shouldBe payment.paymentKey + it.amount shouldBe payment.totalAmount + } + } + + test("결제 정보가 없다면 paymentKey와 amount는 null로 반환한다.") { + val result: List = reservationRepository.findMyReservations(reservation.member.id!!) + + result shouldHaveSize 1 + assertSoftly(result.first()) { + it.id shouldBe reservation.id + it.paymentKey shouldBe null + it.amount shouldBe null + } + } + } + } + + fun persistReservation(reservation: ReservationEntity) { + entityManager.persist(reservation.reservationTime) + entityManager.persist(reservation.theme) + entityManager.persist(reservation.member) + entityManager.persist(reservation) + } +} -- 2.47.2 From 186884e6ce38a380472237581f52b1f8d3e402d1 Mon Sep 17 00:00:00 2001 From: pricelees Date: Sat, 19 Jul 2025 22:17:34 +0900 Subject: [PATCH 29/40] Rename .java to .kt --- .../business/{ReservationService.java => ReservationService.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/roomescape/reservation/business/{ReservationService.java => ReservationService.kt} (100%) diff --git a/src/main/java/roomescape/reservation/business/ReservationService.java b/src/main/java/roomescape/reservation/business/ReservationService.kt similarity index 100% rename from src/main/java/roomescape/reservation/business/ReservationService.java rename to src/main/java/roomescape/reservation/business/ReservationService.kt -- 2.47.2 From 036947153d842a69770b99012423f473fbe67ee1 Mon Sep 17 00:00:00 2001 From: pricelees Date: Sat, 19 Jul 2025 22:17:34 +0900 Subject: [PATCH 30/40] =?UTF-8?q?refactor:=20ReservationService=20?= =?UTF-8?q?=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/ReservationService.kt | 403 +++++++++--------- .../reservation/web/ReservationResponse.kt | 12 +- 2 files changed, 221 insertions(+), 194 deletions(-) diff --git a/src/main/java/roomescape/reservation/business/ReservationService.kt b/src/main/java/roomescape/reservation/business/ReservationService.kt index e38c0f98..f93c7eb3 100644 --- a/src/main/java/roomescape/reservation/business/ReservationService.kt +++ b/src/main/java/roomescape/reservation/business/ReservationService.kt @@ -1,227 +1,244 @@ -package roomescape.reservation.business; +package roomescape.reservation.business -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.List; - -import org.springframework.data.jpa.domain.Specification; -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.infrastructure.persistence.ReservationEntity; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; -import roomescape.reservation.infrastructure.persistence.ReservationSearchSpecification; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; -import roomescape.reservation.web.AdminReservationRequest; -import roomescape.reservation.web.MyReservationsResponse; -import roomescape.reservation.web.ReservationRequest; -import roomescape.reservation.web.ReservationResponse; -import roomescape.reservation.web.ReservationsResponse; -import roomescape.reservation.web.WaitingRequest; -import roomescape.theme.business.ThemeService; -import roomescape.theme.infrastructure.persistence.ThemeEntity; +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.reservation.infrastructure.persistence.* +import roomescape.reservation.web.* +import roomescape.theme.business.ThemeService +import java.time.LocalDate +import java.time.LocalDateTime @Service @Transactional -public class ReservationService { +class ReservationService( + private val reservationRepository: ReservationRepository, + private val reservationTimeService: ReservationTimeService, + private val memberService: MemberService, + private val themeService: ThemeService, +) { - private final ReservationRepository reservationRepository; - private final ReservationTimeService reservationTimeService; - private final MemberService memberService; - private final ThemeService themeService; + @Transactional(readOnly = true) + fun findAllReservations(): ReservationsResponse { + val spec: Specification = ReservationSearchSpecification() + .confirmed() + .build() - public ReservationService( - ReservationRepository reservationRepository, - ReservationTimeService reservationTimeService, - MemberService memberService, - ThemeService themeService - ) { - this.reservationRepository = reservationRepository; - this.reservationTimeService = reservationTimeService; - this.memberService = memberService; - this.themeService = themeService; - } - @Transactional(readOnly = true) - public ReservationsResponse findAllReservations() { - Specification spec = new ReservationSearchSpecification().confirmed().build(); - List response = findAllReservationByStatus(spec); + return ReservationsResponse(findAllReservationByStatus(spec)) + } - return new ReservationsResponse(response); - } + @Transactional(readOnly = true) + fun findAllWaiting(): ReservationsResponse { + val spec: Specification = ReservationSearchSpecification() + .waiting() + .build() - @Transactional(readOnly = true) - public ReservationsResponse findAllWaiting() { - Specification spec = new ReservationSearchSpecification().waiting().build(); - List response = findAllReservationByStatus(spec); + return ReservationsResponse(findAllReservationByStatus(spec)) + } - return new ReservationsResponse(response); - } + private fun findAllReservationByStatus(spec: Specification): List { + return reservationRepository.findAll(spec).map { it.toResponse() } + } - private List findAllReservationByStatus(Specification spec) { - return reservationRepository.findAll(spec) - .stream() - .map(ReservationResponse::from) - .toList(); - } + fun removeReservationById(reservationId: Long, memberId: Long) { + validateIsMemberAdmin(memberId) + reservationRepository.deleteById(reservationId) + } - public void removeReservationById(Long reservationId, Long memberId) { - validateIsMemberAdmin(memberId); - reservationRepository.deleteById(reservationId); - } + fun addReservation(request: ReservationRequest, 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) + } + } - public ReservationEntity addReservation(ReservationRequest request, Long memberId) { - validateIsReservationExist(request.themeId, request.timeId, request.date); - ReservationEntity reservation = getReservationForSave(request.timeId, request.themeId, request.date, memberId, - ReservationStatus.CONFIRMED); - return reservationRepository.save(reservation); - } + fun addReservationByAdmin(request: AdminReservationRequest): ReservationResponse { + validateIsReservationExist(request.themeId, request.timeId, request.date) - public ReservationResponse addReservationByAdmin(AdminReservationRequest request) { - validateIsReservationExist(request.themeId, request.timeId, request.date); - return addReservationWithoutPayment(request.themeId, request.timeId, request.date, - request.memberId, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED); - } + return addReservationWithoutPayment( + request.themeId, + request.timeId, + request.date, + request.memberId, + ReservationStatus.CONFIRMED_PAYMENT_REQUIRED + ) + } - public ReservationResponse addWaiting(WaitingRequest request, Long memberId) { - validateMemberAlreadyReserve(request.themeId, request.timeId, request.date, memberId); - return addReservationWithoutPayment(request.themeId, request.timeId, request.date, memberId, - ReservationStatus.WAITING); - } + fun addWaiting(request: WaitingRequest, memberId: Long): ReservationResponse { + validateMemberAlreadyReserve(request.themeId, request.timeId, request.date, memberId) + return addReservationWithoutPayment( + request.themeId, + request.timeId, + request.date, + memberId, + ReservationStatus.WAITING + ) + } - private ReservationResponse addReservationWithoutPayment(Long themeId, Long timeId, LocalDate date, Long memberId, - ReservationStatus status) { - ReservationEntity reservation = getReservationForSave(timeId, themeId, date, memberId, status); - ReservationEntity saved = reservationRepository.save(reservation); - return ReservationResponse.from(saved); - } + private fun addReservationWithoutPayment( + themeId: Long, + timeId: Long, + date: LocalDate, + memberId: Long, + status: ReservationStatus + ): ReservationResponse = getReservationForSave(timeId, themeId, date, memberId, status) + .also { + reservationRepository.save(it) + }.toResponse() - private void validateMemberAlreadyReserve(Long themeId, Long timeId, LocalDate date, Long memberId) { - Specification spec = new ReservationSearchSpecification() - .sameMemberId(memberId) - .sameThemeId(themeId) - .sameTimeId(timeId) - .sameDate(date) - .build(); - if (reservationRepository.exists(spec)) { - throw new RoomescapeException(ErrorType.HAS_RESERVATION_OR_WAITING, HttpStatus.BAD_REQUEST); - } - } + private fun validateMemberAlreadyReserve(themeId: Long?, timeId: Long?, date: LocalDate?, memberId: Long?) { + val spec: Specification = ReservationSearchSpecification() + .sameMemberId(memberId) + .sameThemeId(themeId) + .sameTimeId(timeId) + .sameDate(date) + .build() - private void validateIsReservationExist(Long themeId, Long timeId, LocalDate date) { - Specification spec = new ReservationSearchSpecification() - .confirmed() - .sameThemeId(themeId) - .sameTimeId(timeId) - .sameDate(date) - .build(); + if (reservationRepository.exists(spec)) { + throw RoomescapeException(ErrorType.HAS_RESERVATION_OR_WAITING, HttpStatus.BAD_REQUEST) + } + } - if (reservationRepository.exists(spec)) { - throw new RoomescapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT); - } - } + private fun validateIsReservationExist(themeId: Long, timeId: Long, date: LocalDate) { + val spec: Specification = ReservationSearchSpecification() + .confirmed() + .sameThemeId(themeId) + .sameTimeId(timeId) + .sameDate(date) + .build() - private void validateDateAndTime( - LocalDate requestDate, - ReservationTimeEntity requestReservationTime - ) { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime request = LocalDateTime.of(requestDate, requestReservationTime.getStartAt()); - if (request.isBefore(now)) { - throw new RoomescapeException(ErrorType.RESERVATION_PERIOD_IN_PAST, - String.format("[now: %s %s | request: %s %s]", - now.toLocalDate(), now.toLocalTime(), requestDate, requestReservationTime.getStartAt()), - HttpStatus.BAD_REQUEST - ); - } - } + if (reservationRepository.exists(spec)) { + throw RoomescapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT) + } + } - private ReservationEntity getReservationForSave(Long timeId, Long themeId, LocalDate date, Long memberId, - ReservationStatus status) { - ReservationTimeEntity time = reservationTimeService.findTimeById(timeId); - ThemeEntity theme = themeService.findThemeById(themeId); - MemberEntity member = memberService.findById(memberId); + private fun validateDateAndTime( + requestDate: LocalDate, + requestReservationTime: ReservationTimeEntity + ) { + val now = LocalDateTime.now() + val request = LocalDateTime.of(requestDate, requestReservationTime.startAt) - validateDateAndTime(date, time); - return new ReservationEntity(null, date, time, theme, member, status); - } + if (request.isBefore(now)) { + throw RoomescapeException( + ErrorType.RESERVATION_PERIOD_IN_PAST, + "[now: $now | request: $request]", + HttpStatus.BAD_REQUEST + ) + } + } - @Transactional(readOnly = true) - public ReservationsResponse findFilteredReservations(Long themeId, Long memberId, LocalDate dateFrom, - LocalDate dateTo) { - validateDateForSearch(dateFrom, dateTo); - Specification spec = new ReservationSearchSpecification() - .confirmed() - .sameThemeId(themeId) - .sameMemberId(memberId) - .dateStartFrom(dateFrom) - .dateEndAt(dateTo) - .build(); + private fun getReservationForSave( + timeId: Long, + themeId: Long, + date: LocalDate, + memberId: Long, + status: ReservationStatus + ): ReservationEntity { + val time = reservationTimeService.findTimeById(timeId) + val theme = themeService.findThemeById(themeId) + val member = memberService.findById(memberId) - List response = reservationRepository.findAll(spec) - .stream() - .map(ReservationResponse::from) - .toList(); + validateDateAndTime(date, time) - return new ReservationsResponse(response); - } + return ReservationEntity( + date = date, + reservationTime = time, + theme = theme, + member = member, + reservationStatus = status + ) + } - private void validateDateForSearch(LocalDate startFrom, LocalDate endAt) { - if (startFrom == null || endAt == null) { - return; - } - if (startFrom.isAfter(endAt)) { - throw new RoomescapeException(ErrorType.INVALID_DATE_RANGE, - String.format("[startFrom: %s, endAt: %s", startFrom, endAt), HttpStatus.BAD_REQUEST); - } - } + @Transactional(readOnly = true) + fun findFilteredReservations( + themeId: Long?, + memberId: Long?, + dateFrom: LocalDate?, + dateTo: LocalDate? + ): ReservationsResponse { + validateDateForSearch(dateFrom, dateTo) + val spec: Specification = ReservationSearchSpecification() + .confirmed() + .sameThemeId(themeId) + .sameMemberId(memberId) + .dateStartFrom(dateFrom) + .dateEndAt(dateTo) + .build() - @Transactional(readOnly = true) - public MyReservationsResponse findMemberReservations(Long memberId) { - return new MyReservationsResponse(reservationRepository.findMyReservations(memberId)); - } + return ReservationsResponse(findAllReservationByStatus(spec)) + } - public void approveWaiting(Long reservationId, Long memberId) { - validateIsMemberAdmin(memberId); - if (reservationRepository.isExistConfirmedReservation(reservationId)) { - throw new RoomescapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT); - } - reservationRepository.updateStatusByReservationId(reservationId, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED); - } + private fun validateDateForSearch(startFrom: LocalDate?, endAt: LocalDate?) { + if (startFrom == null || endAt == null) { + return + } + if (startFrom.isAfter(endAt)) { + throw RoomescapeException( + ErrorType.INVALID_DATE_RANGE, + "[startFrom: $startFrom, endAt: $endAt", HttpStatus.BAD_REQUEST + ) + } + } - public void cancelWaiting(Long reservationId, Long memberId) { - ReservationEntity waiting = reservationRepository.findById(reservationId) - .filter(ReservationEntity::isWaiting) - .filter(r -> r.isSameMember(memberId)) - .orElseThrow(() -> throwReservationNotFound(reservationId)); - reservationRepository.delete(waiting); - } + @Transactional(readOnly = true) + fun findMemberReservations(memberId: Long): MyReservationsResponse { + return MyReservationsResponse(reservationRepository.findMyReservations(memberId)) + } - public void denyWaiting(Long reservationId, Long memberId) { - validateIsMemberAdmin(memberId); - ReservationEntity waiting = reservationRepository.findById(reservationId) - .filter(ReservationEntity::isWaiting) - .orElseThrow(() -> throwReservationNotFound(reservationId)); - reservationRepository.delete(waiting); - } + fun approveWaiting(reservationId: Long, memberId: Long) { + validateIsMemberAdmin(memberId) + if (reservationRepository. isExistConfirmedReservation(reservationId)) { + throw RoomescapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT) + } + reservationRepository.updateStatusByReservationId(reservationId, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED) + } - private void validateIsMemberAdmin(Long memberId) { - MemberEntity member = memberService.findById(memberId); - if (member.isAdmin()) { - return; - } - throw new RoomescapeException(ErrorType.PERMISSION_DOES_NOT_EXIST, HttpStatus.FORBIDDEN); - } + fun cancelWaiting(reservationId: Long, memberId: Long) { + reservationRepository.findByIdOrNull(reservationId)?.takeIf { + it.isWaiting() && it.isSameMember(memberId) + }?.let { + reservationRepository.delete(it) + } ?: throw throwReservationNotFound(reservationId) + } - private RoomescapeException throwReservationNotFound(Long reservationId) { - return new RoomescapeException(ErrorType.RESERVATION_NOT_FOUND, - String.format("[reservationId: %d]", reservationId), HttpStatus.NOT_FOUND); - } + fun denyWaiting(reservationId: Long, memberId: Long) { + validateIsMemberAdmin(memberId) + reservationRepository.findByIdOrNull(reservationId)?.takeIf { + it.isWaiting() + }?.let { + reservationRepository.delete(it) + } ?: throw throwReservationNotFound(reservationId) + } + + private fun validateIsMemberAdmin(memberId: Long) { + memberService.findById(memberId).takeIf { + it.isAdmin() + } ?: throw RoomescapeException( + ErrorType.PERMISSION_DOES_NOT_EXIST, + "[memberId: $memberId]", + HttpStatus.FORBIDDEN + ) + } + + private fun throwReservationNotFound(reservationId: Long?): RoomescapeException { + return RoomescapeException( + ErrorType.RESERVATION_NOT_FOUND, + "[reservationId: $reservationId]", + HttpStatus.NOT_FOUND + ) + } } diff --git a/src/main/java/roomescape/reservation/web/ReservationResponse.kt b/src/main/java/roomescape/reservation/web/ReservationResponse.kt index 0503367b..35e6eb36 100644 --- a/src/main/java/roomescape/reservation/web/ReservationResponse.kt +++ b/src/main/java/roomescape/reservation/web/ReservationResponse.kt @@ -4,9 +4,11 @@ import com.fasterxml.jackson.annotation.JsonProperty import io.swagger.v3.oas.annotations.media.Schema import roomescape.member.web.MemberResponse import roomescape.member.web.MemberResponse.Companion.fromEntity +import roomescape.member.web.toResponse import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationStatus import roomescape.theme.web.ThemeResponse +import roomescape.theme.web.toResponse import java.time.LocalDate import java.time.LocalTime @@ -85,10 +87,18 @@ data class ReservationResponse( } } +fun ReservationEntity.toResponse(): ReservationResponse = ReservationResponse( + id = this.id!!, + date = this.date, + member = this.member.toResponse(), + time = this.reservationTime.toResponse(), + theme = this.theme.toResponse(), + status = this.reservationStatus +) + @Schema(name = "예약 목록 조회 응답", description = "모든 예약 정보 조회 응답시 사용됩니다.") @JvmRecord data class ReservationsResponse( @field:Schema(description = "모든 예약 및 대기 목록") val reservations: List ) - -- 2.47.2 From c2d4e10160e95ab460a815cb930bcc7b4ccd9d7d Mon Sep 17 00:00:00 2001 From: pricelees Date: Sat, 19 Jul 2025 22:41:27 +0900 Subject: [PATCH 31/40] =?UTF-8?q?fix:=20=ED=9A=8C=EC=9B=90=EC=9D=98=20?= =?UTF-8?q?=EC=98=88=EC=95=BD=20=ED=99=95=EC=A0=95=20=EC=97=AC=EB=B6=80?= =?UTF-8?q?=EB=A5=BC=20=ED=99=95=EC=9D=B8=ED=95=98=EB=8A=94=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=EC=97=90=EC=84=9C,=20=EC=9E=85=EB=A0=A5=EB=90=9C=20id?= =?UTF-8?q?=EA=B0=80=20=EC=97=86=EC=9C=BC=EB=A9=B4=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EB=A5=BC=20=EB=8D=98=EC=A7=80=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0(->=20false=20=EB=B0=98=ED=99=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/business/ReservationService.kt | 2 +- .../persistence/ReservationRepository.kt | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/roomescape/reservation/business/ReservationService.kt b/src/main/java/roomescape/reservation/business/ReservationService.kt index f93c7eb3..1047b9c7 100644 --- a/src/main/java/roomescape/reservation/business/ReservationService.kt +++ b/src/main/java/roomescape/reservation/business/ReservationService.kt @@ -201,7 +201,7 @@ class ReservationService( fun approveWaiting(reservationId: Long, memberId: Long) { validateIsMemberAdmin(memberId) - if (reservationRepository. isExistConfirmedReservation(reservationId)) { + if (reservationRepository.isExistConfirmedReservation(reservationId)) { throw RoomescapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT) } reservationRepository.updateStatusByReservationId(reservationId, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED) diff --git a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt index c14602b1..5d17d47a 100644 --- a/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt +++ b/src/main/java/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt @@ -28,11 +28,17 @@ interface ReservationRepository @Query(""" SELECT EXISTS ( SELECT 1 - FROM ReservationEntity r - WHERE r.id = :id - AND r.reservationStatus != 'WAITING' - ) - """) + FROM ReservationEntity r2 + WHERE r2.id = :id + AND EXISTS ( + SELECT 1 FROM ReservationEntity r + WHERE r.theme.id = r2.theme.id + AND r.reservationTime.id = r2.reservationTime.id + AND r.date = r2.date + AND r.reservationStatus != 'WAITING' + ) + ) + """) fun isExistConfirmedReservation(@Param("id") reservationId: Long): Boolean @Query(""" -- 2.47.2 From 2b234511ac00c7b8b4697b8c8f059a5598411c8c Mon Sep 17 00:00:00 2001 From: pricelees Date: Sun, 20 Jul 2025 16:37:43 +0900 Subject: [PATCH 32/40] =?UTF-8?q?test:=20ReservationService=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/ReservationServiceTest.java | 239 ------------------ .../business/ReservationServiteTest.kt | 175 +++++++++++++ src/test/java/roomescape/util/Fixtures.kt | 30 +++ 3 files changed, 205 insertions(+), 239 deletions(-) delete mode 100644 src/test/java/roomescape/reservation/business/ReservationServiceTest.java create mode 100644 src/test/java/roomescape/reservation/business/ReservationServiteTest.kt diff --git a/src/test/java/roomescape/reservation/business/ReservationServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationServiceTest.java deleted file mode 100644 index d9a2a2c9..00000000 --- a/src/test/java/roomescape/reservation/business/ReservationServiceTest.java +++ /dev/null @@ -1,239 +0,0 @@ -package roomescape.reservation.business; - -import static org.assertj.core.api.Assertions.*; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.Sql.ExecutionPhase; - -import roomescape.common.exception.RoomescapeException; -import roomescape.member.business.MemberService; -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.member.infrastructure.persistence.MemberRepository; -import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.infrastructure.persistence.ReservationEntity; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.reservation.web.ReservationRequest; -import roomescape.reservation.web.ReservationResponse; -import roomescape.reservation.web.WaitingRequest; -import roomescape.theme.business.ThemeService; -import roomescape.theme.infrastructure.persistence.ThemeEntity; -import roomescape.theme.infrastructure.persistence.ThemeRepository; - -@SpringBootTest -@Sql(scripts = "/truncate.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD) -@Import({ReservationService.class, MemberService.class, ReservationTimeService.class, ThemeService.class}) -class ReservationServiceTest { - - @Autowired - ReservationTimeRepository reservationTimeRepository; - @Autowired - ReservationRepository reservationRepository; - @Autowired - ThemeRepository themeRepository; - @Autowired - MemberRepository memberRepository; - @Autowired - private ReservationService reservationService; - - @Test - @DisplayName("예약을 추가할때 이미 예약이 존재하면 예외가 발생한다.") - void reservationAlreadyExistFail() { - // given - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(12, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member1 = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - MemberEntity member2 = memberRepository.save( - new MemberEntity(null, "name2", "email2@email.com", "password", Role.MEMBER)); - LocalDate date = LocalDate.now().plusDays(1L); - - // when - reservationService.addReservation( - new ReservationRequest(date, reservationTime.getId(), theme.getId(), "paymentKey", "orderId", - 1000L, "paymentType"), member2.getId()); - - // then - assertThatThrownBy(() -> reservationService.addReservation( - new ReservationRequest(date, reservationTime.getId(), theme.getId(), "paymentKey", "orderId", - 1000L, "paymentType"), member1.getId())) - .isInstanceOf(RoomescapeException.class); - } - - @Test - @DisplayName("이미 예약한 멤버가 같은 테마에 대기를 신청하면 예외가 발생한다.") - void requestWaitWhenAlreadyReserveFail() { - // given - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(12, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - LocalDate date = LocalDate.now().plusDays(1L); - - // when - reservationService.addReservation( - new ReservationRequest(date, reservationTime.getId(), theme.getId(), "paymentKey", "orderId", - 1000L, "paymentType"), member.getId()); - - // then - assertThatThrownBy(() -> reservationService.addWaiting( - new WaitingRequest(date, reservationTime.getId(), theme.getId()), member.getId())) - .isInstanceOf(RoomescapeException.class); - } - - @Test - @DisplayName("예약 대기를 두 번 이상 요청하면 예외가 발생한다.") - void requestWaitTwiceFail() { - // given - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(12, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - MemberEntity member1 = memberRepository.save( - new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); - LocalDate date = LocalDate.now().plusDays(1L); - - // when - reservationService.addReservation( - new ReservationRequest(date, reservationTime.getId(), theme.getId(), "paymentKey", "orderId", - 1000L, "paymentType"), member.getId()); - - reservationService.addWaiting( - new WaitingRequest(date, reservationTime.getId(), theme.getId()), member1.getId()); - - // then - assertThatThrownBy(() -> reservationService.addWaiting( - new WaitingRequest(date, reservationTime.getId(), theme.getId()), member1.getId())) - .isInstanceOf(RoomescapeException.class); - } - - @Test - @DisplayName("이미 지난 날짜로 예약을 생성하면 예외가 발생한다.") - void beforeDateReservationFail() { - // given - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(12, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - LocalDate beforeDate = LocalDate.now().minusDays(1L); - - // when & then - assertThatThrownBy(() -> reservationService.addReservation( - new ReservationRequest(beforeDate, reservationTime.getId(), theme.getId(), "paymentKey", "orderId", - 1000L, "paymentType"), member.getId())) - .isInstanceOf(RoomescapeException.class); - } - - @Test - @DisplayName("현재 날짜가 예약 당일이지만, 이미 지난 시간으로 예약을 생성하면 예외가 발생한다.") - void beforeTimeReservationFail() { - // given - LocalDateTime beforeTime = LocalDateTime.now().minusHours(1L).withNano(0); - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, beforeTime.toLocalTime())); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - - // when & then - assertThatThrownBy(() -> reservationService.addReservation( - new ReservationRequest(beforeTime.toLocalDate(), reservationTime.getId(), theme.getId(), "paymentKey", - "orderId", 1000L, "paymentType"), member.getId())) - .isInstanceOf(RoomescapeException.class); - } - - @Test - @DisplayName("존재하지 않는 회원이 예약을 생성하려고 하면 예외가 발생한다.") - void notExistMemberReservationFail() { - // given - LocalDateTime beforeTime = LocalDateTime.now().minusDays(1L).withNano(0); - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, beforeTime.toLocalTime())); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - Long NotExistMemberId = 1L; - - // when & then - assertThatThrownBy(() -> reservationService.addReservation( - new ReservationRequest(beforeTime.toLocalDate(), reservationTime.getId(), theme.getId(), "paymentKey", - "orderId", 1000L, "paymentType"), - NotExistMemberId)) - .isInstanceOf(RoomescapeException.class); - } - - @Test - @DisplayName("예약을 조회할 때 종료 날짜가 시작 날짜 이전이면 예외가 발생한다.") - void invalidDateRange() { - // given - LocalDate dateFrom = LocalDate.now().plusDays(1); - LocalDate dateTo = LocalDate.now(); - - // when & then - assertThatThrownBy(() -> reservationService.findFilteredReservations(null, null, dateFrom, dateTo)) - .isInstanceOf(RoomescapeException.class); - } - - @Test - @DisplayName("대기중인 예약을 승인할 때, 기존에 예약이 존재하면 예외가 발생한다.") - void confirmWaitingWhenReservationExist() { - // given - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(12, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity admin = memberRepository.save( - new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - MemberEntity member1 = memberRepository.save( - new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); - - reservationService.addReservation( - new ReservationRequest(LocalDate.now().plusDays(1L), reservationTime.getId(), theme.getId(), - "paymentKey", "orderId", - 1000L, "paymentType"), member.getId()); - ReservationResponse waiting = reservationService.addWaiting( - new WaitingRequest(LocalDate.now().plusDays(1L), reservationTime.getId(), theme.getId()), - member1.getId()); - - // when & then - assertThatThrownBy(() -> reservationService.approveWaiting(waiting.id, admin.getId())) - .isInstanceOf(RoomescapeException.class); - } - - @Test - @DisplayName("대기중인 예약을 확정한다.") - void approveWaiting() { - // given - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(12, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity admin = memberRepository.save( - new MemberEntity(null, "admin", "admin@email.com", "password", Role.ADMIN)); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - - // when - ReservationResponse waiting = reservationService.addWaiting( - new WaitingRequest(LocalDate.now().plusDays(1L), reservationTime.getId(), theme.getId()), - member.getId()); - reservationService.approveWaiting(waiting.id, admin.getId()); - - // then - ReservationEntity confirmed = reservationRepository.findById(waiting.id).get(); - assertThat(confirmed.getReservationStatus()).isEqualTo(ReservationStatus.CONFIRMED_PAYMENT_REQUIRED); - } -} diff --git a/src/test/java/roomescape/reservation/business/ReservationServiteTest.kt b/src/test/java/roomescape/reservation/business/ReservationServiteTest.kt new file mode 100644 index 00000000..c9b2fa6a --- /dev/null +++ b/src/test/java/roomescape/reservation/business/ReservationServiteTest.kt @@ -0,0 +1,175 @@ +package roomescape.reservation.business + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import roomescape.common.exception.ErrorType +import roomescape.common.exception.RoomescapeException +import roomescape.member.business.MemberService +import roomescape.member.infrastructure.persistence.Role +import roomescape.reservation.infrastructure.persistence.ReservationRepository +import roomescape.theme.business.ThemeService +import roomescape.util.MemberFixture +import roomescape.util.ReservationFixture +import roomescape.util.ReservationTimeFixture +import java.time.LocalDate +import java.time.LocalTime + +class ReservationServiteTest : FunSpec({ + + val reservationRepository: ReservationRepository = mockk() + val reservationTimeService: ReservationTimeService = mockk() + val memberService: MemberService = mockk() + val themeService: ThemeService = mockk() + val reservationService = ReservationService( + reservationRepository, + reservationTimeService, + memberService, + themeService + ) + + context("예약을 추가할 때") { + test("이미 예약이 있으면 예외를 던진다.") { + every { + reservationRepository.exists(any()) + } returns true + + val reservationRequest = ReservationFixture.createRequest() + + shouldThrow { + reservationService.addReservation(reservationRequest, 1L) + }.also { + it.errorType shouldBe ErrorType.RESERVATION_DUPLICATED + } + } + + context("날짜, 시간이 잘못 입력되면 예외를 던진다.") { + every { + reservationRepository.exists(any()) + } returns false + + every { + themeService.findThemeById(any()) + } returns mockk() + + every { + memberService.findById(any()) + } returns mockk() + + + test("지난 날짜이면 예외를 던진다.") { + val reservationRequest = ReservationFixture.createRequest().copy( + date = LocalDate.now().minusDays(1) + ) + + every { + reservationTimeService.findTimeById(any()) + } returns ReservationTimeFixture.create() + + shouldThrow { + reservationService.addReservation(reservationRequest, 1L) + }.also { + it.errorType shouldBe ErrorType.RESERVATION_PERIOD_IN_PAST + } + } + + test("지난 시간이면 예외를 던진다.") { + val reservationRequest = ReservationFixture.createRequest().copy( + date = LocalDate.now(), + ) + + every { + reservationTimeService.findTimeById(reservationRequest.timeId) + } returns ReservationTimeFixture.create( + startAt = LocalTime.now().minusMinutes(1) + ) + + shouldThrow { + reservationService.addReservation(reservationRequest, 1L) + }.also { + it.errorType shouldBe ErrorType.RESERVATION_PERIOD_IN_PAST + } + } + } + } + + context("예약 대기를 걸 때") { + test("이미 예약한 회원이 같은 날짜와 테마로 대기를 걸면 예외를 던진다.") { + val reservationRequest = ReservationFixture.createRequest().copy( + date = LocalDate.now(), + themeId = 1L, + timeId = 1L, + ) + + every { + reservationRepository.exists(any()) + } returns true + + shouldThrow { + val waitingRequest = ReservationFixture.createWaitingRequest( + date = reservationRequest.date, + themeId = reservationRequest.themeId, + timeId = reservationRequest.timeId + ) + reservationService.addWaiting(waitingRequest, 1L) + }.also { + it.errorType shouldBe ErrorType.HAS_RESERVATION_OR_WAITING + } + } + } + + context("예약을 조회할 때") { + test("종료 날짜가 시작 날짜보다 이전이면 예외를 던진다.") { + val startFrom = LocalDate.now() + val endAt = startFrom.minusDays(1) + + shouldThrow { + reservationService.findFilteredReservations( + null, + null, + startFrom, + endAt + ) + }.also { + it.errorType shouldBe ErrorType.INVALID_DATE_RANGE + } + } + } + + context("대기중인 예약을 승인할 때") { + test("관리자가 아니면 예외를 던진다.") { + val member = MemberFixture.create(id = 1L, role = Role.MEMBER) + + every { + memberService.findById(any()) + } returns member + + shouldThrow { + reservationService.approveWaiting(1L, member.id!!) + }.also { + it.errorType shouldBe ErrorType.PERMISSION_DOES_NOT_EXIST + } + } + + test("이미 확정된 예약이 있으면 예외를 던진다.") { + val member = MemberFixture.create(id = 1L, role = Role.ADMIN) + val reservationId = 1L + + every { + memberService.findById(any()) + } returns member + + every { + reservationRepository.isExistConfirmedReservation(reservationId) + } returns true + + shouldThrow { + reservationService.approveWaiting(reservationId, member.id!!) + }.also { + it.errorType shouldBe ErrorType.RESERVATION_DUPLICATED + } + } + } +}) diff --git a/src/test/java/roomescape/util/Fixtures.kt b/src/test/java/roomescape/util/Fixtures.kt index 7b6c3026..d1009093 100644 --- a/src/test/java/roomescape/util/Fixtures.kt +++ b/src/test/java/roomescape/util/Fixtures.kt @@ -11,6 +11,8 @@ import roomescape.payment.web.PaymentCancel import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationStatus import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity +import roomescape.reservation.web.ReservationRequest +import roomescape.reservation.web.WaitingRequest import roomescape.theme.infrastructure.persistence.ThemeEntity import java.time.LocalDate import java.time.LocalTime @@ -76,6 +78,34 @@ object ReservationFixture { member: MemberEntity = MemberFixture.create(), status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED ): ReservationEntity = ReservationEntity(id, date, reservationTime, theme, member, status) + + fun createRequest( + date: LocalDate = LocalDate.now().plusWeeks(1), + themeId: Long = 1L, + timeId: Long = 1L, + paymentKey: String = "paymentKey", + orderId: String = "orderId", + amount: Long = 10000L, + paymentType: String = "NORMAL", + ): ReservationRequest = ReservationRequest( + date = date, + timeId = timeId, + themeId = themeId, + paymentKey = paymentKey, + orderId = orderId, + amount = amount, + paymentType = paymentType + ) + + fun createWaitingRequest( + date: LocalDate = LocalDate.now().plusWeeks(1), + themeId: Long = 1L, + timeId: Long = 1L + ): WaitingRequest = WaitingRequest( + date = date, + timeId = timeId, + themeId = themeId + ) } object JwtFixture { -- 2.47.2 From 88a1a8e4c6d21f6ac9a8f191f3aa680b9b99609d Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 21 Jul 2025 10:32:00 +0900 Subject: [PATCH 33/40] Rename .java to .kt --- ...onWithPaymentService.java => ReservationWithPaymentService.kt} | 0 ...ymentServiceTest.java => ReservationWithPaymentServiceTest.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/roomescape/reservation/business/{ReservationWithPaymentService.java => ReservationWithPaymentService.kt} (100%) rename src/test/java/roomescape/reservation/business/{ReservationWithPaymentServiceTest.java => ReservationWithPaymentServiceTest.kt} (100%) diff --git a/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java b/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.kt similarity index 100% rename from src/main/java/roomescape/reservation/business/ReservationWithPaymentService.java rename to src/main/java/roomescape/reservation/business/ReservationWithPaymentService.kt diff --git a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt similarity index 100% rename from src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.java rename to src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt -- 2.47.2 From 5ddfd02572e2b6e2d1527bb2f7bdbc11f86d3c4c Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 21 Jul 2025 10:32:00 +0900 Subject: [PATCH 34/40] =?UTF-8?q?test:=20ReservationWithPaymentService=20?= =?UTF-8?q?=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=ED=8B=80?= =?UTF-8?q?=EB=A6=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/roomescape/payment/web/PaymentDTO.kt | 3 +- .../business/ReservationWithPaymentService.kt | 90 ++++--- .../reservation/web/ReservationResponse.kt | 7 +- .../persistence/PaymentRepositoryTest.kt | 27 +- .../ReservationWithPaymentServiceTest.kt | 252 +++++++----------- .../persistence/ReservationRepositoryTest.kt | 2 +- src/test/java/roomescape/util/Fixtures.kt | 4 +- 7 files changed, 170 insertions(+), 215 deletions(-) diff --git a/src/main/java/roomescape/payment/web/PaymentDTO.kt b/src/main/java/roomescape/payment/web/PaymentDTO.kt index a6261cce..b346c20c 100644 --- a/src/main/java/roomescape/payment/web/PaymentDTO.kt +++ b/src/main/java/roomescape/payment/web/PaymentDTO.kt @@ -5,6 +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 java.time.OffsetDateTime class PaymentApprove { @@ -60,6 +61,6 @@ fun PaymentEntity.toReservationPaymentResponse(): ReservationPaymentResponse = R orderId = this.orderId, paymentKey = this.paymentKey, totalAmount = this.totalAmount, - reservation = ReservationResponse.from(this.reservation), + reservation = this.reservation.toResponse(), approvedAt = this.approvedAt ) \ No newline at end of file diff --git a/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.kt b/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.kt index 13a78758..a3b0c47b 100644 --- a/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.kt +++ b/src/main/java/roomescape/reservation/business/ReservationWithPaymentService.kt @@ -1,56 +1,58 @@ -package roomescape.reservation.business; +package roomescape.reservation.business -import java.time.OffsetDateTime; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import roomescape.payment.business.PaymentService; -import roomescape.payment.web.PaymentApprove; -import roomescape.payment.web.PaymentCancel; -import roomescape.payment.web.ReservationPaymentResponse; -import roomescape.reservation.infrastructure.persistence.ReservationEntity; -import roomescape.reservation.web.ReservationRequest; -import roomescape.reservation.web.ReservationResponse; +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import roomescape.payment.business.PaymentService +import roomescape.payment.web.PaymentApprove +import roomescape.payment.web.PaymentCancel +import roomescape.reservation.infrastructure.persistence.ReservationEntity +import roomescape.reservation.web.ReservationRequest +import roomescape.reservation.web.ReservationResponse +import java.time.OffsetDateTime @Service @Transactional -public class ReservationWithPaymentService { +class ReservationWithPaymentService( + private val reservationService: ReservationService, + private val paymentService: PaymentService +) { + fun addReservationWithPayment( + request: ReservationRequest, + paymentInfo: PaymentApprove.Response, + memberId: Long + ): ReservationResponse { + val reservation: ReservationEntity = reservationService.addReservation(request, memberId) - private final ReservationService reservationService; - private final PaymentService paymentService; + return paymentService.savePayment(paymentInfo, reservation) + .reservation + } - public ReservationWithPaymentService(ReservationService reservationService, - PaymentService paymentService) { - this.reservationService = reservationService; - this.paymentService = paymentService; - } + fun saveCanceledPayment( + cancelInfo: PaymentCancel.Response, + approvedAt: OffsetDateTime, + paymentKey: String + ) { + paymentService.saveCanceledPayment(cancelInfo, approvedAt, paymentKey) + } - public ReservationResponse addReservationWithPayment(ReservationRequest request, - PaymentApprove.Response paymentInfo, - Long memberId) { - ReservationEntity reservation = reservationService.addReservation(request, memberId); - ReservationPaymentResponse reservationPaymentResponse = paymentService.savePayment(paymentInfo, reservation); + fun removeReservationWithPayment( + reservationId: Long, + memberId: Long + ): PaymentCancel.Request { + val paymentCancelRequest = paymentService.cancelPaymentByAdmin(reservationId) + reservationService.removeReservationById(reservationId, memberId) - return reservationPaymentResponse.reservation(); - } + return paymentCancelRequest + } - public void saveCanceledPayment(PaymentCancel.Response cancelInfo, OffsetDateTime approvedAt, String paymentKey) { - paymentService.saveCanceledPayment(cancelInfo, approvedAt, paymentKey); - } + @Transactional(readOnly = true) + fun isNotPaidReservation(reservationId: Long): Boolean = !paymentService.isReservationPaid(reservationId) - public PaymentCancel.Request removeReservationWithPayment(Long reservationId, Long memberId) { - PaymentCancel.Request paymentCancelRequest = paymentService.cancelPaymentByAdmin(reservationId); - reservationService.removeReservationById(reservationId, memberId); - return paymentCancelRequest; - } - @Transactional(readOnly = true) - public boolean isNotPaidReservation(Long reservationId) { - return !paymentService.isReservationPaid(reservationId); - } - - public void updateCanceledTime(String paymentKey, OffsetDateTime canceledAt) { - paymentService.updateCanceledTime(paymentKey, canceledAt); - } + fun updateCanceledTime( + paymentKey: String, + canceledAt: OffsetDateTime + ) { + paymentService.updateCanceledTime(paymentKey, canceledAt) + } } diff --git a/src/main/java/roomescape/reservation/web/ReservationResponse.kt b/src/main/java/roomescape/reservation/web/ReservationResponse.kt index 35e6eb36..158f54f6 100644 --- a/src/main/java/roomescape/reservation/web/ReservationResponse.kt +++ b/src/main/java/roomescape/reservation/web/ReservationResponse.kt @@ -3,7 +3,6 @@ package roomescape.reservation.web import com.fasterxml.jackson.annotation.JsonProperty import io.swagger.v3.oas.annotations.media.Schema import roomescape.member.web.MemberResponse -import roomescape.member.web.MemberResponse.Companion.fromEntity import roomescape.member.web.toResponse import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationStatus @@ -78,9 +77,9 @@ data class ReservationResponse( return ReservationResponse( reservation.id!!, reservation.date, - fromEntity(reservation.member), - ReservationTimeResponse.Companion.from(reservation.reservationTime), - ThemeResponse.Companion.from(reservation.theme), + reservation.member.toResponse(), + reservation.reservationTime.toResponse(), + reservation.theme.toResponse(), reservation.reservationStatus ) } diff --git a/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt b/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt index f398564d..4b202077 100644 --- a/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt +++ b/src/test/java/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt @@ -6,6 +6,7 @@ import io.kotest.matchers.shouldBe import jakarta.persistence.EntityManager import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.util.PaymentFixture import roomescape.util.ReservationFixture @@ -15,23 +16,23 @@ class PaymentRepositoryTest( @Autowired val entityManager: EntityManager ) : FunSpec() { - var reservationId: Long = 0L + lateinit var reservation: ReservationEntity init { context("existsByReservationId") { beforeTest { - reservationId = setupReservation() - PaymentFixture.create(reservationId = reservationId) + reservation = setupReservation() + PaymentFixture.create(reservation = reservation) .also { paymentRepository.save(it) } } test("true") { - paymentRepository.existsByReservationId(reservationId) + paymentRepository.existsByReservationId(reservation.id!!) .also { it shouldBe true } } test("false") { - paymentRepository.existsByReservationId(reservationId + 1) + paymentRepository.existsByReservationId(reservation.id!! + 1L) .also { it shouldBe false } } } @@ -40,20 +41,20 @@ class PaymentRepositoryTest( lateinit var paymentKey: String beforeTest { - reservationId = setupReservation() - paymentKey = PaymentFixture.create(reservationId = reservationId) + reservation = setupReservation() + paymentKey = PaymentFixture.create(reservation = reservation) .also { paymentRepository.save(it) } .paymentKey } test("정상 반환") { - paymentRepository.findPaymentKeyByReservationId(reservationId) + paymentRepository.findPaymentKeyByReservationId(reservation.id!!) ?.let { it shouldBe paymentKey } ?: throw AssertionError("Unexpected null value") } test("null 반환") { - paymentRepository.findPaymentKeyByReservationId(reservationId + 1) + paymentRepository.findPaymentKeyByReservationId(reservation.id!! + 1) .also { it shouldBe null } } } @@ -62,8 +63,8 @@ class PaymentRepositoryTest( lateinit var payment: PaymentEntity beforeTest { - reservationId = setupReservation() - payment = PaymentFixture.create(reservationId = reservationId) + reservation = setupReservation() + payment = PaymentFixture.create(reservation = reservation) .also { paymentRepository.save(it) } } @@ -89,7 +90,7 @@ class PaymentRepositoryTest( } } - private fun setupReservation(): Long { + private fun setupReservation(): ReservationEntity { return ReservationFixture.create().also { entityManager.persist(it.member) entityManager.persist(it.theme) @@ -98,6 +99,6 @@ class PaymentRepositoryTest( entityManager.flush() entityManager.clear() - }.id!! + } } } diff --git a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt index 06942c89..d4e1e804 100644 --- a/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt +++ b/src/test/java/roomescape/reservation/business/ReservationWithPaymentServiceTest.kt @@ -1,170 +1,122 @@ -package roomescape.reservation.business; +package roomescape.reservation.business -import static org.assertj.core.api.Assertions.*; +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.mockk.Runs +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import roomescape.payment.business.PaymentService +import roomescape.payment.infrastructure.persistence.PaymentEntity +import roomescape.payment.web.PaymentCancel +import roomescape.payment.web.toReservationPaymentResponse +import roomescape.reservation.infrastructure.persistence.ReservationEntity +import roomescape.reservation.infrastructure.persistence.ReservationStatus +import roomescape.reservation.web.ReservationRequest +import roomescape.reservation.web.ReservationResponse +import roomescape.util.* -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.OffsetDateTime; +class ReservationWithPaymentServiceTest : FunSpec({ + val reservationService: ReservationService = mockk() + val paymentService: PaymentService = mockk() -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.Sql.ExecutionPhase; + val reservationWithPaymentService = ReservationWithPaymentService( + reservationService = reservationService, + paymentService = paymentService + ) -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.member.infrastructure.persistence.MemberRepository; -import roomescape.member.infrastructure.persistence.Role; -import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository; -import roomescape.payment.infrastructure.persistence.PaymentEntity; -import roomescape.payment.infrastructure.persistence.PaymentRepository; -import roomescape.payment.web.PaymentApprove; -import roomescape.payment.web.PaymentCancel; -import roomescape.reservation.infrastructure.persistence.ReservationEntity; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.reservation.web.ReservationRequest; -import roomescape.reservation.web.ReservationResponse; -import roomescape.theme.infrastructure.persistence.ThemeEntity; -import roomescape.theme.infrastructure.persistence.ThemeRepository; + val reservationRequest: ReservationRequest = ReservationFixture.createRequest() + val paymentApproveResponse = PaymentFixture.createApproveResponse() + val memberId = 1L + val reservationEntity: ReservationEntity = ReservationFixture.create( + id = 1L, + date = reservationRequest.date, + reservationTime = ReservationTimeFixture.create(id = reservationRequest.timeId), + theme = ThemeFixture.create(id = reservationRequest.themeId), + member = MemberFixture.create(id = memberId), + status = ReservationStatus.CONFIRMED + ) + val paymentEntity: PaymentEntity = PaymentFixture.create( + id = 1L, + orderId = reservationRequest.orderId, + paymentKey = reservationRequest.paymentKey, + totalAmount = reservationRequest.amount, + reservation = reservationEntity, + ) -@SpringBootTest -@Sql(scripts = "/truncate.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD) -class ReservationWithPaymentServiceTest { + context("addReservationWithPayment") { + test("예약 및 결제 정보를 저장한다.") { + every { + reservationService.addReservation(reservationRequest, memberId) + } returns reservationEntity - @Autowired - private ReservationWithPaymentService reservationWithPaymentService; - @Autowired - private ReservationRepository reservationRepository; - @Autowired - private MemberRepository memberRepository; - @Autowired - private ReservationTimeRepository reservationTimeRepository; - @Autowired - private ThemeRepository themeRepository; - @Autowired - private PaymentRepository paymentRepository; - @Autowired - private CanceledPaymentRepository canceledPaymentRepository; + every { + paymentService.savePayment(paymentApproveResponse, reservationEntity) + } returns paymentEntity.toReservationPaymentResponse() - @Test - @DisplayName("예약과 결제 정보를 추가한다.") - void addReservationWithPayment() { - // given - PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", - OffsetDateTime.now(), 10000L); - LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - ReservationRequest reservationRequest = new ReservationRequest(date, time.getId(), theme.getId(), "payment-key", - "order-id", 10000L, "NORMAL"); + val result: ReservationResponse = reservationWithPaymentService.addReservationWithPayment( + request = reservationRequest, + paymentInfo = paymentApproveResponse, + memberId = memberId + ) - // when - ReservationResponse reservationResponse = reservationWithPaymentService.addReservationWithPayment( - reservationRequest, paymentInfo, member.getId()); + assertSoftly(result) { + 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.theme.id shouldBe reservationEntity.theme.id + this.status shouldBe ReservationStatus.CONFIRMED + } + } - // then - reservationRepository.findById(reservationResponse.id) - .ifPresent(reservation -> { - assertThat(reservation.getMember().getId()).isEqualTo(member.getId()); - assertThat(reservation.getTheme().getId()).isEqualTo(theme.getId()); - assertThat(reservation.getDate()).isEqualTo(date); - assertThat(reservation.getReservationTime().getId()).isEqualTo(time.getId()); - assertThat(reservation.getReservationStatus()).isEqualTo(ReservationStatus.CONFIRMED); - }); - PaymentEntity payment = paymentRepository.findByPaymentKey("payment-key"); - assertThat(payment).isNotNull(); - assertThat(payment.getReservation().getId()).isEqualTo(reservationResponse.id); - assertThat(payment.getPaymentKey()).isEqualTo("payment-key"); - assertThat(payment.getOrderId()).isEqualTo("order-id"); - assertThat(payment.getTotalAmount()).isEqualTo(10000L); - } + context("removeReservationWithPayment") { + test("예약 및 결제 정보를 삭제하고, 결제 취소 정보를 저장한다.") { + val paymentCancelRequest: PaymentCancel.Request = PaymentFixture.createCancelRequest().copy( + paymentKey = paymentEntity.paymentKey, + amount = paymentEntity.totalAmount, + cancelReason = "고객 요청" + ) - @Test - @DisplayName("예약 ID를 이용하여 예약과 결제 정보를 제거하고, 결제 취소 정보를 저장한다.") - void removeReservationWithPayment() { - // given - PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", - OffsetDateTime.now(), 10000L); - LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - ReservationRequest reservationRequest = new ReservationRequest(date, time.getId(), theme.getId(), "payment-key", - "order-id", 10000L, "NORMAL"); + every { + paymentService.cancelPaymentByAdmin(reservationEntity.id!!) + } returns paymentCancelRequest - ReservationResponse reservationResponse = reservationWithPaymentService.addReservationWithPayment( - reservationRequest, paymentInfo, member.getId()); + every { + reservationService.removeReservationById(reservationEntity.id!!, reservationEntity.member.id!!) + } just Runs - // when - PaymentCancel.Request paymentCancelRequest = reservationWithPaymentService.removeReservationWithPayment( - reservationResponse.id, member.getId()); + val result: PaymentCancel.Request = reservationWithPaymentService.removeReservationWithPayment( + reservationId = reservationEntity.id!!, + memberId = reservationEntity.member.id!! + ) - // then - assertThat(paymentCancelRequest.cancelReason).isEqualTo("고객 요청"); - assertThat(reservationRepository.findById(reservationResponse.id)).isEmpty(); - assertThat(paymentRepository.findByPaymentKey("payment-key")).isNull(); - assertThat(canceledPaymentRepository.findByPaymentKey("payment-key")).isNotNull(); - } + result shouldBe paymentCancelRequest + } + } - @Test - @DisplayName("결제 정보가 없으면 True를 반환한다.") - void isNotPaidReservation() { - // given - PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", - OffsetDateTime.now(), 10000L); - LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); + context("isNotPaidReservation") { + test("결제된 예약이면 true를 반환한다.") { + every { + paymentService.isReservationPaid(reservationEntity.id!!) + } returns false - ReservationEntity saved = reservationRepository.save( - new ReservationEntity(null, date, time, theme, member, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); + val result: Boolean = reservationWithPaymentService.isNotPaidReservation(reservationEntity.id!!) - // when - boolean result = reservationWithPaymentService.isNotPaidReservation(saved.getId()); + result shouldBe true + } - // then - assertThat(result).isTrue(); - } + test("결제되지 않은 예약이면 false를 반환한다.") { + every { + paymentService.isReservationPaid(reservationEntity.id!!) + } returns true - @Test - @DisplayName("결제 정보가 있으면 False를 반환한다.") - void isPaidReservation() { - // given - PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", - OffsetDateTime.now(), 10000L); - LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "member", "admin@email.com", "password", Role.ADMIN)); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - ReservationRequest reservationRequest = new ReservationRequest(date, time.getId(), theme.getId(), "payment-key", - "order-id", 10000L, "NORMAL"); + val result: Boolean = reservationWithPaymentService.isNotPaidReservation(reservationEntity.id!!) - ReservationResponse reservationResponse = reservationWithPaymentService.addReservationWithPayment( - reservationRequest, paymentInfo, member.getId()); - - // when - boolean result = reservationWithPaymentService.isNotPaidReservation(reservationResponse.id); - - // then - assertThat(result).isFalse(); - } -} + result shouldBe false + } + } + } +}) diff --git a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt index bfc85aba..40a40923 100644 --- a/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt +++ b/src/test/java/roomescape/reservation/infrastructure/persistence/ReservationRepositoryTest.kt @@ -161,7 +161,7 @@ class ReservationRepositoryTest( test("결제 정보를 포함한 회원의 예약 목록을 반환한다.") { val payment: PaymentEntity = PaymentFixture.create( - reservationId = reservation.id!! + reservation = reservation ).also { entityManager.persist(it) entityManager.flush() diff --git a/src/test/java/roomescape/util/Fixtures.kt b/src/test/java/roomescape/util/Fixtures.kt index d1009093..99bb0ec4 100644 --- a/src/test/java/roomescape/util/Fixtures.kt +++ b/src/test/java/roomescape/util/Fixtures.kt @@ -128,14 +128,14 @@ object PaymentFixture { orderId: String = ORDER_ID, paymentKey: String = PAYMENT_KEY, totalAmount: Long = AMOUNT, - reservationId: Long = Random.nextLong(), + reservation: ReservationEntity = ReservationFixture.create(id = 1L), approvedAt: OffsetDateTime = OffsetDateTime.now() ): PaymentEntity = PaymentEntity( id = id, orderId = orderId, paymentKey = paymentKey, totalAmount = totalAmount, - reservation = ReservationFixture.create(id = reservationId), + reservation = reservation, approvedAt = approvedAt ) -- 2.47.2 From 9008e612e3136ad685463d9f63701e6151759155 Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 21 Jul 2025 20:57:37 +0900 Subject: [PATCH 35/40] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=97=90=EC=84=9C=EC=9D=98=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=ED=99=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=B0=8F=20SQL=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../theme/web/MostReservedThemeAPITest.kt | 8 +- .../java/roomescape/util/DatabaseCleaner.kt | 64 ++++++ src/test/resources/reservationData.sql | 194 ------------------ src/test/resources/test_search_data.sql | 41 ---- src/test/resources/truncate.sql | 25 --- 5 files changed, 69 insertions(+), 263 deletions(-) create mode 100644 src/test/java/roomescape/util/DatabaseCleaner.kt delete mode 100644 src/test/resources/reservationData.sql delete mode 100644 src/test/resources/test_search_data.sql delete mode 100644 src/test/resources/truncate.sql diff --git a/src/test/java/roomescape/theme/web/MostReservedThemeAPITest.kt b/src/test/java/roomescape/theme/web/MostReservedThemeAPITest.kt index 8931f6a2..73b62fdf 100644 --- a/src/test/java/roomescape/theme/web/MostReservedThemeAPITest.kt +++ b/src/test/java/roomescape/theme/web/MostReservedThemeAPITest.kt @@ -8,10 +8,11 @@ import jakarta.persistence.EntityManager import org.hamcrest.Matchers.equalTo import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.server.LocalServerPort -import org.springframework.test.context.jdbc.Sql import org.springframework.transaction.support.TransactionTemplate import roomescape.theme.business.ThemeService import roomescape.theme.util.TestThemeCreateUtil +import roomescape.util.CleanerMode +import roomescape.util.DatabaseCleanerExtension import java.time.LocalDate import kotlin.random.Random @@ -21,13 +22,14 @@ import kotlin.random.Random * 날짜 범위, 예약 수만 검증 */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@Sql(value = ["/truncate.sql"], executionPhase = Sql.ExecutionPhase.AFTER_TEST_CLASS) class MostReservedThemeAPITest( @LocalServerPort val port: Int, val themeService: ThemeService, val transactionTemplate: TransactionTemplate, val entityManager: EntityManager, -) : FunSpec() { +) : FunSpec({ + extension(DatabaseCleanerExtension(mode = CleanerMode.AFTER_SPEC)) +}) { init { beforeSpec { transactionTemplate.executeWithoutResult { diff --git a/src/test/java/roomescape/util/DatabaseCleaner.kt b/src/test/java/roomescape/util/DatabaseCleaner.kt new file mode 100644 index 00000000..17e83bf6 --- /dev/null +++ b/src/test/java/roomescape/util/DatabaseCleaner.kt @@ -0,0 +1,64 @@ +package roomescape.util + +import io.kotest.core.listeners.AfterSpecListener +import io.kotest.core.listeners.AfterTestListener +import io.kotest.core.spec.Spec +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult +import io.kotest.extensions.spring.testContextManager +import jakarta.persistence.EntityManager +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.stereotype.Component + +@Component +class DatabaseCleaner( + val entityManager: EntityManager, + val jdbcTemplate: JdbcTemplate, +) { + val tables: List by lazy { + jdbcTemplate.query("SHOW TABLES") { rs, _ -> + rs.getString(1).lowercase() + } + } + + fun clear() { + entityManager.clear() + + jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY FALSE") + tables.forEach { + jdbcTemplate.execute("TRUNCATE TABLE $it RESTART IDENTITY") + } + jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY TRUE") + } +} + +enum class CleanerMode { + AFTER_EACH_TEST, + AFTER_SPEC +} + +class DatabaseCleanerExtension( + private val mode: CleanerMode +) : AfterTestListener, AfterSpecListener { + override suspend fun afterTest(testCase: TestCase, result: TestResult) { + super.afterTest(testCase, result) + when (mode) { + CleanerMode.AFTER_EACH_TEST -> getCleaner().clear() + CleanerMode.AFTER_SPEC -> Unit + } + } + + override suspend fun afterSpec(spec: Spec) { + super.afterSpec(spec) + when (mode) { + CleanerMode.AFTER_EACH_TEST -> Unit + CleanerMode.AFTER_SPEC -> getCleaner().clear() + } + } + + private suspend fun getCleaner(): DatabaseCleaner { + return testContextManager().testContext + .applicationContext + .getBean(DatabaseCleaner::class.java) + } +} diff --git a/src/test/resources/reservationData.sql b/src/test/resources/reservationData.sql deleted file mode 100644 index b5a4c521..00000000 --- a/src/test/resources/reservationData.sql +++ /dev/null @@ -1,194 +0,0 @@ -INSERT INTO member (name, password, email, role) -VALUES ('이름', '12341234', 'test@test.com', 'MEMBER'); -INSERT INTO member (name, password, email, role) -VALUES ('관리자', '12341234', 'admin@admin.com', 'ADMIN'); - - --- 테마 목록 : 11개 -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마1', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마2', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마3', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마4', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마5', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마6', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마7', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마8', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마9', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마10', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); -INSERT INTO theme (name, description, thumbnail) -VALUES ('테마11', '재밌는 테마입니다', - 'https://www.google.co.kr/url?sa=i&url=http%3A%2F%2Fwww.code-k.co.kr%2Fsub%2Fcode_sub03.html%3FR_JIJEM%3DS1&psig=AOvVaw20fNjL28MSMMiR0Nb57Eh-&ust=1714695060162000&source=images&cd=vfe&opi=89978449&ved=0CBIQjRxqFwoTCOiO2oLX7YUDFQAAAAAdAAAAABAE'); - --- 예약 시간 목록 : 5개 -INSERT INTO reservation_time (start_at) -VALUES ('08:00'); -INSERT INTO reservation_time (start_at) -VALUES ('10:00'); -INSERT INTO reservation_time (start_at) -VALUES ('13:00'); -INSERT INTO reservation_time (start_at) -VALUES ('21:00'); -INSERT INTO reservation_time (start_at) -VALUES ('23:00'); - --- 5,4,2,5,2,3,1,1,1,1,1 --- 내림차순 정렬 ID : 4/1, 2, 6, 3/5, 7/8/9/10/11 - --- 테마 1 예약 목록 : 5개 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 1, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 2, 1, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 3, 1, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 4, 1, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 5, 1, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-1', 'paymentKey-1', 10000, 1, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-2', 'paymentKey-2', 20000, 2, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-3', 'paymentKey-3', 30000, 3, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-4', 'paymentKey-4', 40000, 4, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-5', 'paymentKey-5', 50000, 5, CURRENT_DATE); - --- 테마 2 예약 목록 : 4개 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 2, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 2, 2, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 3, 2, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 4, 2, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-6', 'paymentKey-6', 50000, 6, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-7', 'paymentKey-7', 50000, 7, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-8', 'paymentKey-8', 50000, 8, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-9', 'paymentKey-9', 50000, 9, CURRENT_DATE); - - --- 테마 3 예약 목록 : 2개 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 3, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 2, 3, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-10', 'paymentKey-10', 50000, 10, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-11', 'paymentKey-11', 50000, 11, CURRENT_DATE); - --- 테마 4 예약 목록 : 5개 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 4, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 2, 4, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 3, 4, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 4, 4, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 5, 4, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-12', 'paymentKey-12', 50000, 12, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-13', 'paymentKey-13', 50000, 13, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-14', 'paymentKey-14', 50000, 14, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-15', 'paymentKey-15', 50000, 15, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-16', 'paymentKey-16', 50000, 16, CURRENT_DATE); - --- 테마 5 예약 목록 : 2개 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 5, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 5, 5, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-17', 'paymentKey-17', 50000, 17, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-18', 'paymentKey-18', 50000, 18, CURRENT_DATE); - --- 테마 6 예약 목록 : 3개 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 6, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 2, 6, 1, 'CONFIRMED'); -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 3, 6, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-19', 'paymentKey-19', 50000, 19, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-20', 'paymentKey-20', 50000, 20, CURRENT_DATE); -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-21', 'paymentKey-21', 50000, 21, CURRENT_DATE); - --- 테마 7 예약 목록 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 7, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-22', 'paymentKey-22', 50000, 22, CURRENT_DATE); - --- 테마 8 예약 목록 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 8, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-23', 'paymentKey-23', 50000, 23, CURRENT_DATE); - - --- 테마 9 예약 목록 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 9, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-24', 'paymentKey-24', 50000, 24, CURRENT_DATE); - --- 테마 10 예약 목록 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 1, 10, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-25', 'paymentKey-25', 50000, 25, CURRENT_DATE); - --- 테마 11 예약 목록 -INSERT INTO reservation (date, time_id, theme_id, member_id, reservation_status) -VALUES (DATEADD('DAY', -3, CURRENT_DATE), 5, 11, 1, 'CONFIRMED'); - -insert into payment(order_id, payment_key, total_amount, reservation_id, approved_at) -values ('orderId-26', 'paymentKey-26', 50000, 26, CURRENT_DATE); diff --git a/src/test/resources/test_search_data.sql b/src/test/resources/test_search_data.sql deleted file mode 100644 index c288d560..00000000 --- a/src/test/resources/test_search_data.sql +++ /dev/null @@ -1,41 +0,0 @@ --- 관리자가 특정 조건에 해당되는 예약을 조회하는 테스트에서만 사용되는 데이터입니다. -insert into reservation_time(start_at) -values ('15:00'); - -insert into theme(name, description, thumbnail) -values ('테스트1', '테스트중', 'https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg'); -insert into theme(name, description, thumbnail) -values ('테스트2', '테스트중', 'https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg'); - -insert into member(name, email, password, role) -values ('어드민', 'a@a.a', 'a', 'ADMIN'); -insert into member(name, email, password, role) -values ('1호', '1@1.1', '1', 'MEMBER'); - --- 예약 --- 시간은 같은 시간으로, 날짜는 어제부터 7일 전까지 --- memberId = 1인 멤버는 3개의 예약, memberId = 2인 멤버는 4개의 예약이 있음 --- themeId = 1인 테마는 4개의 예약, themeId = 2인 테마는 3개의 예약이 있음 -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', -1, CURRENT_DATE()), 1, 1, 1, 'CONFIRMED'); -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', -2, CURRENT_DATE()), 1, 1, 1, 'CONFIRMED'); -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', -3, CURRENT_DATE()), 1, 1, 1, 'CONFIRMED'); -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', -4, CURRENT_DATE()), 1, 1, 2, 'CONFIRMED'); -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', -5, CURRENT_DATE()), 1, 2, 2, 'CONFIRMED'); -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', -6, CURRENT_DATE()), 1, 2, 2, 'CONFIRMED'); -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', -7, CURRENT_DATE()), 1, 2, 2, 'CONFIRMED'); - --- 예약 대기 --- 예약 대기는 조회되면 안됨. -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', 7, CURRENT_DATE()), 1, 1, 1, 'WAITING'); -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', 8, CURRENT_DATE()), 1, 1, 1, 'WAITING'); -insert into reservation(date, time_id, theme_id, member_id, reservation_status) -values (DATEADD('DAY', 9, CURRENT_DATE()), 1, 1, 2, 'WAITING'); diff --git a/src/test/resources/truncate.sql b/src/test/resources/truncate.sql deleted file mode 100644 index cd541e0e..00000000 --- a/src/test/resources/truncate.sql +++ /dev/null @@ -1,25 +0,0 @@ -DELETE -FROM payment; -DELETE -FROM canceled_payment; -DELETE -FROM reservation; -DELETE -FROM reservation_time; -DELETE -FROM theme; -DELETE -FROM member; - -ALTER TABLE payment - ALTER COLUMN id RESTART WITH 1; -ALTER TABLE canceled_payment - ALTER COLUMN id RESTART WITH 1; -ALTER TABLE reservation - ALTER COLUMN id RESTART WITH 1; -ALTER TABLE reservation_time - ALTER COLUMN id RESTART WITH 1; -ALTER TABLE theme - ALTER COLUMN id RESTART WITH 1; -ALTER TABLE member - ALTER COLUMN id RESTART WITH 1; -- 2.47.2 From 8a999340c0c26adf3b6669558c93914459ed2491 Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 21 Jul 2025 20:58:18 +0900 Subject: [PATCH 36/40] Rename .java to .kt --- ...eservationControllerTest.java => ReservationControllerTest.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/java/roomescape/reservation/web/{ReservationControllerTest.java => ReservationControllerTest.kt} (100%) diff --git a/src/test/java/roomescape/reservation/web/ReservationControllerTest.java b/src/test/java/roomescape/reservation/web/ReservationControllerTest.kt similarity index 100% rename from src/test/java/roomescape/reservation/web/ReservationControllerTest.java rename to src/test/java/roomescape/reservation/web/ReservationControllerTest.kt -- 2.47.2 From 4b3afd12fffb40f827a9380e7fbe250b4e34868b Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 21 Jul 2025 20:58:18 +0900 Subject: [PATCH 37/40] =?UTF-8?q?test:=20ReservationControllerTest=20?= =?UTF-8?q?=EC=BD=94=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/ReservationControllerTest.kt | 1438 +++++++++-------- 1 file changed, 788 insertions(+), 650 deletions(-) diff --git a/src/test/java/roomescape/reservation/web/ReservationControllerTest.kt b/src/test/java/roomescape/reservation/web/ReservationControllerTest.kt index fb382f10..f4fbfffe 100644 --- a/src/test/java/roomescape/reservation/web/ReservationControllerTest.kt +++ b/src/test/java/roomescape/reservation/web/ReservationControllerTest.kt @@ -1,654 +1,792 @@ -package roomescape.reservation.web; +package roomescape.reservation.web -import static org.assertj.core.api.Assertions.*; -import static org.hamcrest.Matchers.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.Map; -import java.util.stream.Stream; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.MockitoAnnotations; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.http.HttpStatus; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.Sql.ExecutionPhase; - -import io.restassured.RestAssured; -import io.restassured.http.ContentType; -import io.restassured.http.Header; -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.member.infrastructure.persistence.MemberRepository; -import roomescape.member.infrastructure.persistence.Role; -import roomescape.payment.infrastructure.client.TossPaymentClient; -import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity; -import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository; -import roomescape.payment.infrastructure.persistence.PaymentEntity; -import roomescape.payment.infrastructure.persistence.PaymentRepository; -import roomescape.payment.web.PaymentApprove; -import roomescape.payment.web.PaymentCancel; -import roomescape.reservation.infrastructure.persistence.ReservationEntity; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.theme.infrastructure.persistence.ThemeEntity; -import roomescape.theme.infrastructure.persistence.ThemeRepository; +import com.ninjasquad.springmockk.MockkBean +import com.ninjasquad.springmockk.SpykBean +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.restassured.module.kotlin.extensions.Given +import io.restassured.module.kotlin.extensions.Then +import io.restassured.module.kotlin.extensions.When +import jakarta.persistence.EntityManager +import org.hamcrest.Matchers.containsString +import org.hamcrest.Matchers.equalTo +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.web.server.LocalServerPort +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.transaction.support.TransactionTemplate +import roomescape.auth.web.support.AdminInterceptor +import roomescape.auth.web.support.LoginInterceptor +import roomescape.auth.web.support.MemberIdResolver +import roomescape.common.exception.ErrorType +import roomescape.common.exception.RoomescapeException +import roomescape.member.infrastructure.persistence.MemberEntity +import roomescape.member.infrastructure.persistence.Role +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.theme.infrastructure.persistence.ThemeEntity +import roomescape.util.* +import java.time.LocalDate +import java.time.LocalTime @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@Sql(scripts = "/truncate.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD) -public class ReservationControllerTest { - - @Autowired - private ReservationRepository reservationRepository; - @Autowired - private ReservationTimeRepository reservationTimeRepository; - @Autowired - private ThemeRepository themeRepository; - @Autowired - private MemberRepository memberRepository; - @Autowired - private PaymentRepository paymentRepository; - @Autowired - private CanceledPaymentRepository canceledPaymentRepository; - - @MockBean - private TossPaymentClient paymentClient; - - @LocalServerPort - private int port; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - @DisplayName("처음으로 등록하는 예약의 id는 1이다.") - void firstPost() { - String accessTokenCookie = getAdminAccessTokenCookieByLogin("admin@admin.com", "12341234"); - - LocalTime time = LocalTime.of(17, 30); - LocalDate date = LocalDate.now().plusDays(1L); - - reservationTimeRepository.save(new ReservationTimeEntity(null, time)); - themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - - Map reservationParams = Map.of( - "date", date.toString(), - "timeId", "1", - "themeId", "1", - "paymentKey", "pk", - "orderId", "oi", - "amount", "1000", - "paymentType", "DEFAULT" - ); - - when(paymentClient.confirmPayment(any(PaymentApprove.Request.class))).thenReturn( - new PaymentApprove.Response("pk", "oi", OffsetDateTime.of(date, time, ZoneOffset.ofHours(9)), 1000L)); - - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .header("Cookie", accessTokenCookie) - .body(reservationParams) - .when().post("/reservations") - .then().log().all() - .statusCode(201) - .body("data.id", is(1)) - .header("Location", "/reservations/1"); - } - - @Test - @DisplayName("대기중인 예약을 취소한다.") - void cancelWaiting() { - // given - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - String accessTokenCookie = getAccessTokenCookieByLogin("email@email.com", "password"); - - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member1 = memberRepository.save( - new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); - - // when - reservationRepository.save( - new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, member1, - ReservationStatus.CONFIRMED)); - ReservationEntity waiting = reservationRepository.save( - new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, member, - ReservationStatus.WAITING)); - - // then - RestAssured.given().log().all() - .port(port) - .header("Cookie", accessTokenCookie) - .when().delete("/reservations/waiting/{id}", waiting.getId()) - .then().log().all() - .statusCode(204); - } - - @Test - @DisplayName("회원은 자신이 아닌 다른 회원의 예약을 취소할 수 없다.") - void cantCancelOtherMembersWaiting() { - // given - MemberEntity confirmedMember = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - String accessTokenCookie = getAccessTokenCookieByLogin("email@email.com", "password"); - - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity waitingMember = memberRepository.save( - new MemberEntity(null, "name1", "email1r@email.com", "password", Role.MEMBER)); - - // when - reservationRepository.save( - new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, confirmedMember, - ReservationStatus.CONFIRMED)); - ReservationEntity waiting = reservationRepository.save( - new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, waitingMember, - ReservationStatus.WAITING)); - - // then - RestAssured.given().log().all() - .port(port) - .header("Cookie", accessTokenCookie) - .when().delete("/reservations/waiting/{id}", waiting.getId()) - .then().log().all() - .statusCode(404); - } - - @Test - @DisplayName("관리자 권한이 있으면 전체 예약정보를 조회할 수 있다.") - void readEmptyReservations() { - // given - String accessTokenCookie = getAdminAccessTokenCookieByLogin("admin@admin.com", "12341234"); - - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - - // when - reservationRepository.save( - new ReservationEntity(null, LocalDate.now(), reservationTime, theme, member, ReservationStatus.CONFIRMED)); - reservationRepository.save( - new ReservationEntity(null, LocalDate.now().plusDays(1), reservationTime, theme, member, - ReservationStatus.CONFIRMED)); - reservationRepository.save( - new ReservationEntity(null, LocalDate.now().plusDays(2), reservationTime, theme, member, - ReservationStatus.CONFIRMED)); - - // then - RestAssured.given().log().all() - .port(port) - .header(new Header("Cookie", accessTokenCookie)) - .when().get("/reservations") - .then().log().all() - .statusCode(200) - .body("data.reservations.size()", is(3)); - } - - @Test - @DisplayName("예약 취소는 관리자만 할 수 있다.") - void canRemoveMyReservation() { - // given - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - String accessTokenCookie = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); - - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - ReservationEntity reservation = reservationRepository.save( - new ReservationEntity(null, LocalDate.now(), reservationTime, theme, member, ReservationStatus.CONFIRMED)); - - // when & then - RestAssured.given().log().all() - .port(port) - .header("Cookie", accessTokenCookie) - .when().delete("/reservations/" + reservation.getId()) - .then().log().all() - .statusCode(302); - } - - @Test - @DisplayName("관리자가 대기중인 예약을 거절한다.") - void denyWaiting() { - // given - String adminTokenCookie = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); - - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity confirmedMember = memberRepository.save( - new MemberEntity(null, "name1", "email@email.com", "password", Role.MEMBER)); - MemberEntity waitingMember = memberRepository.save( - new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); - - reservationRepository.save( - new ReservationEntity(null, LocalDate.now(), reservationTime, theme, confirmedMember, - ReservationStatus.CONFIRMED)); - ReservationEntity waiting = reservationRepository.save( - new ReservationEntity(null, LocalDate.now(), reservationTime, theme, waitingMember, - ReservationStatus.WAITING)); - - // when & then - RestAssured.given().log().all() - .port(port) - .header("Cookie", adminTokenCookie) - .when().post("/reservations/waiting/{id}/deny", waiting.getId()) - .then().log().all() - .statusCode(204); - } - - @Test - @DisplayName("본인의 예약이 아니더라도 관리자 권한이 있으면 예약 정보를 삭제할 수 있다.") - void readReservationsSizeAfterPostAndDelete() { - // given - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "admin@admin.com", "password", Role.ADMIN)); - String accessTokenCookie = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); - - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity anotherMember = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - - ReservationEntity reservation = reservationRepository.save( - new ReservationEntity(null, LocalDate.now(), reservationTime, theme, anotherMember, - ReservationStatus.CONFIRMED)); - - // when & then - RestAssured.given().log().all() - .port(port) - .header("Cookie", accessTokenCookie) - .when().delete("/reservations/" + reservation.getId()) - .then().log().all() - .statusCode(204); - } - - @ParameterizedTest - @MethodSource("requestValidateSource") - @DisplayName("예약 생성 시, 요청 값에 공백 또는 null이 포함되어 있으면 400 에러를 발생한다.") - void validateBlankRequest(Map invalidRequestBody) { - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .body(invalidRequestBody) - .header("Cookie", getAdminAccessTokenCookieByLogin("a@a.a", "a")) - .when().post("/reservations") - .then().log().all() - .statusCode(400); - } - - private static Stream> requestValidateSource() { - return Stream.of( - Map.of("timeId", "1", - "themeId", "1"), - - Map.of("date", LocalDate.now().plusDays(1L).toString(), - "themeId", "1"), - - Map.of("date", LocalDate.now().plusDays(1L).toString(), - "timeId", "1"), - - Map.of("date", " ", - "timeId", "1", - "themeId", "1"), - - Map.of("date", LocalDate.now().plusDays(1L).toString(), - "timeId", " ", - "themeId", "1"), - - Map.of("date", LocalDate.now().plusDays(1L).toString(), - "timeId", "1", - "themeId", " ") - ); - } - - @Test - @DisplayName("예약 생성 시, 정수 요청 데이터에 문자가 입력되어오면 400 에러를 발생한다.") - void validateRequestDataFormat() { - Map invalidTypeRequestBody = Map.of( - "date", LocalDate.now().plusDays(1L).toString(), - "timeId", "1", - "themeId", "한글" - ); - - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .header("Cookie", getAdminAccessTokenCookieByLogin("a@a.a", "a")) - .body(invalidTypeRequestBody) - .when().post("/reservations") - .then().log().all() - .statusCode(400); - } - - @ParameterizedTest - @DisplayName("모든 예약 / 대기 중인 예약 / 현재 로그인된 회원의 예약 및 대기를 조회한다.") - @CsvSource(value = {"/reservations, reservations, 2", "/reservations/waiting, reservations, 1", - "/reservations-mine, myReservationResponses, 3"}, delimiter = ',') - void getAllReservations(String requestURI, String responseFieldName, int expectedSize) { - // given - LocalDate date = LocalDate.now().plusDays(1); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - ReservationTimeEntity time1 = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(18, 30))); - ReservationTimeEntity time2 = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(19, 30))); - - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.ADMIN)); - String accessToken = getAccessTokenCookieByLogin("email@email.com", "password"); - - // when : 예약은 2개, 예약 대기는 1개 조회되어야 한다. - reservationRepository.save(new ReservationEntity(null, date, time, theme, member, ReservationStatus.CONFIRMED)); - reservationRepository.save( - new ReservationEntity(null, date, time1, theme, member, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); - reservationRepository.save(new ReservationEntity(null, date, time2, theme, member, ReservationStatus.WAITING)); - - // then - RestAssured.given().log().all() - .port(port) - .header("Cookie", accessToken) - .when().get(requestURI) - .then().log().all() - .statusCode(200) - .body("data." + responseFieldName + ".size()", is(expectedSize)); - } - - @Test - @DisplayName("예약을 삭제할 때, 승인되었으나 결제 대기중인 예약은 결제 취소 없이 바로 삭제한다.") - void removeNotPaidReservation() { - // given - LocalDate date = LocalDate.now().plusDays(1); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - String accessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); - - // when - ReservationEntity saved = reservationRepository.save(new ReservationEntity(null, date, time, theme, - memberRepository.save(new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)), - ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); - - // then - RestAssured.given().log().all() - .port(port) - .header("Cookie", accessToken) - .when().delete("/reservations/{id}", saved.getId()) - .then().log().all() - .statusCode(204); - } - - @Test - @DisplayName("이미 결제가 된 예약은 삭제 후 결제 취소를 요청한다.") - void removePaidReservation() { - // given - String accessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); - LocalDate date = LocalDate.now().plusDays(1); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(17, 30))); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - - ReservationEntity saved = reservationRepository.save( - new ReservationEntity(null, date, time, theme, member, ReservationStatus.CONFIRMED)); - PaymentEntity savedPaymentEntity = paymentRepository.save( - new PaymentEntity(null, "pk", "oi", 1000L, saved, OffsetDateTime.now().minusHours(1L))); - - // when - when(paymentClient.cancelPayment(any(PaymentCancel.Request.class))) - .thenReturn(new PaymentCancel.Response("pk", "고객 요청", savedPaymentEntity.getTotalAmount(), - OffsetDateTime.now())); - - // then - RestAssured.given().log().all() - .port(port) - .header("Cookie", accessToken) - .when().delete("/reservations/{id}", saved.getId()) - .then().log().all() - .statusCode(204); - - } - - @Test - @DisplayName("예약을 추가할 때, 결제 승인 이후에 예외가 발생하면 결제를 취소한 뒤 결제 취소 테이블에 취소 정보를 저장한다.") - void saveReservationWithCancelPayment() { - // given - LocalDateTime localDateTime = LocalDateTime.now().minusHours(1L).withNano(0); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - String accessToken = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); - - // when : 이전 날짜의 예약을 추가하여 결제 승인 이후 DB 저장 과정에서 예외를 발생시킨다. - String paymentKey = "pk"; - OffsetDateTime canceledAt = OffsetDateTime.now().plusHours(1L).withNano(0); - OffsetDateTime approvedAt = OffsetDateTime.of(localDateTime, ZoneOffset.ofHours(9)); - when(paymentClient.confirmPayment(any(PaymentApprove.Request.class))) - .thenReturn(new PaymentApprove.Response(paymentKey, "oi", approvedAt, 1000L)); - - when(paymentClient.cancelPayment(any(PaymentCancel.Request.class))) - .thenReturn(new PaymentCancel.Response(paymentKey, "고객 요청", 1000L, canceledAt)); - - RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .header("Cookie", accessToken) - .body(new ReservationRequest(date, time.getId(), theme.getId(), "pk", "oi", 1000L, "DEFAULT")) - .when().post("/reservations") - .then().log().all() - .statusCode(400); - - // then - CanceledPaymentEntity canceledPayment = canceledPaymentRepository.findByPaymentKey(paymentKey); - assertThat(canceledPayment).isNotNull(); - assertThat(canceledPayment.getCanceledAt()).isEqualTo(canceledAt); - assertThat(canceledPayment.getCancelReason()).isEqualTo("고객 요청"); - assertThat(canceledPayment.getCancelAmount()).isEqualTo(1000L); - assertThat(canceledPayment.getApprovedAt()).isEqualTo(approvedAt); - } - - @DisplayName("테마만을 이용하여 예약을 조회한다.") - @ParameterizedTest(name = "테마 ID={0}로 조회 시 {1}개의 예약이 조회된다.") - @CsvSource(value = {"1/4", "2/3"}, delimiter = '/') - @Sql({"/truncate.sql", "/test_search_data.sql"}) - void searchByTheme(String themeId, int expectedCount) { - RestAssured.given().log().all() - .port(port) - .param("themeId", themeId) - .param("memberId", "") - .param("dateFrom", "") - .param("dateTo", "") - .header("cookie", getAdminAccessTokenCookieByLogin("admin@email.com", "password")) - .when().get("/reservations/search") - .then().log().all() - .statusCode(HttpStatus.OK.value()) - .body("data.reservations.size()", is(expectedCount)); - } - - @DisplayName("시작 날짜만을 이용하여 예약을 조회한다.") - @ParameterizedTest(name = "오늘 날짜보다 {0}일 전인 날짜를 시작 날짜로 조회 시 {1}개의 예약이 조회된다.") - @CsvSource(value = {"1/1", "7/7"}, delimiter = '/') - @Sql({"/truncate.sql", "/test_search_data.sql"}) - void searchByFromDate(int minusDays, int expectedCount) { - RestAssured.given().log().all() - .port(port) - .param("themeId", "") - .param("memberId", "") - .param("dateFrom", LocalDate.now().minusDays(minusDays).toString()) - .param("dateTo", "") - .header("cookie", getAdminAccessTokenCookieByLogin("admin@email.com", "password")) - .when().get("/reservations/search") - .then().log().all() - .statusCode(HttpStatus.OK.value()) - .body("data.reservations.size()", is(expectedCount)); - } - - @DisplayName("종료 날짜만을 이용하여 예약을 조회한다..") - @ParameterizedTest(name = "오늘 날짜보다 {0}일 전인 날짜를 종료 날짜로 조회 시 {1}개의 예약이 조회된다.") - @CsvSource(value = {"1/7", "3/5", "7/1"}, delimiter = '/') - @Sql({"/truncate.sql", "/test_search_data.sql"}) - void searchByToDate(int minusDays, int expectedCount) { - RestAssured.given().log().all() - .port(port) - .param("themeId", "") - .param("memberId", "") - .param("dateFrom", "") - .param("dateTo", LocalDate.now().minusDays(minusDays).toString()) - .header("cookie", getAdminAccessTokenCookieByLogin("admin@email.com", "password")) - .when().get("/reservations/search") - .then().log().all() - .statusCode(HttpStatus.OK.value()) - .body("data.reservations.size()", is(expectedCount)); - } - - @Test - @DisplayName("예약 대기를 추가한다.") - void addWaiting() { - // given - LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - MemberEntity member1 = memberRepository.save( - new MemberEntity(null, "name1", "email1@email.com", "password", Role.MEMBER)); - - String accessToken = getAccessTokenCookieByLogin(member.getEmail(), member.getPassword()); - reservationRepository.save( - new ReservationEntity(null, date, time, theme, member1, ReservationStatus.CONFIRMED)); - - // when & then - RestAssured.given().log().all() - .port(port) - .contentType(ContentType.JSON) - .header("Cookie", accessToken) - .body(new WaitingRequest(date, time.getId(), theme.getId())) - .when().post("/reservations/waiting") - .then().log().all() - .statusCode(201) - .body("data.status", is("WAITING")); - } - - @Test - @DisplayName("대기중인 예약을 승인한다.") - void approveWaiting() { - // given - LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - - String accessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); - ReservationEntity waiting = reservationRepository.save( - new ReservationEntity(null, date, time, theme, member, ReservationStatus.WAITING)); - - // when - RestAssured.given().log().all() - .port(port) - .header("Cookie", accessToken) - .when().post("/reservations/waiting/{id}/approve", waiting.getId()) - .then().log().all() - .statusCode(200); - - // then - reservationRepository.findById(waiting.getId()) - .ifPresent(r -> assertThat(r.getReservationStatus()).isEqualTo( - ReservationStatus.CONFIRMED_PAYMENT_REQUIRED)); - - } - - private String getAccessTokenCookieByLogin(final String email, final String password) { - Map loginParams = Map.of( - "email", email, - "password", password - ); - - String accessToken = RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .body(loginParams) - .when().post("/login") - .then().log().all().extract().cookie("accessToken"); - - return "accessToken=" + accessToken; - } - - @Test - @DisplayName("관리자가 직접 예약을 추가한다.") - void addReservationByAdmin() { - // given - LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); - - String adminAccessToken = getAdminAccessTokenCookieByLogin("admin@email.com", "password"); - - // when & then - RestAssured.given().log().all() - .port(port) - .contentType(ContentType.JSON) - .header("Cookie", adminAccessToken) - .body(new AdminReservationRequest(date, time.getId(), theme.getId(), member.getId())) - .when().post("/reservations/admin") - .then().log().all() - .statusCode(201); - } - - private String getAdminAccessTokenCookieByLogin(final String email, final String password) { - memberRepository.save(new MemberEntity(null, "이름", email, password, Role.ADMIN)); - - Map loginParams = Map.of( - "email", email, - "password", password - ); - - String accessToken = RestAssured.given().log().all() - .contentType(ContentType.JSON) - .port(port) - .body(loginParams) - .when().post("/login") - .then().log().all().extract().cookie("accessToken"); - - return "accessToken=" + accessToken; - } +class ReservationControllerTest( + @LocalServerPort val port: Int, + val entityManager: EntityManager, + val transactionTemplate: TransactionTemplate +) : FunSpec({ + extension(DatabaseCleanerExtension(mode = CleanerMode.AFTER_EACH_TEST)) +}) { + @MockkBean + lateinit var paymentClient: TossPaymentClient + + @SpykBean + lateinit var loginInterceptor: LoginInterceptor + + @SpykBean + lateinit var adminInterceptor: AdminInterceptor + + @SpykBean + lateinit var memberIdResolver: MemberIdResolver + + init { + context("POST /reservations") { + lateinit var member: MemberEntity + beforeTest { + member = login(MemberFixture.create(role = Role.MEMBER)) + } + + test("정상 응답") { + val reservationRequest = createRequest() + val paymentApproveResponse = PaymentFixture.createApproveResponse().copy( + paymentKey = reservationRequest.paymentKey, + orderId = reservationRequest.orderId, + totalAmount = reservationRequest.amount, + ) + + every { + paymentClient.confirmPayment(any()) + } returns paymentApproveResponse + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + body(reservationRequest) + }.When { + post("/reservations") + }.Then { + log().all() + statusCode(201) + body("data.date", equalTo(reservationRequest.date.toString())) + body("data.status", equalTo(ReservationStatus.CONFIRMED.name)) + } + } + + test("결제 과정에서 발생하는 에러는 그대로 응답") { + val reservationRequest = createRequest() + val paymentException = RoomescapeException( + ErrorType.PAYMENT_SERVER_ERROR, + HttpStatus.INTERNAL_SERVER_ERROR + ) + + every { + paymentClient.confirmPayment(any()) + } throws paymentException + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + body(reservationRequest) + }.When { + post("/reservations") + }.Then { + log().all() + statusCode(paymentException.httpStatus.value()) + body("errorType", equalTo(paymentException.errorType.name)) + } + } + + test("결제 완료 후 예약 / 결제 정보 저장 과정에서 에러 발생시 결제 취소 후 에러 응답") { + val reservationRequest = createRequest() + val paymentApproveResponse = PaymentFixture.createApproveResponse().copy( + paymentKey = reservationRequest.paymentKey, + orderId = reservationRequest.orderId, + totalAmount = reservationRequest.amount, + ) + + every { + paymentClient.confirmPayment(any()) + } returns paymentApproveResponse + + // 예약 저장 과정에서 테마가 없는 예외 + val invalidRequest = reservationRequest.copy(themeId = reservationRequest.themeId + 1) + val expectedException = RoomescapeException(ErrorType.THEME_NOT_FOUND, HttpStatus.BAD_REQUEST) + + every { + paymentClient.cancelPayment(any()) + } returns PaymentFixture.createCancelResponse() + + val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery( + "SELECT COUNT(c) FROM CanceledPaymentEntity c", + Long::class.java + ).singleResult + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + body(invalidRequest) + }.When { + post("/reservations") + }.Then { + log().all() + statusCode(expectedException.httpStatus.value()) + body("errorType", equalTo(expectedException.errorType.name)) + } + + val canceledPaymentSizeAfterApiCall: Long = entityManager.createQuery( + "SELECT COUNT(c) FROM CanceledPaymentEntity c", + Long::class.java + ).singleResult + + canceledPaymentSizeAfterApiCall shouldBe canceledPaymentSizeBeforeApiCall + 1L + } + } + + context("GET /reservations") { + lateinit var reservations: MutableMap> + beforeTest { + reservations = createDummyReservations() + } + + test("관리자이면 정상 응답") { + login(MemberFixture.create(role = Role.ADMIN)) + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + }.When { + get("/reservations") + }.Then { + log().all() + statusCode(200) + body("data.reservations.size()", equalTo(reservations.values.sumOf { it.size })) + } + } + } + + context("GET /reservations-mine") { + lateinit var reservations: MutableMap> + beforeTest { + reservations = createDummyReservations() + } + + test("로그인한 회원이 자신의 예약 목록을 조회한다.") { + val member: MemberEntity = login(reservations.keys.first()) + val expectedReservations: Int = reservations[member]?.size ?: 0 + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + }.When { + get("/reservations-mine") + }.Then { + log().all() + statusCode(200) + body("data.reservations.size()", equalTo(expectedReservations)) + } + } + } + + context("GET /reservations/search") { + lateinit var reservations: MutableMap> + beforeTest { + reservations = createDummyReservations() + } + + test("관리자만 검색할 수 있다.") { + login(reservations.keys.first()) + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + }.When { + get("/reservations/search") + }.Then { + log().all() + header(HttpHeaders.CONTENT_TYPE, containsString(MediaType.TEXT_HTML_VALUE)) + } + } + + test("파라미터를 지정하지 않으면 전체 목록 응답") { + login(MemberFixture.create(role = Role.ADMIN)) + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + }.When { + get("/reservations/search") + }.Then { + log().all() + statusCode(200) + body("data.reservations.size()", equalTo(reservations.values.sumOf { it.size })) + } + } + + test("시작 날짜가 종료 날짜 이전이면 예외 응답") { + login(MemberFixture.create(role = Role.ADMIN)) + + val startDate = LocalDate.now().plusDays(1) + val endDate = LocalDate.now() + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + param("dateFrom", startDate.toString()) + param("dateTo", endDate.toString()) + }.When { + get("/reservations/search") + }.Then { + log().all() + statusCode(HttpStatus.BAD_REQUEST.value()) + body("errorType", equalTo(ErrorType.INVALID_DATE_RANGE.name)) + } + } + + test("동일한 회원의 모든 예약 응답") { + login(MemberFixture.create(role = Role.ADMIN)) + val member: MemberEntity = reservations.keys.first() + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + param("memberId", member.id) + }.When { + get("/reservations/search") + }.Then { + log().all() + statusCode(200) + body("data.reservations.size()", equalTo(reservations[member]?.size ?: 0)) + } + } + + test("동일한 테마의 모든 예약 응답") { + login(MemberFixture.create(role = Role.ADMIN)) + val themes = reservations.values.flatten().map { it.theme } + val requestThemeId: Long = themes.first().id!! + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + param("themeId", requestThemeId) + }.When { + get("/reservations/search") + }.Then { + log().all() + statusCode(200) + body("data.reservations.size()", equalTo(themes.filter { it.id == requestThemeId }.size)) + } + } + + test("시작 날짜와 종료 날짜 사이의 예약 응답") { + login(MemberFixture.create(role = Role.ADMIN)) + val dateFrom: LocalDate = reservations.values.flatten().minOf { it.date } + val dateTo: LocalDate = reservations.values.flatten().maxOf { it.date } + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + param("dateFrom", dateFrom.toString()) + param("dateTo", dateTo.toString()) + }.When { + get("/reservations/search") + }.Then { + log().all() + statusCode(200) + body("data.reservations.size()", equalTo(reservations.values.sumOf { it.size })) + } + } + } + + context("DELETE /reservations/{id}") { + lateinit var reservations: MutableMap> + beforeTest { + reservations = createDummyReservations() + } + + test("관리자만 예약을 삭제할 수 있다.") { + login(MemberFixture.create(role = Role.MEMBER)) + val reservation: ReservationEntity = reservations.values.flatten().first() + + Given { + port(port) + }.When { + delete("/reservations/${reservation.id}") + }.Then { + log().all() + statusCode(302) + header(HttpHeaders.LOCATION, containsString("/login")) + } + } + + test("결제되지 않은 예약은 바로 제거") { + login(MemberFixture.create(role = Role.ADMIN)) + val reservationId: Long = reservations.values.flatten().first().id!! + + transactionTemplate.execute { + val reservation: ReservationEntity = entityManager.find( + ReservationEntity::class.java, + reservationId + ) + reservation.reservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED + entityManager.persist(reservation) + entityManager.flush() + entityManager.clear() + } + + Given { + port(port) + }.When { + delete("/reservations/$reservationId") + }.Then { + log().all() + statusCode(HttpStatus.NO_CONTENT.value()) + } + + // 예약이 삭제되었는지 확인 + transactionTemplate.executeWithoutResult { + val deletedReservation = entityManager.find( + ReservationEntity::class.java, + reservationId + ) + deletedReservation shouldBe null + } + } + + test("결제된 예약은 취소 후 제거") { + login(MemberFixture.create(role = Role.ADMIN)) + val reservation: ReservationEntity = reservations.values.flatten().first() + lateinit var payment: PaymentEntity + + transactionTemplate.execute { + payment = PaymentFixture.create(reservation = reservation).also { + entityManager.persist(it) + entityManager.flush() + entityManager.clear() + } + } + + every { + paymentClient.cancelPayment(any()) + } returns PaymentFixture.createCancelResponse() + + val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery( + "SELECT COUNT(c) FROM CanceledPaymentEntity c", + Long::class.java + ).singleResult + + Given { + port(port) + }.When { + delete("/reservations/${reservation.id}") + }.Then { + log().all() + statusCode(HttpStatus.NO_CONTENT.value()) + } + + val canceledPaymentSizeAfterApiCall: Long = entityManager.createQuery( + "SELECT COUNT(c) FROM CanceledPaymentEntity c", + Long::class.java + ).singleResult + + canceledPaymentSizeAfterApiCall shouldBe canceledPaymentSizeBeforeApiCall + 1L + } + } + + context("POST /reservations/admin") { + test("관리자가 예약을 추가하면 결제 대기 상태로 예약 생성") { + val member = login(MemberFixture.create(role = Role.ADMIN)) + val adminRequest: AdminReservationRequest = createRequest().let { + AdminReservationRequest( + date = it.date, + themeId = it.themeId, + timeId = it.timeId, + memberId = member.id!!, + ) + } + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + body(adminRequest) + }.When { + post("/reservations/admin") + }.Then { + log().all() + statusCode(201) + body("data.status", equalTo(ReservationStatus.CONFIRMED_PAYMENT_REQUIRED.name)) + } + } + } + + context("GET /reservations/waiting") { + lateinit var reservations: MutableMap> + beforeTest { + reservations = createDummyReservations() + } + + test("관리자가 아니면 조회할 수 없다.") { + login(MemberFixture.create(role = Role.MEMBER)) + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + }.When { + get("/reservations/waiting") + }.Then { + log().all() + header(HttpHeaders.CONTENT_TYPE, containsString(MediaType.TEXT_HTML_VALUE)) + } + } + + test("대기 중인 예약 목록을 조회한다.") { + login(MemberFixture.create(role = Role.ADMIN)) + val expected = reservations.values.flatten() + .count { it.reservationStatus == ReservationStatus.WAITING } + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + }.When { + get("/reservations/waiting") + }.Then { + log().all() + statusCode(200) + body("data.reservations.size()", equalTo(expected)) + } + } + } + + context("POST /reservations/waiting") { + test("회원이 대기 예약을 추가한다.") { + val member = login(MemberFixture.create(role = Role.MEMBER)) + val waitingRequest: WaitingRequest = createRequest().let { + WaitingRequest( + date = it.date, + themeId = it.themeId, + timeId = it.timeId + ) + } + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + body(waitingRequest) + }.When { + post("/reservations/waiting") + }.Then { + log().all() + statusCode(201) + body("data.member.id", equalTo(member.id!!.toInt())) + body("data.status", equalTo(ReservationStatus.WAITING.name)) + } + } + + test("이미 예약된 시간, 테마로 대기 예약 요청 시 예외 응답") { + val member = login(MemberFixture.create(role = Role.MEMBER)) + val reservationRequest = createRequest() + + transactionTemplate.executeWithoutResult { + val reservation = ReservationFixture.create( + date = reservationRequest.date, + theme = entityManager.find(ThemeEntity::class.java, reservationRequest.themeId), + reservationTime = entityManager.find(ReservationTimeEntity::class.java, reservationRequest.timeId), + member = member, + status = ReservationStatus.WAITING + ) + entityManager.persist(reservation) + entityManager.flush() + entityManager.clear() + } + + // 이미 예약된 시간, 테마로 대기 예약 요청 + val waitingRequest = WaitingRequest( + date = reservationRequest.date, + themeId = reservationRequest.themeId, + timeId = reservationRequest.timeId + ) + + Given { + port(port) + contentType(MediaType.APPLICATION_JSON_VALUE) + body(waitingRequest) + }.When { + post("/reservations/waiting") + }.Then { + log().all() + statusCode(HttpStatus.BAD_REQUEST.value()) + body("errorType", equalTo(ErrorType.HAS_RESERVATION_OR_WAITING.name)) + } + } + } + + context("DELETE /reservations/waiting/{id}") { + lateinit var reservations: MutableMap> + beforeTest { + reservations = createDummyReservations() + } + + test("대기 중인 예약을 취소한다.") { + val member = login(MemberFixture.create(role = Role.MEMBER)) + val waiting: ReservationEntity = createSingleReservation( + member = member, + status = ReservationStatus.WAITING + ) + + Given { + port(port) + }.When { + delete("/reservations/waiting/${waiting.id}") + }.Then { + log().all() + statusCode(HttpStatus.NO_CONTENT.value()) + } + + transactionTemplate.executeWithoutResult { _ -> + entityManager.find( + ReservationEntity::class.java, + waiting.id + ) shouldBe null + } + } + + test("이미 완료된 예약은 삭제할 수 없다.") { + val member = login(MemberFixture.create(role = Role.MEMBER)) + val reservation: ReservationEntity = createSingleReservation( + member = member, + status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED + ) + + Given { + port(port) + }.When { + delete("/reservations/waiting/{id}", reservation.id) + }.Then { + log().all() + body("errorType", equalTo(ErrorType.RESERVATION_NOT_FOUND.name)) + statusCode(HttpStatus.NOT_FOUND.value()) + } + } + } + + context("POST /reservations/waiting/{id}/approve") { + test("관리자만 승인할 수 있다.") { + login(MemberFixture.create(role = Role.MEMBER)) + + Given { + port(port) + }.When { + post("/reservations/waiting/1/approve") + }.Then { + log().all() + statusCode(302) + header(HttpHeaders.LOCATION, containsString("/login")) + } + } + + test("대기 예약을 승인하면 결제 대기 상태로 변경") { + val member = login(MemberFixture.create(role = Role.ADMIN)) + val reservation = createSingleReservation( + member = member, + status = ReservationStatus.WAITING + ) + + Given { + port(port) + }.When { + post("/reservations/waiting/${reservation.id!!}/approve") + }.Then { + log().all() + statusCode(200) + } + + transactionTemplate.executeWithoutResult { _ -> + entityManager.find( + ReservationEntity::class.java, + reservation.id + )?.also { + it.reservationStatus shouldBe ReservationStatus.CONFIRMED_PAYMENT_REQUIRED + } ?: throw AssertionError("Reservation not found") + } + } + } + + context("POST /reservations/waiting/{id}/deny") { + test("관리자만 거절할 수 있다.") { + login(MemberFixture.create(role = Role.MEMBER)) + + Given { + port(port) + }.When { + post("/reservations/waiting/1/deny") + }.Then { + log().all() + statusCode(302) + header(HttpHeaders.LOCATION, containsString("/login")) + } + } + + test("거절된 예약은 삭제된다.") { + val member = login(MemberFixture.create(role = Role.ADMIN)) + val reservation = createSingleReservation( + member = member, + status = ReservationStatus.WAITING + ) + + Given { + port(port) + }.When { + post("/reservations/waiting/${reservation.id!!}/deny") + }.Then { + log().all() + statusCode(204) + } + + transactionTemplate.executeWithoutResult { _ -> + entityManager.find( + ReservationEntity::class.java, + reservation.id + ) shouldBe null + } + } + } + } + + fun createSingleReservation( + date: LocalDate = LocalDate.now().plusDays(1), + time: LocalTime = LocalTime.now(), + themeName: String = "Default Theme", + member: MemberEntity = MemberFixture.create(role = Role.MEMBER), + status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED + ): ReservationEntity { + return ReservationFixture.create( + date = date, + theme = ThemeFixture.create(name = themeName), + reservationTime = ReservationTimeFixture.create(startAt = time), + member = member, + status = status + ).also { it -> + transactionTemplate.execute { _ -> + if (member.id == null) { + entityManager.persist(member) + } + entityManager.persist(it.reservationTime) + entityManager.persist(it.theme) + entityManager.persist(it) + entityManager.flush() + entityManager.clear() + } + } + } + + fun createDummyReservations(): MutableMap> { + val reservations: MutableMap> = mutableMapOf() + val members: List = listOf( + MemberFixture.create(role = Role.MEMBER), + MemberFixture.create(role = Role.MEMBER) + ) + + transactionTemplate.executeWithoutResult { + members.forEach { member -> + entityManager.persist(member) + } + entityManager.flush() + entityManager.clear() + } + + transactionTemplate.executeWithoutResult { + repeat(10) { index -> + val theme = ThemeFixture.create(name = "theme$index") + val time = ReservationTimeFixture.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, + member = members[index % members.size], + status = ReservationStatus.CONFIRMED + ) + entityManager.persist(reservation) + reservations.getOrPut(reservation.member) { mutableListOf() }.add(reservation) + } + entityManager.flush() + entityManager.clear() + } + + return reservations + } + + fun createRequest( + theme: ThemeEntity = ThemeFixture.create(), + time: ReservationTimeEntity = ReservationTimeFixture.create(), + ): ReservationRequest { + lateinit var reservationRequest: ReservationRequest + + transactionTemplate.executeWithoutResult { + entityManager.persist(theme) + entityManager.persist(time) + + reservationRequest = ReservationFixture.createRequest( + themeId = theme.id!!, + timeId = time.id!!, + ) + + entityManager.flush() + entityManager.clear() + } + + return reservationRequest + } + + fun login(member: MemberEntity): MemberEntity { + if (member.id == null) { + transactionTemplate.executeWithoutResult { + entityManager.persist(member) + entityManager.flush() + entityManager.clear() + } + } + + if (member.isAdmin()) { + loginAsAdmin() + } else { + loginAsUser() + } + resolveMemberId(member.id!!) + + return member + } + + private fun loginAsUser() { + every { + loginInterceptor.preHandle(any(), any(), any()) + } returns true + } + + private fun loginAsAdmin() { + every { + adminInterceptor.preHandle(any(), any(), any()) + } returns true + } + + private fun resolveMemberId(memberId: Long) { + every { + memberIdResolver.resolveArgument(any(), any(), any(), any()) + } returns memberId + } } -- 2.47.2 From 0a4ef5284cedbabcb37778c340291445c4a1f24e Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 21 Jul 2025 21:01:06 +0900 Subject: [PATCH 38/40] =?UTF-8?q?fix:=20json=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/reservation/web/ReservationResponse.kt | 2 +- src/main/resources/static/js/reservation-mine.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/roomescape/reservation/web/ReservationResponse.kt b/src/main/java/roomescape/reservation/web/ReservationResponse.kt index 158f54f6..3776d150 100644 --- a/src/main/java/roomescape/reservation/web/ReservationResponse.kt +++ b/src/main/java/roomescape/reservation/web/ReservationResponse.kt @@ -43,7 +43,7 @@ data class MyReservationResponse( @JvmRecord data class MyReservationsResponse( @field:Schema(description = "현재 로그인한 회원의 예약 및 대기 목록") - val myReservationResponses: List + val reservations: List ) @Schema(name = "예약 정보", description = "예약 저장 및 조회 응답에 사용됩니다.") diff --git a/src/main/resources/static/js/reservation-mine.js b/src/main/resources/static/js/reservation-mine.js index ae17a8af..80a4d903 100644 --- a/src/main/resources/static/js/reservation-mine.js +++ b/src/main/resources/static/js/reservation-mine.js @@ -11,7 +11,7 @@ document.addEventListener('DOMContentLoaded', () => { function render(data) { const tableBody = document.getElementById('table-body'); tableBody.innerHTML = ''; - data.data.myReservationResponses.forEach(item => { + data.data.reservations.forEach(item => { const row = tableBody.insertRow(); const theme = item.themeName; -- 2.47.2 From ef76d1b0035de2fcf930023bba6f621adbf2aeaa Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 21 Jul 2025 21:01:56 +0900 Subject: [PATCH 39/40] Rename .java to .kt --- .../business/{PaymentServiceTest.java => PaymentServiceTest.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/java/roomescape/payment/business/{PaymentServiceTest.java => PaymentServiceTest.kt} (100%) diff --git a/src/test/java/roomescape/payment/business/PaymentServiceTest.java b/src/test/java/roomescape/payment/business/PaymentServiceTest.kt similarity index 100% rename from src/test/java/roomescape/payment/business/PaymentServiceTest.java rename to src/test/java/roomescape/payment/business/PaymentServiceTest.kt -- 2.47.2 From ba0dc44e04591e30e912e037dfb7e3ee3427b45d Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 21 Jul 2025 21:01:56 +0900 Subject: [PATCH 40/40] =?UTF-8?q?test:=20PaymentServiceTest=20=EC=BD=94?= =?UTF-8?q?=ED=8B=80=EB=A6=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/business/PaymentServiceKTest.kt | 129 ---------- .../payment/business/PaymentServiceTest.kt | 241 ++++++++---------- 2 files changed, 107 insertions(+), 263 deletions(-) delete mode 100644 src/test/java/roomescape/payment/business/PaymentServiceKTest.kt diff --git a/src/test/java/roomescape/payment/business/PaymentServiceKTest.kt b/src/test/java/roomescape/payment/business/PaymentServiceKTest.kt deleted file mode 100644 index e72b228c..00000000 --- a/src/test/java/roomescape/payment/business/PaymentServiceKTest.kt +++ /dev/null @@ -1,129 +0,0 @@ -package roomescape.payment.business - -import io.kotest.assertions.assertSoftly -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe -import io.mockk.every -import io.mockk.just -import io.mockk.mockk -import io.mockk.runs -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorType -import roomescape.common.exception.RoomescapeException -import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository -import roomescape.payment.infrastructure.persistence.PaymentRepository -import roomescape.payment.web.PaymentCancel -import roomescape.util.PaymentFixture -import java.time.OffsetDateTime - -class PaymentServiceKTest : FunSpec({ - val paymentRepository: PaymentRepository = mockk() - val canceledPaymentRepository: CanceledPaymentRepository = mockk() - - val paymentService = PaymentService(paymentRepository, canceledPaymentRepository) - - context("cancelPaymentByAdmin") { - val reservationId = 1L - test("reservationId로 paymentKey를 찾을 수 없으면 예외를 던진다.") { - every { paymentRepository.findPaymentKeyByReservationId(reservationId) } returns null - - val exception = shouldThrow { - paymentService.cancelPaymentByAdmin(reservationId) - } - - assertSoftly(exception) { - this.errorType shouldBe ErrorType.PAYMENT_NOT_FOUND - this.httpStatus shouldBe HttpStatus.NOT_FOUND - } - } - - context("reservationId로 paymentKey를 찾고난 후") { - val paymentKey = "test-payment-key" - - every { - paymentRepository.findPaymentKeyByReservationId(reservationId) - } returns paymentKey - - test("해당 paymentKey로 paymentEntity를 찾을 수 없으면 예외를 던진다.") { - every { - paymentRepository.findByPaymentKey(paymentKey) - } returns null - - val exception = shouldThrow { - paymentService.cancelPaymentByAdmin(reservationId) - } - - assertSoftly(exception) { - this.errorType shouldBe ErrorType.PAYMENT_NOT_FOUND - this.httpStatus shouldBe HttpStatus.NOT_FOUND - } - } - - test("해당 paymentKey로 paymentEntity를 찾고, cancelPaymentEntity를 저장한다.") { - val paymentEntity = PaymentFixture.create(paymentKey = paymentKey) - - every { - paymentRepository.findByPaymentKey(paymentKey) - } returns paymentEntity.also { - every { - paymentRepository.delete(it) - } just runs - } - - every { - canceledPaymentRepository.save(any()) - } returns PaymentFixture.createCanceled( - id = 1L, - paymentKey = paymentKey, - cancelAmount = paymentEntity.totalAmount, - ) - - val result: PaymentCancel.Request = paymentService.cancelPaymentByAdmin(reservationId) - - assertSoftly(result) { - this.paymentKey shouldBe paymentKey - this.amount shouldBe paymentEntity.totalAmount - this.cancelReason shouldBe "고객 요청" - } - } - } - } - - context("updateCanceledTime") { - val paymentKey = "test-payment-key" - val canceledAt = OffsetDateTime.now() - - test("paymentKey로 canceledPaymentEntity를 찾을 수 없으면 예외를 던진다.") { - every { - canceledPaymentRepository.findByPaymentKey(paymentKey) - } returns null - - val exception = shouldThrow { - paymentService.updateCanceledTime(paymentKey, canceledAt) - } - - assertSoftly(exception) { - this.errorType shouldBe ErrorType.PAYMENT_NOT_FOUND - this.httpStatus shouldBe HttpStatus.NOT_FOUND - } - } - - test("paymentKey로 canceledPaymentEntity를 찾고, canceledAt을 업데이트한다.") { - val canceledPaymentEntity = PaymentFixture.createCanceled( - paymentKey = paymentKey, - canceledAt = canceledAt.minusMinutes(1) - ) - - every { - canceledPaymentRepository.findByPaymentKey(paymentKey) - } returns canceledPaymentEntity - - paymentService.updateCanceledTime(paymentKey, canceledAt) - - assertSoftly(canceledPaymentEntity) { - this.canceledAt shouldBe canceledAt - } - } - } -}) diff --git a/src/test/java/roomescape/payment/business/PaymentServiceTest.kt b/src/test/java/roomescape/payment/business/PaymentServiceTest.kt index dffdd39a..be9c05fa 100644 --- a/src/test/java/roomescape/payment/business/PaymentServiceTest.kt +++ b/src/test/java/roomescape/payment/business/PaymentServiceTest.kt @@ -1,156 +1,129 @@ -package roomescape.payment.business; +package roomescape.payment.business -import static org.assertj.core.api.Assertions.*; +import io.kotest.assertions.assertSoftly +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.runs +import org.springframework.http.HttpStatus +import roomescape.common.exception.ErrorType +import roomescape.common.exception.RoomescapeException +import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository +import roomescape.payment.infrastructure.persistence.PaymentRepository +import roomescape.payment.web.PaymentCancel +import roomescape.util.PaymentFixture +import java.time.OffsetDateTime -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.OffsetDateTime; +class PaymentServiceTest : FunSpec({ + val paymentRepository: PaymentRepository = mockk() + val canceledPaymentRepository: CanceledPaymentRepository = mockk() -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.Sql.ExecutionPhase; + val paymentService = PaymentService(paymentRepository, canceledPaymentRepository) -import roomescape.common.exception.RoomescapeException; -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.member.infrastructure.persistence.MemberRepository; -import roomescape.member.infrastructure.persistence.Role; -import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity; -import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository; -import roomescape.payment.web.PaymentApprove; -import roomescape.payment.web.PaymentCancel; -import roomescape.payment.web.ReservationPaymentResponse; -import roomescape.reservation.infrastructure.persistence.ReservationEntity; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.theme.infrastructure.persistence.ThemeEntity; -import roomescape.theme.infrastructure.persistence.ThemeRepository; + context("cancelPaymentByAdmin") { + val reservationId = 1L + test("reservationId로 paymentKey를 찾을 수 없으면 예외를 던진다.") { + every { paymentRepository.findPaymentKeyByReservationId(reservationId) } returns null -@SpringBootTest -@Sql(scripts = "/truncate.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD) -class PaymentServiceTest { + val exception = shouldThrow { + paymentService.cancelPaymentByAdmin(reservationId) + } - @Autowired - private PaymentService paymentService; - @Autowired - private ReservationRepository reservationRepository; - @Autowired - private MemberRepository memberRepository; - @Autowired - private ReservationTimeRepository reservationTimeRepository; - @Autowired - private ThemeRepository themeRepository; - @Autowired - private CanceledPaymentRepository canceledPaymentRepository; + assertSoftly(exception) { + this.errorType shouldBe ErrorType.PAYMENT_NOT_FOUND + this.httpStatus shouldBe HttpStatus.NOT_FOUND + } + } - @Test - @DisplayName("결제 정보를 저장한다.") - void savePayment() { - // given - PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", - OffsetDateTime.now(), 10000L); - LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - ReservationEntity reservation = reservationRepository.save( - new ReservationEntity(null, date, time, theme, member, - ReservationStatus.CONFIRMED)); + context("reservationId로 paymentKey를 찾고난 후") { + val paymentKey = "test-payment-key" - // when - ReservationPaymentResponse reservationPaymentResponse = paymentService.savePayment(paymentInfo, reservation); + every { + paymentRepository.findPaymentKeyByReservationId(reservationId) + } returns paymentKey - // then - assertThat(reservationPaymentResponse.reservation().id).isEqualTo(reservation.getId()); - assertThat(reservationPaymentResponse.paymentKey()).isEqualTo(paymentInfo.paymentKey); - } + test("해당 paymentKey로 paymentEntity를 찾을 수 없으면 예외를 던진다.") { + every { + paymentRepository.findByPaymentKey(paymentKey) + } returns null - @Test - @DisplayName("예약 ID로 결제 정보를 제거하고, 결제 취소 테이블에 취소 정보를 저장한다.") - void cancelPaymentByAdmin() { - // given - PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", - OffsetDateTime.now(), 10000L); - LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - ReservationEntity reservation = reservationRepository.save( - new ReservationEntity(null, date, time, theme, member, - ReservationStatus.CONFIRMED)); + val exception = shouldThrow { + paymentService.cancelPaymentByAdmin(reservationId) + } - paymentService.savePayment(paymentInfo, reservation); + assertSoftly(exception) { + this.errorType shouldBe ErrorType.PAYMENT_NOT_FOUND + this.httpStatus shouldBe HttpStatus.NOT_FOUND + } + } - // when - PaymentCancel.Request paymentCancelRequest = paymentService.cancelPaymentByAdmin(reservation.getId()); + test("해당 paymentKey로 paymentEntity를 찾고, cancelPaymentEntity를 저장한다.") { + val paymentEntity = PaymentFixture.create(paymentKey = paymentKey) - // then - assertThat(canceledPaymentRepository.findByPaymentKey("payment-key")).isNotNull(); - assertThat(paymentCancelRequest.paymentKey).isEqualTo(paymentInfo.paymentKey); - assertThat(paymentCancelRequest.cancelReason).isEqualTo("고객 요청"); - assertThat(paymentCancelRequest.amount).isEqualTo(10000L); - } + every { + paymentRepository.findByPaymentKey(paymentKey) + } returns paymentEntity.also { + every { + paymentRepository.delete(it) + } just runs + } - @Test - @DisplayName("입력된 예약 ID에 대한 결제 정보가 없으면 예외가 발생한다.") - void cancelPaymentByAdminWithNonExistentReservationId() { - // given - Long nonExistentReservationId = 1L; + every { + canceledPaymentRepository.save(any()) + } returns PaymentFixture.createCanceled( + id = 1L, + paymentKey = paymentKey, + cancelAmount = paymentEntity.totalAmount, + ) - // when - assertThatThrownBy(() -> paymentService.cancelPaymentByAdmin(nonExistentReservationId)) - .isInstanceOf(RoomescapeException.class); - } + val result: PaymentCancel.Request = paymentService.cancelPaymentByAdmin(reservationId) - @Test - @DisplayName("결제 취소 정보에 있는 취소 시간을 업데이트한다.") - void updateCanceledTime() { - // given - PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", - OffsetDateTime.now(), 10000L); - LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); - LocalDate date = localDateTime.toLocalDate(); - ReservationTimeEntity time = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); - ReservationEntity reservation = reservationRepository.save( - new ReservationEntity(null, date, time, theme, member, - ReservationStatus.CONFIRMED)); + assertSoftly(result) { + this.paymentKey shouldBe paymentKey + this.amount shouldBe paymentEntity.totalAmount + this.cancelReason shouldBe "고객 요청" + } + } + } + } - paymentService.savePayment(paymentInfo, reservation); - paymentService.cancelPaymentByAdmin(reservation.getId()); + context("updateCanceledTime") { + val paymentKey = "test-payment-key" + val canceledAt = OffsetDateTime.now() - // when - OffsetDateTime canceledAt = OffsetDateTime.now().plusHours(2L); - paymentService.updateCanceledTime(paymentInfo.paymentKey, canceledAt); + test("paymentKey로 canceledPaymentEntity를 찾을 수 없으면 예외를 던진다.") { + every { + canceledPaymentRepository.findByPaymentKey(paymentKey) + } returns null - // then - CanceledPaymentEntity canceledPayment = canceledPaymentRepository.findByPaymentKey(paymentInfo.paymentKey); + val exception = shouldThrow { + paymentService.updateCanceledTime(paymentKey, canceledAt) + } - assertThat(canceledPayment).isNotNull(); - assertThat(canceledPayment.getCanceledAt()).isEqualTo(canceledAt); - } + assertSoftly(exception) { + this.errorType shouldBe ErrorType.PAYMENT_NOT_FOUND + this.httpStatus shouldBe HttpStatus.NOT_FOUND + } + } - @Test - @DisplayName("결제 취소 시간을 업데이트 할 때, 입력한 paymentKey가 존재하지 않으면 예외가 발생한다.") - void updateCanceledTimeWithNonExistentPaymentKey() { - // given - OffsetDateTime canceledAt = OffsetDateTime.now().plusHours(2L); + test("paymentKey로 canceledPaymentEntity를 찾고, canceledAt을 업데이트한다.") { + val canceledPaymentEntity = PaymentFixture.createCanceled( + paymentKey = paymentKey, + canceledAt = canceledAt.minusMinutes(1) + ) - // when - assertThatThrownBy(() -> paymentService.updateCanceledTime("non-existent-payment-key", canceledAt)) - .isInstanceOf(RoomescapeException.class); - } -} + every { + canceledPaymentRepository.findByPaymentKey(paymentKey) + } returns canceledPaymentEntity + + paymentService.updateCanceledTime(paymentKey, canceledAt) + + assertSoftly(canceledPaymentEntity) { + this.canceledAt shouldBe canceledAt + } + } + } +}) -- 2.47.2