From 1f130d40f6583c2e84042ea72b747fa557f1ab85 Mon Sep 17 00:00:00 2001 From: zoomin3022 Date: Sat, 8 Jun 2024 18:14:27 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor:=20=EB=AF=B8=ED=8C=85=EB=A3=B8=20?= =?UTF-8?q?=EC=98=88=EC=95=BD=20=EC=98=88=EC=99=B8=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=A2=80=20=EB=8D=94=20=EC=84=B8=EB=B6=84=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sabujak/reservation/exception/ReservationErrorCode.java | 3 ++- .../sabujak/reservation/service/ReservationService.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) 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 2792892..c0dddb1 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,8 @@ 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", "참여자의 겹치는 미팅룸 예약이 존재합니다."); private final HttpStatus httpStatus; private final String customCode; 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 4213479..2639dac 100644 --- a/src/main/java/com/example/sabujak/reservation/service/ReservationService.java +++ b/src/main/java/com/example/sabujak/reservation/service/ReservationService.java @@ -87,7 +87,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); } // 대표자 및 참여자 리차징룸 중복 예약 처리 From 6103d609db66d427147ef8bd78a621bec991b64f Mon Sep 17 00:00:00 2001 From: zoomin3022 Date: Sat, 8 Jun 2024 18:30:41 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20#105=20GET=20/recharging-room/{bran?= =?UTF-8?q?dId}=20=EB=A6=AC=EC=B0=A8=EC=A7=95=EB=A3=B8=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReservationRepositoryCustom.java | 4 +- .../repository/ReservationRepositoryImpl.java | 10 ++++ .../space/controller/SpaceController.java | 13 +++++ .../response/RechargingRoomResponseDto.java | 54 +++++++++++++++++++ .../repository/RechargingRoomRepository.java | 12 +++++ .../sabujak/space/service/SpaceService.java | 49 +++++++++++++++++ 6 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/sabujak/space/dto/response/RechargingRoomResponseDto.java create mode 100644 src/main/java/com/example/sabujak/space/repository/RechargingRoomRepository.java 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 b99a699..8700466 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,12 @@ 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); } 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 823c4a1..b3f25e6 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,13 @@ 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(); + } } 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 109c414..42112c1 100644 --- a/src/main/java/com/example/sabujak/space/controller/SpaceController.java +++ b/src/main/java/com/example/sabujak/space/controller/SpaceController.java @@ -4,6 +4,7 @@ import com.example.sabujak.security.dto.request.AuthRequestDto; 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; @@ -97,4 +98,16 @@ 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-room/{branchId}") + public ResponseEntity>> getRechargingRoomList(@PathVariable Long branchId) { + return ResponseEntity.ok(Response.success(spaceService.getRechargingRoomList(branchId))); + } } 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 0000000..4580ce2 --- /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/repository/RechargingRoomRepository.java b/src/main/java/com/example/sabujak/space/repository/RechargingRoomRepository.java new file mode 100644 index 0000000..194063c --- /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 dcc2102..8f30766 100644 --- a/src/main/java/com/example/sabujak/space/service/SpaceService.java +++ b/src/main/java/com/example/sabujak/space/service/SpaceService.java @@ -6,21 +6,30 @@ 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.response.FocusDeskResponseDto; import com.example.sabujak.space.dto.response.MeetingRoomResponseDto; +import com.example.sabujak.space.dto.response.RechargingRoomResponseDto; 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.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; @@ -32,6 +41,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; @@ -98,4 +108,43 @@ public List getFocusDeskList(Long branchI .map(FocusDeskResponseDto.FocusDeskForList::from) .collect(Collectors.toList()); } + + 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; + } } From a1dcf61055010bbd2639c78462e420989d1ca3cd Mon Sep 17 00:00:00 2001 From: zoomin3022 Date: Sat, 8 Jun 2024 19:11:45 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20#105=20POST=20/recharging-rooms=20?= =?UTF-8?q?=EB=A6=AC=EC=B0=A8=EC=A7=95=EB=A3=B8=20=EC=98=88=EC=95=BD=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReservationController.java | 14 ++++++++++ .../dto/request/ReservationRequestDto.java | 18 ++++++++++++ .../exception/ReservationErrorCode.java | 3 +- .../ReservationRepositoryCustom.java | 1 + .../repository/ReservationRepositoryImpl.java | 13 +++++++++ .../service/ReservationService.java | 28 +++++++++++++++++++ .../exception/meetingroom/SpaceErrorCode.java | 3 +- 7 files changed, 78 insertions(+), 2 deletions(-) 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 92bbcdb..cf53a13 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,20 @@ 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)))}) 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 f9974e1..8b0f111 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/exception/ReservationErrorCode.java b/src/main/java/com/example/sabujak/reservation/exception/ReservationErrorCode.java index c0dddb1..653697d 100644 --- a/src/main/java/com/example/sabujak/reservation/exception/ReservationErrorCode.java +++ b/src/main/java/com/example/sabujak/reservation/exception/ReservationErrorCode.java @@ -19,7 +19,8 @@ public enum ReservationErrorCode implements ErrorCode { RESERVATION_NOT_EXISTS(NOT_FOUND, "9-005", "존재하지 않는 예약입니다"), ALREADY_ENDED_RESERVATION(BAD_REQUEST, "9-006", "이미 종료된 예약입니다."), ALREADY_CANCELED_RESERVATION(BAD_REQUEST, "9-007", "이미 취소한 예약입니다."), - PARTICIPANTS_OVERLAPPING_MEETINGROOM_EXISTS(BAD_REQUEST, "9-008", "참여자의 겹치는 미팅룸 예약이 존재합니다."); + 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 8700466..a3ca99e 100644 --- a/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryCustom.java +++ b/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryCustom.java @@ -13,6 +13,7 @@ public interface ReservationRepositoryCustom { boolean existsOverlappingMeetingRoomReservationInMembers(List members, LocalDateTime startAt, LocalDateTime endAt); boolean existsOverlappingRechargingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt); + boolean existsOverlappingRechargingRoomReservation(Member member, LocalDateTime startAt); List findOverlappingRechargingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt); List findOverlappingRechargingRoomReservationInMembers(List members, LocalDateTime startAt, LocalDateTime endAt); 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 b3f25e6..47a7f99 100644 --- a/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryImpl.java +++ b/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryImpl.java @@ -62,6 +62,19 @@ public boolean existsOverlappingRechargingRoomReservation(Member member, LocalDa .fetchFirst() != null; } + @Override + public boolean existsOverlappingRechargingRoomReservation(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 List findOverlappingRechargingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt) { return queryFactory.selectFrom(reservation) 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 2639dac..72a9910 100644 --- a/src/main/java/com/example/sabujak/reservation/service/ReservationService.java +++ b/src/main/java/com/example/sabujak/reservation/service/ReservationService.java @@ -17,8 +17,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; @@ -48,6 +50,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; @@ -414,6 +417,31 @@ 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.existsOverlappingRechargingRoomReservation(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/exception/meetingroom/SpaceErrorCode.java b/src/main/java/com/example/sabujak/space/exception/meetingroom/SpaceErrorCode.java index d1b5eef..cdd4f56 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; From e285d3be95e8495fbcd3190470b82a70e4d11f91 Mon Sep 17 00:00:00 2001 From: zoomin3022 Date: Sat, 8 Jun 2024 19:44:11 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=20#105=20ToastType=20Common=20Dto?= =?UTF-8?q?=20=EB=A1=9C=20=EB=B9=BC=EB=83=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/sabujak/common/dto/ToastType.java | 6 ++++++ .../space/dto/response/MeetingRoomResponseDto.java | 5 +---- .../com/example/sabujak/space/service/SpaceService.java | 9 +++++---- 3 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/example/sabujak/common/dto/ToastType.java 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 0000000..65f4453 --- /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/space/dto/response/MeetingRoomResponseDto.java b/src/main/java/com/example/sabujak/space/dto/response/MeetingRoomResponseDto.java index 9ad8de2..4143488 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/service/SpaceService.java b/src/main/java/com/example/sabujak/space/service/SpaceService.java index 8f30766..4985c9e 100644 --- a/src/main/java/com/example/sabujak/space/service/SpaceService.java +++ b/src/main/java/com/example/sabujak/space/service/SpaceService.java @@ -12,6 +12,7 @@ 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; @@ -52,12 +53,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( @@ -76,7 +77,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; From c1e845d35e37908dab9f1a57c30d1dde953eaaca Mon Sep 17 00:00:00 2001 From: zoomin3022 Date: Sat, 8 Jun 2024 19:44:52 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=20#105=20=EB=A6=AC=EC=B0=A8?= =?UTF-8?q?=EC=A7=95=EB=A3=B8=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20API=20url=20?= =?UTF-8?q?=EB=8B=A8=EC=88=98=20->=20=EB=B3=B5=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/sabujak/space/controller/SpaceController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 42112c1..22c726f 100644 --- a/src/main/java/com/example/sabujak/space/controller/SpaceController.java +++ b/src/main/java/com/example/sabujak/space/controller/SpaceController.java @@ -106,7 +106,7 @@ public ResponseEntity>> get @Parameters({ @Parameter(name = "branchId", description = "지점 Id", example = "1") }) - @GetMapping("/recharging-room/{branchId}") + @GetMapping("/recharging-rooms/{branchId}") public ResponseEntity>> getRechargingRoomList(@PathVariable Long branchId) { return ResponseEntity.ok(Response.success(spaceService.getRechargingRoomList(branchId))); } From b825d1064e5aa2ec7b39847aff44545fbcc57b99 Mon Sep 17 00:00:00 2001 From: zoomin3022 Date: Sat, 8 Jun 2024 19:47:45 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20#105=20GET=20/recharging-rooms/chec?= =?UTF-8?q?k-overlap=20=EB=A6=AC=EC=B0=A8=EC=A7=95=EB=A3=B8=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EA=B2=80=EC=A6=9D=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReservationController.java | 13 +++++++ .../dto/response/ReservationResponseDto.java | 4 ++ .../ReservationRepositoryCustom.java | 4 +- .../repository/ReservationRepositoryImpl.java | 39 ++++++++++++------- .../service/ReservationService.java | 25 +++++++++++- 5 files changed, 70 insertions(+), 15 deletions(-) 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 cf53a13..bf7c597 100644 --- a/src/main/java/com/example/sabujak/reservation/controller/ReservationController.java +++ b/src/main/java/com/example/sabujak/reservation/controller/ReservationController.java @@ -143,6 +143,19 @@ public ResponseEntity> reserveRechargingRoom(@AuthenticationPrinc 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)))}) 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 d10243b..d7d154e 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; @@ -13,6 +14,9 @@ public class ReservationResponseDto { public record CheckOverlap(Boolean alreadyUsing) { } + public record CheckRechargingRoomOverlap(ToastType toastType) { + } + @Getter public static class FindMemberList { 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 a3ca99e..edff0fb 100644 --- a/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryCustom.java +++ b/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryCustom.java @@ -13,7 +13,6 @@ public interface ReservationRepositoryCustom { boolean existsOverlappingMeetingRoomReservationInMembers(List members, LocalDateTime startAt, LocalDateTime endAt); boolean existsOverlappingRechargingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt); - boolean existsOverlappingRechargingRoomReservation(Member member, LocalDateTime startAt); List findOverlappingRechargingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt); List findOverlappingRechargingRoomReservationInMembers(List members, LocalDateTime startAt, LocalDateTime endAt); @@ -26,4 +25,7 @@ public interface ReservationRepositoryCustom { 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 47a7f99..e9f90b0 100644 --- a/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryImpl.java +++ b/src/main/java/com/example/sabujak/reservation/repository/ReservationRepositoryImpl.java @@ -62,19 +62,6 @@ public boolean existsOverlappingRechargingRoomReservation(Member member, LocalDa .fetchFirst() != null; } - @Override - public boolean existsOverlappingRechargingRoomReservation(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 List findOverlappingRechargingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt) { return queryFactory.selectFrom(reservation) @@ -188,4 +175,30 @@ public List findAllByRechargingRoomListAndStartTimes(List 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; From 525245c64c678c20c143f44258e1f2138756ca28 Mon Sep 17 00:00:00 2001 From: zoomin3022 Date: Sat, 8 Jun 2024 19:49:48 +0900 Subject: [PATCH 7/7] =?UTF-8?q?style:=20#105=20=ED=8F=AC=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=EC=A1=B4=20=EA=B2=80=EC=A6=9D=20=EA=B4=80=EB=A0=A8=20=EB=AA=85?= =?UTF-8?q?=ED=99=95=ED=95=98=EA=B2=8C=20rename?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/controller/ReservationController.java | 6 +++--- .../reservation/dto/response/ReservationResponseDto.java | 2 +- .../sabujak/reservation/service/ReservationService.java | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) 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 bf7c597..14e9507 100644 --- a/src/main/java/com/example/sabujak/reservation/controller/ReservationController.java +++ b/src/main/java/com/example/sabujak/reservation/controller/ReservationController.java @@ -178,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/response/ReservationResponseDto.java b/src/main/java/com/example/sabujak/reservation/dto/response/ReservationResponseDto.java index d7d154e..dd19557 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 @@ -11,7 +11,7 @@ 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/service/ReservationService.java b/src/main/java/com/example/sabujak/reservation/service/ReservationService.java index 0e43da2..6d0cc03 100644 --- a/src/main/java/com/example/sabujak/reservation/service/ReservationService.java +++ b/src/main/java/com/example/sabujak/reservation/service/ReservationService.java @@ -216,7 +216,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(); @@ -231,7 +231,7 @@ public ReservationResponseDto.CheckOverlap checkOverlap(String email, Long focus // 당일 예약한게 없으면 사용중인 좌석이 없음 if (todayReservations.isEmpty()) { - return new ReservationResponseDto.CheckOverlap(false); + return new ReservationResponseDto.CheckFocusDeskOverlap(false); } // 당일 예약 중 가장 최근 좌석을 찾아서 @@ -240,10 +240,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) {