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/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); diff --git a/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java b/src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java index d7681a0..7256976 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.existsByUserIdAndReservationId(user.getId(), reservation.getId()); + boolean canWriteReview = isComplete && !reviewWritten; String firstImageUrl = imageRepository 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 44551ca..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 existsByUserIdAndRoomGuesthouseId(Long userId, Long roomGuesthouseId); + 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(); }