Skip to content

Commit

Permalink
Merge pull request #80 from 4bujak-4bujak/feature/reservation
Browse files Browse the repository at this point in the history
feat: 일정(예약) 내역 조회 관련 기능 구현
  • Loading branch information
zoomin3022 authored Jun 5, 2024
2 parents cef6b16 + b961ce4 commit a93bd97
Show file tree
Hide file tree
Showing 10 changed files with 317 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.sabujak.common.response.Response;
import com.example.sabujak.reservation.dto.request.ReservationRequestDto;
import com.example.sabujak.reservation.dto.response.ReservationHistoryResponse;
import com.example.sabujak.reservation.dto.response.ReservationResponseDto;
import com.example.sabujak.reservation.service.ReservationService;
import com.example.sabujak.security.dto.request.AuthRequestDto;
Expand All @@ -19,6 +20,8 @@
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Tag(name = "reservations", description = "예약 관련 API")
@RestController
@RequiredArgsConstructor
Expand All @@ -27,7 +30,45 @@ public class ReservationController {

private final ReservationService reservationService;

// @ApiResponses(value = {

@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("/today")
public ResponseEntity<Response<List<ReservationHistoryResponse.ReservationForList>>> getTodayReservations(@AuthenticationPrincipal AuthRequestDto.Access access) {
return ResponseEntity.ok(Response.success(reservationService.getReservations(access.getEmail(), 0, 0)));
}

@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 = "오늘 n개의 예약 기능 에서 n 반환")
@Parameters({
@Parameter(name = "access", hidden = true)
})
@GetMapping("/today/count")
public ResponseEntity<Response<ReservationHistoryResponse.TodayReservationCount>> getTodayReservationCount(@AuthenticationPrincipal AuthRequestDto.Access access) {
return ResponseEntity.ok(Response.success(reservationService.getTodayReservationCount(access.getEmail())));
}

@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 = "30일 내 예약 내역 리스트 조회", description = "시작날짜가 오늘부터 최대 30일 이내 모든 예약 내역 리스트 조회")
@Parameters({
@Parameter(name = "access", hidden = true)
})
@GetMapping
public ResponseEntity<Response<List<ReservationHistoryResponse.ReservationForList>>> getReservations(@AuthenticationPrincipal AuthRequestDto.Access access) {
return ResponseEntity.ok(Response.success(reservationService.getReservations(access.getEmail(), 1, 30)));
}


// @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 = "예약 과정에서 같은 회사에 다니고 특정 검증을 거쳐 참석자로 초대될 수 있는 사람 조회")
Expand All @@ -43,19 +84,19 @@ public class ReservationController {
// return ResponseEntity.ok(Response.success(reservationService.findMembers(access.getEmail(), searchTerm)));
// }
//
// @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)
// })
// @PostMapping("/meeting-rooms")
// public ResponseEntity<Response<Void>> reserveMeetingRoom(@AuthenticationPrincipal AuthRequestDto.Access access,
// @Valid @RequestBody ReservationRequestDto.MeetingRoomDto meetingRoomDto) {
// reservationService.reserveMeetingRoom(access.getEmail(), meetingRoomDto);
// 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)
})
@PostMapping("/meeting-rooms")
public ResponseEntity<Response<Void>> reserveMeetingRoom(@AuthenticationPrincipal AuthRequestDto.Access access,
@Valid @RequestBody ReservationRequestDto.MeetingRoomDto meetingRoomDto) {
reservationService.reserveMeetingRoom(access.getEmail(), meetingRoomDto);
return ResponseEntity.ok(Response.success(null));
}

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "예약 성공", content = @Content(schema = @Schema(implementation = Response.class))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,36 @@
import com.example.sabujak.reservation.entity.MemberReservationType;
import com.example.sabujak.reservation.entity.Reservation;
import com.example.sabujak.space.entity.FocusDesk;
import com.example.sabujak.space.entity.MeetingRoom;
import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;

public class ReservationRequestDto {

// public record MeetingRoomDto(
// @Positive
// Long meetingRoomId,
// @Future
// LocalDateTime startAt,
// @Future
// LocalDateTime endAt,
// List<Long> memberIds) {
//
// public Reservation toReservationEntity(MeetingRoom meetingRoom, LocalDateTime startAt, LocalDateTime endAt,
// Member representative, List<Member> participants) {
// Reservation reservation = Reservation.createReservation(startAt, endAt, meetingRoom);
// reservation.addMemberReservation(representative, MemberReservationType.REPRESENTATIVE);
// participants.forEach(member -> reservation.addMemberReservation(member, MemberReservationType.PARTICIPANT));
//
// return reservation;
// }
// }
public record MeetingRoomDto(
@NotNull
String reservationName,
@Positive
Long meetingRoomId,
@Future
LocalDateTime startAt,
@Future
LocalDateTime endAt,
List<Long> memberIds) {

public Reservation toReservationEntity(MeetingRoom meetingRoom, Member representative, List<Member> participants) {
Reservation reservation = Reservation.createReservation(reservationName, startAt, endAt, meetingRoom);
reservation.addMemberReservation(representative, MemberReservationType.REPRESENTATIVE);
participants.forEach(member -> reservation.addMemberReservation(member, MemberReservationType.PARTICIPANT));

return reservation;
}
}

public record FocusDeskDto(
@Positive
Expand All @@ -37,7 +42,7 @@ public record FocusDeskDto(
public Reservation toReservationEntity(FocusDesk focusDesk, LocalDateTime startAt, Member member) {
LocalDateTime endAt = startAt.plusDays(1).with(LocalTime.MIDNIGHT);

Reservation reservation = Reservation.createReservation(startAt, endAt, focusDesk);
Reservation reservation = Reservation.createReservation("포커스존", startAt, endAt, focusDesk);
reservation.addMemberReservation(member, MemberReservationType.REPRESENTATIVE);

return reservation;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.example.sabujak.reservation.dto.response;

import com.example.sabujak.member.entity.Member;
import com.example.sabujak.reservation.entity.MemberReservationType;
import com.example.sabujak.reservation.entity.Reservation;
import com.example.sabujak.space.dto.SpaceType;
import com.example.sabujak.space.entity.FocusDesk;
import com.example.sabujak.space.entity.Space;
import lombok.Getter;

import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

public class ReservationHistoryResponse {

public record TodayReservationCount(Integer count) {
}

@Getter
public static class ReservationForList {
private Long reservationId;
private String reservationName;
private String branchName;
private String spaceName;
private String startAt;
private String endAt;
private SpaceType spaceType;
private List<String> memberImageUrls;
private MemberReservationType memberType;

public static ReservationForList of(Reservation reservation, Space space, List<Member> members, MemberReservationType memberType) {
ReservationForList reservationForList = new ReservationForList();
reservationForList.reservationId = reservation.getReservationId();
reservationForList.reservationName = reservation.getReservationName();
reservationForList.branchName = space.getBranch().getBranchName();

reservationForList.spaceName = space.getSpaceName();
if(space instanceof FocusDesk){
reservationForList.spaceName += " " + ((FocusDesk) space).getFocusDeskNumber();
}

reservationForList.startAt = reservation.getReservationStartDateTime().format(DateTimeFormatter.ofPattern("HH:mm"));
reservationForList.endAt = reservation.getReservationEndDateTime().format(DateTimeFormatter.ofPattern("HH:mm"));

String spaceType = space.getDtype().toUpperCase();
reservationForList.spaceType = SpaceType.valueOf(spaceType);

reservationForList.memberImageUrls = members.stream()
.map(member -> member.getImage().getImageUrl())
.collect(Collectors.toList());

reservationForList.memberType = memberType;

return reservationForList;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.example.sabujak.member.entity.Member;
import com.example.sabujak.space.entity.Space;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand Down Expand Up @@ -31,12 +32,17 @@ public class Reservation extends BaseEntity {
@OneToMany(mappedBy = "reservation", cascade = CascadeType.ALL)
private List<MemberReservation> memberReservations = new ArrayList<>();

@Column(name = "reservation_name")
@NotNull
private String reservationName;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "space_id")
private Space space;

public static Reservation createReservation(LocalDateTime reservationStartDateTime, LocalDateTime reservationEndDateTime, Space space) {
public static Reservation createReservation(String reservationName, LocalDateTime reservationStartDateTime, LocalDateTime reservationEndDateTime, Space space) {
Reservation reservation = new Reservation();
reservation.reservationName = reservationName;
reservation.reservationStartDateTime = reservationStartDateTime;
reservation.reservationEndDateTime = reservationEndDateTime;
reservation.space = space;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.sabujak.reservation.repository;

import com.example.sabujak.reservation.entity.MemberReservation;
import com.example.sabujak.reservation.entity.Reservation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface MemberReservationRepository extends JpaRepository<MemberReservation, Long> {

@Query("select mr from MemberReservation mr join fetch mr.member m join fetch m.image where mr.reservation in :reservations")
List<MemberReservation> findMemberReservationsByReservations(List<Reservation> reservations);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@

public interface ReservationRepositoryCustom {

// boolean existsOverlappingMeetingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt);
boolean existsOverlappingMeetingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt);

List<Reservation> findTodayReservationOrderByTime(Member member, LocalDateTime startAt);
List<Reservation> findTodayFocusDeskReservationOrderByTime(Member member, LocalDateTime startAt);

List<Reservation> findReservationsWithDuration(Member member, LocalDateTime now, int durationStart, int durationEnd);
Integer countTodayReservation(Member member, LocalDateTime now);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.time.LocalTime;
import java.util.List;

import static com.example.sabujak.branch.entity.QBranch.branch;
import static com.example.sabujak.reservation.entity.QMemberReservation.memberReservation;
import static com.example.sabujak.reservation.entity.QReservation.reservation;
import static com.example.sabujak.space.entity.QSpace.space;
Expand All @@ -17,23 +18,23 @@
public class ReservationRepositoryImpl implements ReservationRepositoryCustom {
private final JPAQueryFactory queryFactory;

// @Override
// public boolean existsOverlappingMeetingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt) {
// return queryFactory.selectOne()
// .from(reservation)
// .join(reservation.memberReservations, memberReservation)
// .join(reservation.space, space)
// .where(memberReservation.member.eq(member),
// space.dtype.eq("MeetingRoom"),
// reservation.reservationStartDateTime.between(startAt, endAt)
// .or(reservation.reservationEndDateTime.between(startAt, endAt))
// .or(reservation.reservationStartDateTime.before(startAt)
// .and(reservation.reservationEndDateTime.after(endAt))))
// .fetchFirst() != null;
// }
@Override
public boolean existsOverlappingMeetingRoomReservation(Member member, LocalDateTime startAt, LocalDateTime endAt) {
return queryFactory.selectOne()
.from(reservation)
.join(reservation.memberReservations, memberReservation)
.join(reservation.space, space)
.where(memberReservation.member.eq(member),
space.dtype.eq("MeetingRoom"),
reservation.reservationStartDateTime.between(startAt, endAt)
.or(reservation.reservationEndDateTime.between(startAt, endAt))
.or(reservation.reservationStartDateTime.before(startAt)
.and(reservation.reservationEndDateTime.after(endAt))))
.fetchFirst() != null;
}

@Override
public List<Reservation> findTodayReservationOrderByTime(Member member, LocalDateTime startAt) {
public List<Reservation> findTodayFocusDeskReservationOrderByTime(Member member, LocalDateTime startAt) {
LocalDateTime endAt = startAt;
startAt = startAt.with(LocalTime.MIDNIGHT);
return queryFactory.selectFrom(reservation)
Expand All @@ -43,6 +44,36 @@ public List<Reservation> findTodayReservationOrderByTime(Member member, LocalDat
space.dtype.eq("FocusDesk"),
reservation.reservationStartDateTime.between(startAt, endAt))
.orderBy(reservation.reservationId.asc())
//포커스 데스크는 시간을 설정하는게 아니라 예약한 시간부터 바로 사용하는거라 reservationId 가 곧 시간순
.fetch();
}

@Override
public List<Reservation> findReservationsWithDuration(Member member, LocalDateTime now, int durationStart, int durationEnd) {
LocalDateTime startAt = now.plusDays(durationStart).with(LocalTime.MIDNIGHT);
LocalDateTime endAt = now.plusDays(durationEnd).with(LocalTime.MAX);

return queryFactory.selectFrom(reservation)
.join(reservation.memberReservations, memberReservation)
.join(reservation.space, space).fetchJoin()
.join(space.branch, branch).fetchJoin()
.where(memberReservation.member.eq(member),
reservation.reservationStartDateTime.between(startAt, endAt))
.orderBy(reservation.reservationStartDateTime.asc())
.fetch();
}

@Override
public Integer countTodayReservation(Member member, LocalDateTime now) {
LocalDateTime startAt = now.with(LocalTime.MIDNIGHT);
LocalDateTime endAt = now.with(LocalTime.MAX);

return Math.toIntExact(queryFactory.select(reservation.count())
.from(reservation)
.join(reservation.memberReservations, memberReservation)
.join(reservation.space, space)
.where(memberReservation.member.eq(member),
reservation.reservationStartDateTime.between(startAt, endAt))
.fetchFirst());
}
}
Loading

0 comments on commit a93bd97

Please sign in to comment.