diff --git a/src/main/java/com/example/sabujak/common/dto/ToastType.java b/src/main/java/com/example/sabujak/common/dto/ToastType.java new file mode 100644 index 00000000..65f4453c --- /dev/null +++ b/src/main/java/com/example/sabujak/common/dto/ToastType.java @@ -0,0 +1,6 @@ +package com.example.sabujak.common.dto; + +public enum ToastType { + OVERLAPPING_MEETING_ROOM_EXISTS, + OVERLAPPING_RECHARGING_ROOM_EXISTS +} diff --git a/src/main/java/com/example/sabujak/reservation/controller/ReservationController.java b/src/main/java/com/example/sabujak/reservation/controller/ReservationController.java index 92bbcdb6..14e9507d 100644 --- a/src/main/java/com/example/sabujak/reservation/controller/ReservationController.java +++ b/src/main/java/com/example/sabujak/reservation/controller/ReservationController.java @@ -129,6 +129,33 @@ public ResponseEntity> cancelMeetingRoomReservation(@Authenticati return ResponseEntity.ok(Response.success(null)); } + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "예약 성공", content = @Content(schema = @Schema(implementation = Response.class))), + @ApiResponse(responseCode = "404", description = "예약 실패", content = @Content(schema = @Schema(implementation = Response.class)))}) + @Operation(summary = "리차징룸 예약", description = "리차징룸을 30분동안 예약") + @Parameters({ + @Parameter(name = "access", hidden = true) + }) + @PostMapping("/recharging-rooms") + public ResponseEntity> reserveRechargingRoom(@AuthenticationPrincipal AuthRequestDto.Access access, + @Valid @RequestBody ReservationRequestDto.RechargingRoomDto rechargingRoomDto) { + reservationService.reserveRechargingRoom(access.getEmail(), rechargingRoomDto); + return ResponseEntity.ok(Response.success(null)); + } + + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "검증 성공", content = @Content(schema = @Schema(implementation = Response.class))), + @ApiResponse(responseCode = "404", description = "검증 실패", content = @Content(schema = @Schema(implementation = Response.class)))}) + @Operation(summary = "리차징룸 예약 중복 검증", description = "선택한 시간에 이미 리차징룸이나 미팅룸을 예약 했는지 검증") + @Parameters({ + @Parameter(name = "access", hidden = true) + }) + @GetMapping("/recharging-rooms/check-overlap") + public ResponseEntity> checkRechargingRoomOverlap(@AuthenticationPrincipal AuthRequestDto.Access access, + @RequestParam LocalDateTime startAt) { + return ResponseEntity.ok(Response.success(reservationService.checkRechargingRoomOverlap(access.getEmail(), startAt))); + } + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "예약 성공", content = @Content(schema = @Schema(implementation = Response.class))), @ApiResponse(responseCode = "404", description = "예약 실패", content = @Content(schema = @Schema(implementation = Response.class)))}) @@ -151,9 +178,9 @@ public ResponseEntity> reserveFocusDesk(@AuthenticationPrincipal @Parameter(name = "access", hidden = true) }) @GetMapping("/focus-desks/check-overlap/{focusDeskId}") - public ResponseEntity> checkOverlap(@AuthenticationPrincipal AuthRequestDto.Access access, - @PathVariable Long focusDeskId) { - return ResponseEntity.ok(Response.success(reservationService.checkOverlap(access.getEmail(), focusDeskId))); + public ResponseEntity> checkFocusDeskOverlap(@AuthenticationPrincipal AuthRequestDto.Access access, + @PathVariable Long focusDeskId) { + return ResponseEntity.ok(Response.success(reservationService.checkFocusDeskOverlap(access.getEmail(), focusDeskId))); } @ApiResponses(value = { diff --git a/src/main/java/com/example/sabujak/reservation/dto/request/ReservationRequestDto.java b/src/main/java/com/example/sabujak/reservation/dto/request/ReservationRequestDto.java index f9974e15..8b0f1118 100644 --- a/src/main/java/com/example/sabujak/reservation/dto/request/ReservationRequestDto.java +++ b/src/main/java/com/example/sabujak/reservation/dto/request/ReservationRequestDto.java @@ -5,6 +5,7 @@ import com.example.sabujak.reservation.entity.Reservation; import com.example.sabujak.space.entity.FocusDesk; import com.example.sabujak.space.entity.MeetingRoom; +import com.example.sabujak.space.entity.RechargingRoom; import jakarta.validation.constraints.Future; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; @@ -48,4 +49,21 @@ public Reservation toReservationEntity(FocusDesk focusDesk, LocalDateTime startA return reservation; } } + + public record RechargingRoomDto( + @Positive + Long rechargingRoomId, + + @Future + LocalDateTime startAt) { + + public Reservation toReservationEntity(RechargingRoom rechargingRoom, LocalDateTime startAt, Member member) { + LocalDateTime endAt = startAt.plusMinutes(30); + + Reservation reservation = Reservation.createReservation("리차징룸", startAt, endAt, rechargingRoom); + reservation.addMemberReservation(member, MemberReservationType.REPRESENTATIVE); + + return reservation; + } + } } diff --git a/src/main/java/com/example/sabujak/reservation/dto/response/ReservationResponseDto.java b/src/main/java/com/example/sabujak/reservation/dto/response/ReservationResponseDto.java index d10243b2..dd195572 100644 --- a/src/main/java/com/example/sabujak/reservation/dto/response/ReservationResponseDto.java +++ b/src/main/java/com/example/sabujak/reservation/dto/response/ReservationResponseDto.java @@ -1,5 +1,6 @@ package com.example.sabujak.reservation.dto.response; +import com.example.sabujak.common.dto.ToastType; import com.example.sabujak.member.entity.Member; import lombok.Getter; @@ -10,7 +11,10 @@ public class ReservationResponseDto { - public record CheckOverlap(Boolean alreadyUsing) { + public record CheckFocusDeskOverlap(Boolean alreadyUsing) { + } + + public record CheckRechargingRoomOverlap(ToastType toastType) { } diff --git a/src/main/java/com/example/sabujak/reservation/exception/ReservationErrorCode.java b/src/main/java/com/example/sabujak/reservation/exception/ReservationErrorCode.java index 27928924..653697d5 100644 --- a/src/main/java/com/example/sabujak/reservation/exception/ReservationErrorCode.java +++ b/src/main/java/com/example/sabujak/reservation/exception/ReservationErrorCode.java @@ -18,7 +18,9 @@ public enum ReservationErrorCode implements ErrorCode { NOT_RESERVED_BY_MEMBER(BAD_REQUEST, "9-004", "해당 회원이 예약한 내역이 아닙니다."), RESERVATION_NOT_EXISTS(NOT_FOUND, "9-005", "존재하지 않는 예약입니다"), ALREADY_ENDED_RESERVATION(BAD_REQUEST, "9-006", "이미 종료된 예약입니다."), - ALREADY_CANCELED_RESERVATION(BAD_REQUEST, "9-007", "이미 취소한 예약입니다."); + ALREADY_CANCELED_RESERVATION(BAD_REQUEST, "9-007", "이미 취소한 예약입니다."), + PARTICIPANTS_OVERLAPPING_MEETINGROOM_EXISTS(BAD_REQUEST, "9-008", "참여자의 겹치는 미팅룸 예약이 존재합니다."), + OVERLAPPING_RECHARGING_ROOM_EXISTS(BAD_REQUEST, "9-009", "리차징룸 예약이 겹칩니다."); private final HttpStatus httpStatus; private final String customCode; diff --git a/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryCustom.java b/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryCustom.java index b99a699b..edff0fb2 100644 --- a/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryCustom.java +++ b/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryCustom.java @@ -2,6 +2,7 @@ import com.example.sabujak.member.entity.Member; import com.example.sabujak.reservation.entity.Reservation; +import com.example.sabujak.space.entity.RechargingRoom; import java.time.LocalDateTime; import java.util.List; @@ -16,11 +17,15 @@ public interface ReservationRepositoryCustom { List findOverlappingRechargingRoomReservationInMembers(List members, LocalDateTime startAt, LocalDateTime endAt); - List findTodayFocusDeskReservationOrderByTime(Member member, LocalDateTime startAt); List findReservationsWithDuration(Member member, LocalDateTime now, int durationStart, int durationEnd); List findReservationsToday(Member member, LocalDateTime now); Integer countTodayReservation(Member member, LocalDateTime now); + + List findAllByRechargingRoomListAndStartTimes(List rechargingRooms, LocalDateTime startAt, LocalDateTime endAt); + + boolean existsOverlappingRechargingRoomReservationByStartAt(Member member, LocalDateTime startAt); + boolean existsOverlappingMeetingRoomReservationsByStartAt(Member member, LocalDateTime startAt); } diff --git a/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryImpl.java b/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryImpl.java index 823c4a13..e9f90b0a 100644 --- a/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryImpl.java +++ b/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryImpl.java @@ -3,6 +3,7 @@ import com.example.sabujak.member.entity.Member; import com.example.sabujak.reservation.entity.Reservation; import com.example.sabujak.reservation.entity.ReservationStatus; +import com.example.sabujak.space.entity.RechargingRoom; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -165,4 +166,39 @@ public Integer countTodayReservation(Member member, LocalDateTime now) { reservation.reservationStartDateTime.between(startAt, endAt)) .fetchFirst()); } + + @Override + public List findAllByRechargingRoomListAndStartTimes(List rechargingRooms, LocalDateTime startAt, LocalDateTime endAt) { + return queryFactory.selectFrom(reservation) + .join(reservation.space, space) + .where(space.in(rechargingRooms), + reservation.reservationStartDateTime.between(startAt, endAt)) + .fetch(); + } + + @Override + public boolean existsOverlappingRechargingRoomReservationByStartAt(Member member, LocalDateTime startAt) { + return queryFactory.selectOne() + .from(reservation) + .join(reservation.memberReservations, memberReservation) + .join(reservation.space, space) + .where(memberReservation.member.eq(member), + memberReservation.memberReservationStatus.eq(ReservationStatus.ACCEPTED), + space.dtype.eq("RechargingRoom"), + reservation.reservationStartDateTime.eq(startAt)) + .fetchFirst() != null; + } + + @Override + public boolean existsOverlappingMeetingRoomReservationsByStartAt(Member member, LocalDateTime startAt) { + return queryFactory.selectOne() + .from(reservation) + .join(reservation.memberReservations, memberReservation) + .join(reservation.space, space) + .where(memberReservation.member.eq(member), + memberReservation.memberReservationStatus.eq(ReservationStatus.ACCEPTED), + space.dtype.eq("MeetingRoom"), + reservation.reservationStartDateTime.eq(startAt)) + .fetchFirst() != null; + } } diff --git a/src/main/java/com/example/sabujak/reservation/service/ReservationService.java b/src/main/java/com/example/sabujak/reservation/service/ReservationService.java index 24e64d89..4d40cd37 100644 --- a/src/main/java/com/example/sabujak/reservation/service/ReservationService.java +++ b/src/main/java/com/example/sabujak/reservation/service/ReservationService.java @@ -1,5 +1,6 @@ package com.example.sabujak.reservation.service; +import com.example.sabujak.common.dto.ToastType; import com.example.sabujak.member.entity.Member; import com.example.sabujak.member.repository.MemberRepository; import com.example.sabujak.reservation.dto.FindMeetingRoomEntryNotificationMembersEvent; @@ -17,8 +18,10 @@ import com.example.sabujak.security.exception.AuthException; import com.example.sabujak.space.entity.FocusDesk; import com.example.sabujak.space.entity.MeetingRoom; +import com.example.sabujak.space.entity.RechargingRoom; import com.example.sabujak.space.exception.meetingroom.SpaceException; import com.example.sabujak.space.repository.FocusDeskRepository; +import com.example.sabujak.space.repository.RechargingRoomRepository; import com.example.sabujak.space.repository.meetingroom.MeetingRoomRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -49,6 +52,7 @@ public class ReservationService { private final ReservationRepository reservationRepository; private final MeetingRoomRepository meetingRoomRepository; private final FocusDeskRepository focusDeskRepository; + private final RechargingRoomRepository rechargingRoomRepository; private final MemberReservationRepository memberReservationRepository; private final ApplicationEventPublisher publisher; @@ -88,7 +92,7 @@ public void reserveMeetingRoom(String email, ReservationRequestDto.MeetingRoomDt } //참여자 미팅룸 예약 검증 else if (verifyOverlappingMeetingRoom(participants, meetingRoomDto.startAt(), meetingRoomDto.endAt())) { - throw new ReservationException(REPRESENTATIVE_OVERLAPPING_MEETINGROOM_EXISTS); + throw new ReservationException(PARTICIPANTS_OVERLAPPING_MEETINGROOM_EXISTS); } // 대표자 및 참여자 리차징룸 중복 예약 처리 @@ -213,7 +217,7 @@ public void endUseFocusDesk(String email, Long spaceId) { focusDesk.changeCanReserve(true); } - public ReservationResponseDto.CheckOverlap checkOverlap(String email, Long focusDeskId) { + public ReservationResponseDto.CheckFocusDeskOverlap checkFocusDeskOverlap(String email, Long focusDeskId) { LocalDateTime now = LocalDateTime.now(); @@ -228,7 +232,7 @@ public ReservationResponseDto.CheckOverlap checkOverlap(String email, Long focus // 당일 예약한게 없으면 사용중인 좌석이 없음 if (todayReservations.isEmpty()) { - return new ReservationResponseDto.CheckOverlap(false); + return new ReservationResponseDto.CheckFocusDeskOverlap(false); } // 당일 예약 중 가장 최근 좌석을 찾아서 @@ -237,10 +241,10 @@ public ReservationResponseDto.CheckOverlap checkOverlap(String email, Long focus // 가장 최근 좌석을 종료하지 않았고 해당 좌석이 예약 종료된 상태가 아니면 사용중인 좌석이 있음 if (todayLatestReservation.getReservationEndDateTime().isAfter(now) && !todayLatestFocusDesk.isCanReserve()) { - return new ReservationResponseDto.CheckOverlap(true); + return new ReservationResponseDto.CheckFocusDeskOverlap(true); } - return new ReservationResponseDto.CheckOverlap(false); + return new ReservationResponseDto.CheckFocusDeskOverlap(false); } public ReservationHistoryResponse.TodayReservationCount getTodayReservationCount(String email) { @@ -415,6 +419,53 @@ public void cancelMeetingRoom(String email, Long reservationId) { } } + @Transactional + public void reserveRechargingRoom(String email, ReservationRequestDto.RechargingRoomDto rechargingRoomDto) { + final Member member = memberRepository.findByMemberEmail(email) + .orElseThrow(() -> new AuthException(ACCOUNT_NOT_EXISTS)); + + final RechargingRoom rechargingRoom = rechargingRoomRepository.findById(rechargingRoomDto.rechargingRoomId()) + .orElseThrow(() -> new SpaceException(MEETING_ROOM_NOT_FOUND)); + + //리차징룸 예약 중복 검증 + if (verifyOverlappingRechargingRoom(member, rechargingRoomDto.startAt())) { + throw new ReservationException(OVERLAPPING_RECHARGING_ROOM_EXISTS); + } + + Reservation reservation = rechargingRoomDto.toReservationEntity(rechargingRoom, rechargingRoomDto.startAt(), member); + + reservationRepository.save(reservation); + } + + private boolean verifyOverlappingRechargingRoom(Member member, LocalDateTime startAt) { + if (reservationRepository.existsOverlappingRechargingRoomReservationByStartAt(member, startAt)) { + return true; + } + return false; + } + + public ReservationResponseDto.CheckRechargingRoomOverlap checkRechargingRoomOverlap(String email, LocalDateTime startAt) { + + final Member member = memberRepository.findByMemberEmail(email) + .orElseThrow(() -> new AuthException(ACCOUNT_NOT_EXISTS)); + + + // 해당 회원이 해당 시간에 예약한 미팅룸이 있는지 확인 + if (verifyOverlappingMeetingRoom(member, startAt)) { + return new ReservationResponseDto.CheckRechargingRoomOverlap(ToastType.OVERLAPPING_MEETING_ROOM_EXISTS); + } else if (verifyOverlappingRechargingRoom(member, startAt)) { + return new ReservationResponseDto.CheckRechargingRoomOverlap(ToastType.OVERLAPPING_RECHARGING_ROOM_EXISTS); + } + return null; + } + + private boolean verifyOverlappingMeetingRoom(Member member, LocalDateTime startAt) { + if (reservationRepository.existsOverlappingMeetingRoomReservationsByStartAt(member, startAt)) { + return true; + } + return false; + } + private ReserveMeetingRoomEvent createReserveMeetingRoomEvent(Reservation reservation, MeetingRoom meetingRoom, List participants, List cancelers) { Long reservationId = reservation.getReservationId(); LocalDateTime reservationDate = reservation.getReservationStartDateTime(); diff --git a/src/main/java/com/example/sabujak/space/controller/SpaceController.java b/src/main/java/com/example/sabujak/space/controller/SpaceController.java index c5a3f49c..2456300a 100644 --- a/src/main/java/com/example/sabujak/space/controller/SpaceController.java +++ b/src/main/java/com/example/sabujak/space/controller/SpaceController.java @@ -5,6 +5,7 @@ import com.example.sabujak.space.dto.SpaceCountResponseDto; import com.example.sabujak.space.dto.response.FocusDeskResponseDto; import com.example.sabujak.space.dto.response.MeetingRoomResponseDto; +import com.example.sabujak.space.dto.response.RechargingRoomResponseDto; import com.example.sabujak.space.entity.MeetingRoomType; import com.example.sabujak.space.service.SpaceService; import io.swagger.v3.oas.annotations.Operation; @@ -98,6 +99,19 @@ public ResponseEntity>> getFocusDeskList(@PathVariable Long branchId) { return ResponseEntity.ok(Response.success(spaceService.getFocusDeskList(branchId))); } + + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "조회 성공", content = @Content(schema = @Schema(implementation = Response.class))), + @ApiResponse(responseCode = "404", description = "조회 실패", content = @Content(schema = @Schema(implementation = Response.class)))}) + @Operation(summary = "리차징룸 리스트", description = "리차징룸 리스트를 30분 단위 5개 시간을 예약 가능 불가능을 표시하여 조회") + @Parameters({ + @Parameter(name = "branchId", description = "지점 Id", example = "1") + }) + @GetMapping("/recharging-rooms/{branchId}") + public ResponseEntity>> getRechargingRoomList(@PathVariable Long branchId) { + return ResponseEntity.ok(Response.success(spaceService.getRechargingRoomList(branchId))); + } + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "조회 성공", content = @Content(schema = @Schema(implementation = Response.class))), @ApiResponse(responseCode = "404", description = "조회 실패", content = @Content(schema = @Schema(implementation = Response.class)))}) diff --git a/src/main/java/com/example/sabujak/space/dto/response/MeetingRoomResponseDto.java b/src/main/java/com/example/sabujak/space/dto/response/MeetingRoomResponseDto.java index 9ad8de26..4143488e 100644 --- a/src/main/java/com/example/sabujak/space/dto/response/MeetingRoomResponseDto.java +++ b/src/main/java/com/example/sabujak/space/dto/response/MeetingRoomResponseDto.java @@ -1,6 +1,7 @@ package com.example.sabujak.space.dto.response; import com.example.sabujak.branch.entity.Branch; +import com.example.sabujak.common.dto.ToastType; import com.example.sabujak.space.entity.MeetingRoom; import lombok.AllArgsConstructor; import lombok.Getter; @@ -14,10 +15,6 @@ public class MeetingRoomResponseDto { @Getter public static class MeetingRoomList { - public enum ToastType { - OVERLAPPING_MEETING_ROOM_EXISTS, - OVERLAPPING_RECHARGING_ROOM_EXISTS - } private List meetingRoomForListList = new ArrayList<>(); private ToastType toastType; diff --git a/src/main/java/com/example/sabujak/space/dto/response/RechargingRoomResponseDto.java b/src/main/java/com/example/sabujak/space/dto/response/RechargingRoomResponseDto.java new file mode 100644 index 00000000..4580ce2d --- /dev/null +++ b/src/main/java/com/example/sabujak/space/dto/response/RechargingRoomResponseDto.java @@ -0,0 +1,54 @@ +package com.example.sabujak.space.dto.response; + +import com.example.sabujak.space.entity.RechargingRoom; +import lombok.Getter; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +public class RechargingRoomResponseDto { + + @Getter + public static class RechargingRoomForList { + private Long rechargingRoomId; + private String rechargingRoomName; + private int rechargingRoomFloor; + private List times; + + public static RechargingRoomForList of(RechargingRoom rechargingRoom, Map reservationTimes) { + RechargingRoomForList rechargingRoomForList = new RechargingRoomForList(); + rechargingRoomForList.rechargingRoomId = rechargingRoom.getSpaceId(); + rechargingRoomForList.rechargingRoomName = rechargingRoom.getSpaceName(); + rechargingRoomForList.rechargingRoomFloor = rechargingRoom.getSpaceFloor(); + rechargingRoomForList.times = reservationTimes.entrySet().stream() + .map(entry -> ReservationTimes.of(entry.getKey(), entry.getValue())) + .sorted(Comparator.comparing(ReservationTimes::getStartAt)) + .toList(); + return rechargingRoomForList; + } + + } + + @Getter + public static class ReservationTimes { + private String startAt; + private String endAt; + private boolean canReserve; + + public static ReservationTimes of(String startAt, Boolean canReserve) { + ReservationTimes reservationTimes = new ReservationTimes(); + reservationTimes.startAt = startAt; + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); + LocalTime start = LocalTime.parse(startAt, formatter); + LocalTime endAt = start.plusMinutes(30); + reservationTimes.endAt = endAt.format(formatter); + + reservationTimes.canReserve = canReserve; + return reservationTimes; + } + } +} diff --git a/src/main/java/com/example/sabujak/space/exception/meetingroom/SpaceErrorCode.java b/src/main/java/com/example/sabujak/space/exception/meetingroom/SpaceErrorCode.java index d1b5eef7..cdd4f562 100644 --- a/src/main/java/com/example/sabujak/space/exception/meetingroom/SpaceErrorCode.java +++ b/src/main/java/com/example/sabujak/space/exception/meetingroom/SpaceErrorCode.java @@ -12,7 +12,8 @@ public enum SpaceErrorCode implements ErrorCode { MEETING_ROOM_NOT_FOUND(NOT_FOUND, "8-001", "존재하지 않는 미팅룸입니다"), - FOCUS_DESK_NOT_FOUND(NOT_FOUND, "8-002", "존재하지 않는 포커스 데스크(좌석) 입니다"); + FOCUS_DESK_NOT_FOUND(NOT_FOUND, "8-002", "존재하지 않는 포커스 데스크(좌석) 입니다"), + RECHARGING_ROOM_NOT_FOUND(NOT_FOUND, "8-003", "존재하지 않는 리차징룸 입니다"); private final HttpStatus httpStatus; private final String customCode; diff --git a/src/main/java/com/example/sabujak/space/repository/RechargingRoomRepository.java b/src/main/java/com/example/sabujak/space/repository/RechargingRoomRepository.java new file mode 100644 index 00000000..194063c9 --- /dev/null +++ b/src/main/java/com/example/sabujak/space/repository/RechargingRoomRepository.java @@ -0,0 +1,12 @@ +package com.example.sabujak.space.repository; + +import com.example.sabujak.branch.entity.Branch; +import com.example.sabujak.space.entity.RechargingRoom; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface RechargingRoomRepository extends JpaRepository { + + List findAllByBranch(Branch branch); +} diff --git a/src/main/java/com/example/sabujak/space/service/SpaceService.java b/src/main/java/com/example/sabujak/space/service/SpaceService.java index a912f325..96baa9dd 100644 --- a/src/main/java/com/example/sabujak/space/service/SpaceService.java +++ b/src/main/java/com/example/sabujak/space/service/SpaceService.java @@ -6,23 +6,35 @@ import com.example.sabujak.branch.repository.BranchRepository; import com.example.sabujak.member.entity.Member; import com.example.sabujak.member.repository.MemberRepository; +import com.example.sabujak.reservation.entity.Reservation; import com.example.sabujak.reservation.repository.ReservationRepository; import com.example.sabujak.security.exception.AuthException; import com.example.sabujak.space.dto.SpaceCountResponseDto; import com.example.sabujak.space.dto.response.FocusDeskResponseDto; import com.example.sabujak.space.dto.response.MeetingRoomResponseDto; +import com.example.sabujak.space.dto.response.RechargingRoomResponseDto; +import com.example.sabujak.common.dto.ToastType; import com.example.sabujak.space.entity.MeetingRoom; import com.example.sabujak.space.entity.MeetingRoomType; +import com.example.sabujak.space.entity.RechargingRoom; +import com.example.sabujak.space.entity.Space; import com.example.sabujak.space.exception.meetingroom.SpaceException; import com.example.sabujak.space.repository.FocusDeskRepository; + +import com.example.sabujak.space.repository.RechargingRoomRepository; import com.example.sabujak.space.repository.SpaceRepository; + import com.example.sabujak.space.repository.meetingroom.MeetingRoomRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import static com.example.sabujak.security.exception.AuthErrorCode.ACCOUNT_NOT_EXISTS; @@ -34,6 +46,7 @@ public class SpaceService { private final MeetingRoomRepository meetingRoomRepository; private final FocusDeskRepository focusDeskRepository; + private final RechargingRoomRepository rechargingRoomRepository; private final BranchRepository branchRepository; private final MemberRepository memberRepository; private final ReservationRepository reservationRepository; @@ -45,12 +58,12 @@ public MeetingRoomResponseDto.MeetingRoomList getMeetingRoomList(String email, L final Member member = memberRepository.findByMemberEmail(email) .orElseThrow(() -> new AuthException(ACCOUNT_NOT_EXISTS)); - MeetingRoomResponseDto.MeetingRoomList.ToastType toastType = null; + ToastType toastType = null; if (verifyOverlappingMeetingRoom(member, startAt, endAt)) { - toastType = MeetingRoomResponseDto.MeetingRoomList.ToastType.OVERLAPPING_MEETING_ROOM_EXISTS; + toastType = ToastType.OVERLAPPING_MEETING_ROOM_EXISTS; } else if (verifyOverlappingRechargingRoom(member, startAt, endAt)) { - toastType = MeetingRoomResponseDto.MeetingRoomList.ToastType.OVERLAPPING_RECHARGING_ROOM_EXISTS; + toastType = ToastType.OVERLAPPING_RECHARGING_ROOM_EXISTS; } return new MeetingRoomResponseDto.MeetingRoomList( @@ -69,7 +82,7 @@ private boolean verifyOverlappingMeetingRoom(Member member, LocalDateTime startA } private boolean verifyOverlappingRechargingRoom(Member member, LocalDateTime startAt, LocalDateTime endAt) { - if (reservationRepository.existsOverlappingRechargingRoomReservation(member, startAt, endAt)) { + if (reservationRepository.existsOverlappingRechargingRoomReservationByStartAt(member, startAt, endAt)) { return true; } return false; @@ -101,7 +114,47 @@ public List getFocusDeskList(Long branchI .map(FocusDeskResponseDto.FocusDeskForList::from) .collect(Collectors.toList()); } - public SpaceCountResponseDto countRoomByBranch(Long branchId){ + + public List getRechargingRoomList(Long branchId) { + List rechargingRoomList = new ArrayList<>(); + + LocalDateTime now = LocalDateTime.now(); + int minutes = now.getMinute(); + if (minutes < 30) { + now = now.withMinute(30).withSecond(0).withNano(0); + } else { + now = now.withMinute(0).withSecond(0).withNano(0).plusHours(1); + } + + Branch branch = branchRepository.findById(branchId) + .orElseThrow(() -> new BranchException(BranchErrorCode.BRANCH_NOT_FOUND)); + + List rechargingRooms = rechargingRoomRepository.findAllByBranch(branch); + List reservations = reservationRepository.findAllByRechargingRoomListAndStartTimes(rechargingRooms, now, now.plusHours(2)); + Map> reservationMap = reservations.stream() + .collect(Collectors.groupingBy(Reservation::getSpace)); + + for (RechargingRoom rechargingRoom : rechargingRooms) { + Map reservationTimes = new HashMap<>(); + for (int i = 0; i < 5; i++) { + String startTime = now.plusMinutes(30 * i).format(DateTimeFormatter.ofPattern("HH:mm")); + String endTime = now.plusMinutes(30 * (i + 1)).format(DateTimeFormatter.ofPattern("HH:mm")); + + reservationTimes.put(startTime, true); + } + + if (reservationMap.size() > 0) { + for (Reservation reservation : reservationMap.get(rechargingRoom)) { + reservationTimes.put(reservation.getReservationStartDateTime().format(DateTimeFormatter.ofPattern("HH:mm")), false); + } + } + + rechargingRoomList.add(RechargingRoomResponseDto.RechargingRoomForList.of(rechargingRoom, reservationTimes)); + } + return rechargingRoomList; + } + + public SpaceCountResponseDto countRoomByBranch(Long branchId) { Branch branch = branchRepository.findById(branchId) .orElseThrow(() -> new BranchException(BranchErrorCode.BRANCH_NOT_FOUND)); int miniCount = meetingRoomRepository.countAllByBranchAndMeetingRoomType(branch, MeetingRoomType.MINI);