11package com .sumte .reservation .service ;
22
3+ import java .time .LocalDate ;
4+ import java .time .LocalTime ;
5+ import java .util .List ;
6+ import java .util .Optional ;
7+
8+ import org .springframework .data .domain .Page ;
9+ import org .springframework .data .domain .Pageable ;
10+ import org .springframework .stereotype .Service ;
11+ import org .springframework .transaction .annotation .Transactional ;
12+
313import com .sumte .apiPayload .code .error .CommonErrorCode ;
414import com .sumte .apiPayload .code .error .ReservationErrorCode ;
515import com .sumte .apiPayload .exception .SumteException ;
16+ import com .sumte .image .entity .Image ;
17+ import com .sumte .image .entity .OwnerType ;
18+ import com .sumte .image .repository .ImageRepository ;
619import com .sumte .payment .entity .Payment ;
720import com .sumte .payment .entity .PaymentStatus ;
821import com .sumte .payment .repository .PaymentRepository ;
9- import com .sumte .reservation .entity .ReservationStatus ;
10- import com .sumte .review .repository .ReviewRepository ;
11- import org .springframework .data .domain .Page ;
12- import org .springframework .data .domain .Pageable ;
13- import org .springframework .stereotype .Service ;
14-
1522import com .sumte .reservation .converter .ReservationConverter ;
1623import com .sumte .reservation .dto .ReservationRequestDTO ;
1724import com .sumte .reservation .dto .ReservationResponseDTO ;
1825import com .sumte .reservation .entity .Reservation ;
26+ import com .sumte .reservation .entity .ReservationStatus ;
1927import com .sumte .reservation .repository .ReservationRepository ;
28+ import com .sumte .review .repository .ReviewRepository ;
2029import com .sumte .room .entity .Room ;
2130import com .sumte .room .repository .RoomRepository ;
2231import com .sumte .user .entity .User ;
2332import com .sumte .user .repository .UserRepository ;
2433
2534import lombok .RequiredArgsConstructor ;
26- import org .springframework .transaction .annotation .Transactional ;
27-
28- import java .time .LocalDate ;
29- import java .time .LocalTime ;
30- import java .util .List ;
31- import java .util .Optional ;
3235
3336@ Service
3437@ RequiredArgsConstructor
@@ -40,17 +43,20 @@ public class ReservationServiceImpl implements ReservationService {
4043 private final UserRepository userRepository ;
4144 private final PaymentRepository paymentRepository ;
4245 private final ReviewRepository reviewRepository ;
46+ private final ImageRepository imageRepository ;
4347
4448 @ Override
4549 @ Transactional
46- public ReservationResponseDTO .CreateReservationDTO createReservation (ReservationRequestDTO .CreateReservationDTO request , Long userId ) {
50+ public ReservationResponseDTO .CreateReservationDTO createReservation (
51+ ReservationRequestDTO .CreateReservationDTO request , Long userId ) {
4752 User user = userRepository .findById (userId )
48- .orElseThrow (() -> new SumteException (CommonErrorCode .USER_NOT_FOUND ));
53+ .orElseThrow (() -> new SumteException (CommonErrorCode .USER_NOT_FOUND ));
4954 Room room = roomRepository .findById (request .getRoomId ())
50- .orElseThrow (() -> new SumteException (ReservationErrorCode .ROOM_NOT_FOUND ));
55+ .orElseThrow (() -> new SumteException (ReservationErrorCode .ROOM_NOT_FOUND ));
5156
5257 // 닐짜 유효성 검사
53- if (request .getStartDate ().isAfter (request .getEndDate ()) || request .getStartDate ().isEqual (request .getEndDate ())) {
58+ if (request .getStartDate ().isAfter (request .getEndDate ()) || request .getStartDate ()
59+ .isEqual (request .getEndDate ())) {
5460 throw new SumteException (ReservationErrorCode .RESERVATION_DATE_INVALID );
5561 }
5662 // 정원 초과 검사
@@ -59,12 +65,13 @@ public ReservationResponseDTO.CreateReservationDTO createReservation(Reservation
5965 throw new SumteException (ReservationErrorCode .ROOM_CAPACITY_EXCEEDED );
6066 }
6167 // 중복 예약 검사
62- boolean isOverlapping = reservationRepository .existsOverlappingReservation (room , request .getStartDate (), request .getEndDate ());
63- if (isOverlapping ) {
68+ boolean isOverlapping = reservationRepository .existsOverlappingReservation (room , request .getStartDate (),
69+ request .getEndDate ());
70+ if (isOverlapping ) {
6471 throw new SumteException (ReservationErrorCode .ALREADY_RESERVED );
6572 }
6673
67- Reservation reservation = reservationConverter .toEntity (request ,user ,room );
74+ Reservation reservation = reservationConverter .toEntity (request , user , room );
6875 reservationRepository .save (reservation );
6976 return reservationConverter .toCreateResponse (reservation );
7077 }
@@ -73,37 +80,60 @@ public ReservationResponseDTO.CreateReservationDTO createReservation(Reservation
7380 @ Transactional (readOnly = true )
7481 public Page <ReservationResponseDTO .MyReservationDTO > getMyReservations (Long userId , Pageable pageable ) {
7582 User user = userRepository .findById (userId )
76- .orElseThrow (() -> new SumteException (CommonErrorCode .USER_NOT_FOUND ));
83+ .orElseThrow (() -> new SumteException (CommonErrorCode .USER_NOT_FOUND ));
7784
7885 Page <Reservation > reservations = reservationRepository .findAllByUser (user , pageable );
7986 return reservations .map (reservation -> {
8087 boolean isComplete = reservation .getReservationStatus ().equals (ReservationStatus .COMPLETED );
8188
82- boolean reviewWritten = reviewRepository .existsByUserIdAndRoomGuesthouseId (user .getId (), reservation .getRoom ().getGuesthouse ().getId ());
89+ boolean reviewWritten = reviewRepository .existsByUserIdAndRoomGuesthouseId (user .getId (),
90+ reservation .getRoom ().getGuesthouse ().getId ());
8391 boolean canWriteReview = isComplete && !reviewWritten ;
8492
85- return reservationConverter .toMyReservationDTO (reservation ,canWriteReview ,reviewWritten );
93+ // 첫 번째 방 이미지 URL 조회
94+ String firstImageUrl = imageRepository
95+ .findByOwnerTypeAndOwnerIdOrderBySortOrderAsc (
96+ OwnerType .ROOM ,
97+ reservation .getRoom ().getId ()
98+ )
99+ .stream ()
100+ .map (Image ::getUrl )
101+ .findFirst ()
102+ .orElse (null );
103+
104+ return reservationConverter .toMyReservationDTO (reservation , firstImageUrl , canWriteReview , reviewWritten );
86105 });
87106 }
88107
89108 @ Override
90109 @ Transactional (readOnly = true )
91110 public ReservationResponseDTO .ReservationDetailDTO getReservationDetail (Long reservationId , Long userId ) {
92111 Reservation reservation = reservationRepository .findById (reservationId )
93- .orElseThrow (() -> new SumteException (ReservationErrorCode .RESERVATION_NOT_FOUND ));
112+ .orElseThrow (() -> new SumteException (ReservationErrorCode .RESERVATION_NOT_FOUND ));
94113
95114 if (!reservation .getUser ().getId ().equals (userId )) {
96115 throw new SumteException (CommonErrorCode .FORBIDDEN );
97116 }
98117
99- return reservationConverter .toReservationDetailDTO (reservation );
118+ // 첫 번째 방 이미지 URL 조회
119+ String firstImageUrl = imageRepository
120+ .findByOwnerTypeAndOwnerIdOrderBySortOrderAsc (
121+ OwnerType .ROOM ,
122+ reservation .getRoom ().getId ()
123+ )
124+ .stream ()
125+ .map (Image ::getUrl )
126+ .findFirst ()
127+ .orElse (null );
128+
129+ return reservationConverter .toReservationDetailDTO (reservation , firstImageUrl );
100130 }
101131
102132 @ Override
103133 @ Transactional
104134 public void cancelReservation (Long reservationId , Long userId ) {
105135 Reservation reservation = reservationRepository .findById (reservationId )
106- .orElseThrow (() -> new SumteException (ReservationErrorCode .RESERVATION_NOT_FOUND ));
136+ .orElseThrow (() -> new SumteException (ReservationErrorCode .RESERVATION_NOT_FOUND ));
107137
108138 // 사용자 본인 확인
109139 if (!reservation .getUser ().getId ().equals (userId )) {
@@ -129,14 +159,15 @@ public void updateCompletedReservations() {
129159
130160 boolean isAfterCheckout = endDate .isBefore (today ) || (endDate .isEqual (today ) && checkoutTime .isBefore (now ));
131161
132- if (!isAfterCheckout ) continue ;
162+ if (!isAfterCheckout )
163+ continue ;
133164
134165 Optional <Payment > paymentOpt = paymentRepository .findByReservation (reservation );
135166
136167 boolean isPaid = paymentOpt
137- .map (Payment ::getPaymentStatus )
138- .filter (status -> status == PaymentStatus .PAID )
139- .isPresent ();
168+ .map (Payment ::getPaymentStatus )
169+ .filter (status -> status == PaymentStatus .PAID )
170+ .isPresent ();
140171
141172 if (isPaid ) {
142173 reservation .complete ();
0 commit comments