From 7e8ecac48cd2776cad9266e42e1e99811d75fc0f Mon Sep 17 00:00:00 2001 From: hyowon Date: Wed, 20 Aug 2025 13:02:55 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[fix/#89]=20=EA=B2=B0=EC=A0=9C=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C=EB=90=9C=20=EB=A3=B8=EB=A7=8C=20=EC=98=88=EC=95=BD?= =?UTF-8?q?=EC=9D=B4=20=EB=B6=88=EA=B0=80=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ReservationRepository.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/sumte/reservation/repository/ReservationRepository.java b/src/main/java/com/sumte/reservation/repository/ReservationRepository.java index 47dae26..94c68ff 100644 --- a/src/main/java/com/sumte/reservation/repository/ReservationRepository.java +++ b/src/main/java/com/sumte/reservation/repository/ReservationRepository.java @@ -15,15 +15,19 @@ import java.util.List; public interface ReservationRepository extends JpaRepository { - @Query(""" - SELECT CASE WHEN COUNT(r) > 0 THEN true ELSE false END - FROM Reservation r - WHERE r.room = :room - AND r.startDate < :endDate - AND r.endDate > :startDate""") - boolean existsOverlappingReservation(@Param("room") Room room, - @Param("startDate") LocalDate startDate, - @Param("endDate") LocalDate endDate); + @Query(""" +SELECT CASE WHEN COUNT(r) > 0 THEN true ELSE false END +FROM Reservation r +JOIN Payment p ON p.reservation = r +WHERE r.room = :room + AND r.reservationStatus <> com.sumte.reservation.entity.ReservationStatus.CANCELED + AND p.paymentStatus = com.sumte.payment.entity.PaymentStatus.PAID + AND r.startDate < :endDate + AND r.endDate > :startDate +""") + boolean existsOverlappingReservation(@Param("room") Room room, + @Param("startDate") LocalDate startDate, + @Param("endDate") LocalDate endDate); List findByReservationStatusNot(ReservationStatus status); From 255b680f00b0b5a8df09a361aea2c8f1bf8ebbf7 Mon Sep 17 00:00:00 2001 From: hyowon Date: Wed, 20 Aug 2025 15:21:45 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[fix/#89]=20=ED=9B=84=EA=B8=B0=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EC=97=AC=EB=B6=80=20=ED=8C=90=EB=8B=A8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sumte/reservation/service/ReservationServiceImpl.java | 5 ++--- .../java/com/sumte/review/repository/ReviewRepository.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java b/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java index d7681a0..7fae044 100644 --- a/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java +++ b/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java @@ -102,9 +102,8 @@ public Page getMyReservations(Pageable return reservations.map(reservation -> { boolean isComplete = reservation.getReservationStatus().equals(ReservationStatus.COMPLETED); - boolean reviewWritten = reviewRepository.existsByUserIdAndRoomGuesthouseId( - user.getId(), reservation.getRoom().getGuesthouse().getId() - ); + boolean reviewWritten = reviewRepository.existsByUserIdAndRoomId(user.getId(), reservation.getRoom().getId()); + boolean canWriteReview = isComplete && !reviewWritten; String firstImageUrl = imageRepository diff --git a/src/main/java/com/sumte/review/repository/ReviewRepository.java b/src/main/java/com/sumte/review/repository/ReviewRepository.java index 44551ca..c73d283 100644 --- a/src/main/java/com/sumte/review/repository/ReviewRepository.java +++ b/src/main/java/com/sumte/review/repository/ReviewRepository.java @@ -32,5 +32,5 @@ public interface ReviewRepository extends JpaRepository { int countByGuesthouseId(@Param("guesthouseId") Long guesthouseId); // int countByRoomGuesthouseId(Long guesthouseId); - boolean existsByUserIdAndRoomGuesthouseId(Long userId, Long roomGuesthouseId); + boolean existsByUserIdAndRoomId(Long userId, Long roomId); } \ No newline at end of file From f4e551fc8b443406d7276734a464cb546b887676 Mon Sep 17 00:00:00 2001 From: hyowon Date: Wed, 20 Aug 2025 16:40:03 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[fix/#89]=20=ED=9B=84=EA=B8=B0=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EC=97=AC=EB=B6=80=20=ED=8C=90=EB=8B=A8,=20?= =?UTF-8?q?=EC=98=88=EC=95=BD=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=B5=9C=EC=A2=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apiPayload/code/error/ReviewErrorCode.java | 3 ++- .../service/ReservationServiceImpl.java | 2 +- .../sumte/review/converter/ReviewConverter.java | 17 ++++++++++------- .../com/sumte/review/dto/ReviewRequestDto.java | 3 +-- .../com/sumte/review/dto/ReviewResponseDto.java | 1 + .../java/com/sumte/review/entity/Review.java | 5 +++++ .../review/repository/ReviewRepository.java | 2 +- .../com/sumte/review/service/ReviewService.java | 14 +++++++++++--- 8 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/sumte/apiPayload/code/error/ReviewErrorCode.java b/src/main/java/com/sumte/apiPayload/code/error/ReviewErrorCode.java index 1193208..0a04c35 100644 --- a/src/main/java/com/sumte/apiPayload/code/error/ReviewErrorCode.java +++ b/src/main/java/com/sumte/apiPayload/code/error/ReviewErrorCode.java @@ -13,7 +13,8 @@ public enum ReviewErrorCode implements ErrorCode { USER_NOT_FOUND(HttpStatus.NOT_FOUND, "REVIEW404", "리뷰 작성자를 찾을 수 없습니다."), ROOM_NOT_FOUND(HttpStatus.NOT_FOUND, "REVIEW404", "리뷰 대상 방을 찾을 수 없습니다."), REVIEW_NOT_FOUND(HttpStatus.NOT_FOUND, "REVIEW404", "해당 리뷰를 찾을 수 없습니다."), - UNAUTHORIZED(HttpStatus.FORBIDDEN, "REVIEW403", "권한이 없습니다."); + UNAUTHORIZED(HttpStatus.FORBIDDEN, "REVIEW403", "권한이 없습니다."), + ALREADY_REVIEWED(HttpStatus.CONFLICT, "REVIEW409", "이미 해당 예약에 대한 후기가 작성되었습니다."); // FORBIDDEN_REVIEW(HttpStatus.FORBIDDEN, "REVIEW403", "본인 리뷰만 수정/삭제할 수 있습니다."); 일단 만들어주기 본인의 리뷰에 대해서만 처리 private final HttpStatus httpStatus; diff --git a/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java b/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java index 7fae044..7256976 100644 --- a/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java +++ b/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java @@ -102,7 +102,7 @@ public Page getMyReservations(Pageable return reservations.map(reservation -> { boolean isComplete = reservation.getReservationStatus().equals(ReservationStatus.COMPLETED); - boolean reviewWritten = reviewRepository.existsByUserIdAndRoomId(user.getId(), reservation.getRoom().getId()); + boolean reviewWritten = reviewRepository.existsByUserIdAndReservationId(user.getId(), reservation.getId()); boolean canWriteReview = isComplete && !reviewWritten; diff --git a/src/main/java/com/sumte/review/converter/ReviewConverter.java b/src/main/java/com/sumte/review/converter/ReviewConverter.java index 32654ef..6cddcd6 100644 --- a/src/main/java/com/sumte/review/converter/ReviewConverter.java +++ b/src/main/java/com/sumte/review/converter/ReviewConverter.java @@ -1,5 +1,6 @@ package com.sumte.review.converter; +import com.sumte.reservation.entity.Reservation; import com.sumte.review.dto.ReviewRequestDto; import com.sumte.review.dto.ReviewResponseDto; import com.sumte.review.entity.Review; @@ -8,10 +9,11 @@ public class ReviewConverter { - public static Review toEntity(ReviewRequestDto dto, User user, Room room) { + public static Review toEntity(ReviewRequestDto dto, User user, Reservation reservation) { return Review.builder() .user(user) - .room(room) + .room(reservation.getRoom()) + .reservation(reservation) .contents(dto.getContents()) .score(dto.getScore()) .build(); @@ -24,11 +26,12 @@ public static void updateEntity(Review review, ReviewRequestDto dto) { public static ReviewResponseDto toDto(Review review) { return new ReviewResponseDto( - review.getId(), - review.getUser().getId(), - review.getRoom().getId(), - review.getContents(), - review.getScore() + review.getId(), + review.getUser().getId(), + review.getRoom().getId(), + review.getReservation() != null ? review.getReservation().getId() : null, + review.getContents(), + review.getScore() ); } } \ No newline at end of file diff --git a/src/main/java/com/sumte/review/dto/ReviewRequestDto.java b/src/main/java/com/sumte/review/dto/ReviewRequestDto.java index 96bf8d7..171b195 100644 --- a/src/main/java/com/sumte/review/dto/ReviewRequestDto.java +++ b/src/main/java/com/sumte/review/dto/ReviewRequestDto.java @@ -14,8 +14,7 @@ @Getter public class ReviewRequestDto { - @NotNull - private Long roomId; + private Long reservationId; private String contents; diff --git a/src/main/java/com/sumte/review/dto/ReviewResponseDto.java b/src/main/java/com/sumte/review/dto/ReviewResponseDto.java index c52f099..2c2e5d0 100644 --- a/src/main/java/com/sumte/review/dto/ReviewResponseDto.java +++ b/src/main/java/com/sumte/review/dto/ReviewResponseDto.java @@ -13,6 +13,7 @@ public class ReviewResponseDto { private Long id; private Long userId; private Long roomId; + private Long reservationId; private String contents; private int score; diff --git a/src/main/java/com/sumte/review/entity/Review.java b/src/main/java/com/sumte/review/entity/Review.java index 3ab63b0..de41d15 100644 --- a/src/main/java/com/sumte/review/entity/Review.java +++ b/src/main/java/com/sumte/review/entity/Review.java @@ -1,6 +1,7 @@ package com.sumte.review.entity; import com.sumte.jpa.BaseTimeEntity; +import com.sumte.reservation.entity.Reservation; import com.sumte.room.entity.Room; import com.sumte.user.entity.User; @@ -35,6 +36,10 @@ public class Review extends BaseTimeEntity { @JoinColumn(name = "room_id") private Room room; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "reservation_id") + private Reservation reservation; + private String contents; private int score; diff --git a/src/main/java/com/sumte/review/repository/ReviewRepository.java b/src/main/java/com/sumte/review/repository/ReviewRepository.java index c73d283..019aba4 100644 --- a/src/main/java/com/sumte/review/repository/ReviewRepository.java +++ b/src/main/java/com/sumte/review/repository/ReviewRepository.java @@ -32,5 +32,5 @@ public interface ReviewRepository extends JpaRepository { int countByGuesthouseId(@Param("guesthouseId") Long guesthouseId); // int countByRoomGuesthouseId(Long guesthouseId); - boolean existsByUserIdAndRoomId(Long userId, Long roomId); + boolean existsByUserIdAndReservationId(Long userId, Long reservationId); } \ No newline at end of file diff --git a/src/main/java/com/sumte/review/service/ReviewService.java b/src/main/java/com/sumte/review/service/ReviewService.java index 9072c01..6f1527a 100644 --- a/src/main/java/com/sumte/review/service/ReviewService.java +++ b/src/main/java/com/sumte/review/service/ReviewService.java @@ -6,6 +6,9 @@ import java.util.Optional; import java.util.stream.Collectors; +import com.sumte.apiPayload.code.error.ReservationErrorCode; +import com.sumte.reservation.entity.Reservation; +import com.sumte.reservation.repository.ReservationRepository; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -36,16 +39,21 @@ public class ReviewService { private final ReviewRepository reviewRepository; private final UserRepository userRepository; private final RoomRepository roomRepository; + private final ReservationRepository reservationRepository; private final ImageRepository imageRepository; @Transactional public Long createReview(Long userId, ReviewRequestDto dto) { User user = userRepository.findById(userId) .orElseThrow(() -> new SumteException(ReviewErrorCode.USER_NOT_FOUND)); - Room room = roomRepository.findById(dto.getRoomId()) - .orElseThrow(() -> new SumteException(ReviewErrorCode.ROOM_NOT_FOUND)); + Reservation reservation = reservationRepository.findById(dto.getReservationId()) + .orElseThrow(() -> new SumteException(ReservationErrorCode.RESERVATION_NOT_FOUND)); - Review review = ReviewConverter.toEntity(dto, user, room); + if (reviewRepository.existsByUserIdAndReservationId(userId, reservation.getId())) { + throw new SumteException(ReviewErrorCode.ALREADY_REVIEWED); + } + + Review review = ReviewConverter.toEntity(dto, user, reservation); Review saved = reviewRepository.save(review); return saved.getId(); }