diff --git a/src/main/java/com/kernellabs/kernellabs/application/PlaceService.java b/src/main/java/com/kernellabs/kernellabs/application/PlaceService.java index 936515a..d75ce64 100644 --- a/src/main/java/com/kernellabs/kernellabs/application/PlaceService.java +++ b/src/main/java/com/kernellabs/kernellabs/application/PlaceService.java @@ -1,12 +1,19 @@ package com.kernellabs.kernellabs.application; import com.kernellabs.kernellabs.domain.Place; +import com.kernellabs.kernellabs.domain.Reservation; import com.kernellabs.kernellabs.global.exception.CustomException; import com.kernellabs.kernellabs.global.exception.ErrorCode; import com.kernellabs.kernellabs.infrastructure.repository.PlaceRepository; +import com.kernellabs.kernellabs.infrastructure.repository.ReservationRepository; +import com.kernellabs.kernellabs.presentation.dto.response.PlaceDetailResponse; import com.kernellabs.kernellabs.presentation.dto.response.PlaceListResponse; -import com.kernellabs.kernellabs.presentation.dto.response.PlaceViewResponse; +import com.kernellabs.kernellabs.presentation.dto.response.TimeSlotResponse; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -18,6 +25,7 @@ public class PlaceService { private final PlaceRepository placeRepository; + private final ReservationRepository reservationRepository; public List getAllPlace() { return placeRepository.findAll().stream() @@ -25,10 +33,48 @@ public List getAllPlace() { .collect(Collectors.toList()); } - public PlaceViewResponse getPlaceDetail(Long placeId) { + public PlaceDetailResponse getPlaceDetailWithDate(Long placeId, LocalDate date) { + // 1. 장소 정보 조회 Place place = placeRepository.findById(placeId) .orElseThrow(() -> new CustomException(ErrorCode.PLACE_NOT_FOUND)); - return PlaceViewResponse.from(place); + // 2. 해당 날짜 실제 운영 시간 확인 + LocalTime openTime = place.getOpenTime(); + LocalTime closeTime = place.getCloseTime(); + + // 3. 해당 날짜에 이미 예약된 시간 목록 조회 + List reservations = reservationRepository.findByPlaceIdAndReservationDate(placeId, date); + Set reservedSlots = getReservedSlots(reservations); + + // 4. 전체 시간 슬롯 생성 및 예약 가능 여부 판단 + List timeSlots = generateTimeSlots(openTime, closeTime, reservedSlots); + + // 5. 최종 응답 DTO 생성 및 반환 + return PlaceDetailResponse.of(place, timeSlots); + } + + private List generateTimeSlots(LocalTime openTime, LocalTime closeTime, Set reservedSlots) { + List slots = new ArrayList<>(); + LocalTime currentTime = openTime; + while (!currentTime.isAfter(closeTime.minusHours(1))) { + boolean isAvailable = !reservedSlots.contains(currentTime); + slots.add(new TimeSlotResponse(currentTime.toString(), isAvailable)); + currentTime = currentTime.plusHours(1); + } + return slots; + } + + private Set getReservedSlots(List reservations) { + return reservations.stream() + .flatMap(reservation -> { + List slots = new ArrayList<>(); + LocalTime current = reservation.getStartTime(); + while (current.isBefore(reservation.getEndTime())) { + slots.add(current); + current = current.plusHours(1); + } + return slots.stream(); + }) + .collect(Collectors.toSet()); } } diff --git a/src/main/java/com/kernellabs/kernellabs/infrastructure/repository/ReservationRepository.java b/src/main/java/com/kernellabs/kernellabs/infrastructure/repository/ReservationRepository.java index 7606690..a1fba65 100644 --- a/src/main/java/com/kernellabs/kernellabs/infrastructure/repository/ReservationRepository.java +++ b/src/main/java/com/kernellabs/kernellabs/infrastructure/repository/ReservationRepository.java @@ -27,4 +27,6 @@ boolean existsByPlaceIdAndReservationDateAndIdNotAndStartTimeBeforeAndEndTimeAft LocalTime endTime, LocalTime startTime ); + + List findByPlaceIdAndReservationDate(Long placeId, LocalDate date); } diff --git a/src/main/java/com/kernellabs/kernellabs/presentation/controller/PlaceController.java b/src/main/java/com/kernellabs/kernellabs/presentation/controller/PlaceController.java index e25fcc3..b83475b 100644 --- a/src/main/java/com/kernellabs/kernellabs/presentation/controller/PlaceController.java +++ b/src/main/java/com/kernellabs/kernellabs/presentation/controller/PlaceController.java @@ -2,14 +2,18 @@ import com.kernellabs.kernellabs.application.PlaceService; import com.kernellabs.kernellabs.global.common.ApiResponse; +import com.kernellabs.kernellabs.presentation.dto.response.PlaceDetailResponse; import com.kernellabs.kernellabs.presentation.dto.response.PlaceListResponse; -import com.kernellabs.kernellabs.presentation.dto.response.PlaceViewResponse; +import java.time.LocalDate; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.format.annotation.DateTimeFormat.ISO; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -26,8 +30,12 @@ public ResponseEntity getAllPlaces() { } @GetMapping("/{placeId}") - public ResponseEntity> getPlace(@PathVariable Long placeId) { - PlaceViewResponse response = placeService.getPlaceDetail(placeId); + public ResponseEntity> getPlace(@PathVariable Long placeId, + @RequestParam(required = false) @DateTimeFormat(iso = ISO.DATE) LocalDate date) { + // 날짜 파라미터가 없으면 오늘 날짜 기본값 + LocalDate targetDate = (date == null) ? LocalDate.now() : date; + + PlaceDetailResponse response = placeService.getPlaceDetailWithDate(placeId, targetDate); return ResponseEntity.ok(ApiResponse.success(response)); } } diff --git a/src/main/java/com/kernellabs/kernellabs/presentation/dto/response/PlaceViewResponse.java b/src/main/java/com/kernellabs/kernellabs/presentation/dto/response/PlaceDetailResponse.java similarity index 51% rename from src/main/java/com/kernellabs/kernellabs/presentation/dto/response/PlaceViewResponse.java rename to src/main/java/com/kernellabs/kernellabs/presentation/dto/response/PlaceDetailResponse.java index c8d04e5..2000b00 100644 --- a/src/main/java/com/kernellabs/kernellabs/presentation/dto/response/PlaceViewResponse.java +++ b/src/main/java/com/kernellabs/kernellabs/presentation/dto/response/PlaceDetailResponse.java @@ -2,33 +2,34 @@ import com.kernellabs.kernellabs.domain.Place; import java.time.LocalTime; +import java.util.List; import lombok.Builder; import lombok.Getter; @Getter @Builder -public class PlaceViewResponse { +public class PlaceDetailResponse { + private Long id; + private String name; + private String address; + private String thumbnailUrl; + private String description; + private LocalTime openTime; + private LocalTime closeTime; + private Integer unitPrice; + private List timeSlots; // 시간표 정보 - private final Long id; - private final String thumbnailUrl; - private final String name; - private final String address; - private final LocalTime openTime; - private final LocalTime closeTime; - private final Integer unitPrice; - private final String description; - - public static PlaceViewResponse from(Place place) { - return PlaceViewResponse.builder() + public static PlaceDetailResponse of(Place place, List timeSlots) { + return PlaceDetailResponse.builder() .id(place.getId()) - .thumbnailUrl(place.getThumbnailUrl()) .name(place.getName()) .address(place.getAddress()) + .thumbnailUrl(place.getThumbnailUrl()) + .description(place.getDescription()) .openTime(place.getOpenTime()) .closeTime(place.getCloseTime()) .unitPrice(place.getUnitPrice()) - .description(place.getDescription()) + .timeSlots(timeSlots) .build(); } - } diff --git a/src/main/java/com/kernellabs/kernellabs/presentation/dto/response/TimeSlotResponse.java b/src/main/java/com/kernellabs/kernellabs/presentation/dto/response/TimeSlotResponse.java new file mode 100644 index 0000000..764ac2f --- /dev/null +++ b/src/main/java/com/kernellabs/kernellabs/presentation/dto/response/TimeSlotResponse.java @@ -0,0 +1,13 @@ +package com.kernellabs.kernellabs.presentation.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class TimeSlotResponse { + + private String time; + private boolean isAvailable; + +}