diff --git a/src/main/java/com/likelion/innerjoin/post/controller/PostController.java b/src/main/java/com/likelion/innerjoin/post/controller/PostController.java index 79382f9..2436827 100644 --- a/src/main/java/com/likelion/innerjoin/post/controller/PostController.java +++ b/src/main/java/com/likelion/innerjoin/post/controller/PostController.java @@ -148,7 +148,7 @@ public CommonResponse getApplications(@PathVariable Long pos @PostMapping("/interview-times") - @Operation(summary = "특정 recruiting의 면접 가능 시간 생성") + @Operation(summary = "특정 recruiting의 면접 가능 시간 생성, 예약 가능 시간 설정") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "면접 가능 시간 생성 성공"), @ApiResponse(responseCode = "401", description = "세션값이 잘못되었습니다"), @@ -156,13 +156,13 @@ public CommonResponse getApplications(@PathVariable Long pos @ApiResponse(responseCode = "500", description = "서버 내부 오류") }) public CommonResponse createInterviewTimes(@RequestBody MeetingTimeRequestDTO request, HttpSession session) { - meetingTimeService.createMeetingTimes(request.getRecruitingId(), request.getMeetingTimes(), session); - return new CommonResponse<>("면접 가능 시간이 성공적으로 생성되었습니다."); + meetingTimeService.createMeetingTimes(request.getRecruitingId(), request, session); + return new CommonResponse<>("면접 가능 시간 리스트가 설정되었습니다. 예약 가능 시간이 설정되었습니다."); } @GetMapping("/interview-times/{recruiting_id}") - @Operation(summary = "특정 recruiting의 면접 가능 시간 목록 조회") + @Operation(summary = "특정 recruiting의 정보 조회 (직무명, 면접가능시간, 예약시간 등)") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "면접 가능 시간 목록 조회 성공"), @ApiResponse(responseCode = "404", description = "해당 recruiting id를 찾을 수 없음"), diff --git a/src/main/java/com/likelion/innerjoin/post/model/dto/request/MeetingTimeRequestDTO.java b/src/main/java/com/likelion/innerjoin/post/model/dto/request/MeetingTimeRequestDTO.java index a422606..3a0cf37 100644 --- a/src/main/java/com/likelion/innerjoin/post/model/dto/request/MeetingTimeRequestDTO.java +++ b/src/main/java/com/likelion/innerjoin/post/model/dto/request/MeetingTimeRequestDTO.java @@ -9,6 +9,8 @@ public class MeetingTimeRequestDTO { private Long recruitingId; private List meetingTimes; + private LocalDateTime reservationStartTime; + private LocalDateTime reservationEndTime; @Data public static class MeetingTimeDto { diff --git a/src/main/java/com/likelion/innerjoin/post/model/dto/response/MeetingTimeListResponseDTO.java b/src/main/java/com/likelion/innerjoin/post/model/dto/response/MeetingTimeListResponseDTO.java index 7fe3578..fa1bcf3 100644 --- a/src/main/java/com/likelion/innerjoin/post/model/dto/response/MeetingTimeListResponseDTO.java +++ b/src/main/java/com/likelion/innerjoin/post/model/dto/response/MeetingTimeListResponseDTO.java @@ -1,13 +1,19 @@ package com.likelion.innerjoin.post.model.dto.response; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import java.time.LocalDateTime; import java.util.List; @Data @AllArgsConstructor +@Builder public class MeetingTimeListResponseDTO { private Long recruitingId; + private String jobTitle; + private LocalDateTime reservationStartTime; + private LocalDateTime reservationEndTime; private List meetingTimes; } diff --git a/src/main/java/com/likelion/innerjoin/post/model/entity/Recruiting.java b/src/main/java/com/likelion/innerjoin/post/model/entity/Recruiting.java index 2b59529..1e41d46 100644 --- a/src/main/java/com/likelion/innerjoin/post/model/entity/Recruiting.java +++ b/src/main/java/com/likelion/innerjoin/post/model/entity/Recruiting.java @@ -1,5 +1,6 @@ package com.likelion.innerjoin.post.model.entity; +import com.fasterxml.jackson.annotation.JsonFormat; import com.likelion.innerjoin.common.entity.DataEntity; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -7,6 +8,7 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.time.LocalDateTime; import java.util.List; @Entity @@ -32,6 +34,14 @@ public class Recruiting extends DataEntity { @Column(name = "job_title") private String jobTitle; + @Column(name = "reservation_start_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime reservationStartTime; + + @Column(name = "reservation_end_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime reservationEndTime; + @OneToMany(mappedBy = "recruiting", orphanRemoval = true, cascade = CascadeType.ALL) private List application; diff --git a/src/main/java/com/likelion/innerjoin/post/repository/MeetingTimeRepository.java b/src/main/java/com/likelion/innerjoin/post/repository/MeetingTimeRepository.java index 243b360..4ed1a53 100644 --- a/src/main/java/com/likelion/innerjoin/post/repository/MeetingTimeRepository.java +++ b/src/main/java/com/likelion/innerjoin/post/repository/MeetingTimeRepository.java @@ -8,4 +8,5 @@ public interface MeetingTimeRepository extends JpaRepository { List findByRecruiting(Recruiting recruiting); + List findByRecruitingId(Long recruitingId); } diff --git a/src/main/java/com/likelion/innerjoin/post/service/ApplicationService.java b/src/main/java/com/likelion/innerjoin/post/service/ApplicationService.java index 4f86eac..d2a5c53 100644 --- a/src/main/java/com/likelion/innerjoin/post/service/ApplicationService.java +++ b/src/main/java/com/likelion/innerjoin/post/service/ApplicationService.java @@ -20,6 +20,7 @@ import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Service; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -252,6 +253,13 @@ public MeetingTimeResponseDTO selectMeetingTime (MeetingTimeSelectionDto dto, Ht throw new AllowedNumExceededException("면접 허용 인원을 초과했습니다."); } + // 예약 종료 시간 확인 + LocalDateTime reservationEndTime = meetingTime.getRecruiting().getReservationEndTime(); + if (reservationEndTime != null && LocalDateTime.now().isAfter(reservationEndTime)) { + throw new IllegalStateException("면접 예약이 종료되었습니다."); + } + + //면접 시간 설정 application.setMeetingTime(meetingTime); applicationRepository.save(application); diff --git a/src/main/java/com/likelion/innerjoin/post/service/MeetingTimeService.java b/src/main/java/com/likelion/innerjoin/post/service/MeetingTimeService.java index 34ef2e2..2ab2642 100644 --- a/src/main/java/com/likelion/innerjoin/post/service/MeetingTimeService.java +++ b/src/main/java/com/likelion/innerjoin/post/service/MeetingTimeService.java @@ -6,10 +6,7 @@ import com.likelion.innerjoin.post.exception.UnauthorizedException; import com.likelion.innerjoin.post.model.dto.response.MeetingTimeResponseDTO; import com.likelion.innerjoin.post.model.dto.response.MeetingTimeListResponseDTO; -import com.likelion.innerjoin.post.model.entity.Application; -import com.likelion.innerjoin.post.model.entity.MeetingTime; -import com.likelion.innerjoin.post.model.entity.Recruiting; -import com.likelion.innerjoin.post.model.entity.Post; +import com.likelion.innerjoin.post.model.entity.*; import com.likelion.innerjoin.post.model.dto.request.MeetingTimeRequestDTO; import com.likelion.innerjoin.post.repository.MeetingTimeRepository; import com.likelion.innerjoin.post.repository.PostRepository; @@ -18,6 +15,7 @@ import com.likelion.innerjoin.user.model.entity.User; import com.likelion.innerjoin.user.util.SessionVerifier; import jakarta.servlet.http.HttpSession; +import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -34,21 +32,34 @@ public class MeetingTimeService { private final SessionVerifier sessionVerifier; //면접시간 리스트 생성 - public void createMeetingTimes(Long recruitingId, List meetingTimeDtos, HttpSession session) { + @Transactional + public void createMeetingTimes(Long recruitingId, MeetingTimeRequestDTO request, HttpSession session) { + // Recruiting 조회 Recruiting recruiting = recruitingRepository.findById(recruitingId) .orElseThrow(() -> new RecruitingNotFoundException("Recruiting not found with id: " + recruitingId)); + // Post 조회 및 Club 검증 Post post = postRepository.findById(recruiting.getPost().getId()) .orElseThrow(() -> new PostNotFoundException("Post not found")); - // post의 club_id가 유저의 club_id와 일치하는지 확인 if (!post.getClub().getId().equals(checkClub(session).getId())) { throw new UnauthorizedException("홍보글의 club_id가 현재 유저의 club_id와 일치하지 않습니다."); } - // 요청DTO를 MeetingTime 엔티티로 변환 - List meetingTimes = meetingTimeDtos.stream() + // 홍보글의 RecruitmentStatus 확인 (면접 시간이 이미 확정된 경우) + if (post.getRecruitmentStatus() == RecruitmentStatus.TIME_SET) { + throw new IllegalStateException("면접 시간이 이미 공개되어서(TIME_SET) 다시 설정할 수 없습니다."); + } + + // 기존 MeetingTime 삭제 + List existingMeetingTimes = meetingTimeRepository.findByRecruitingId(recruitingId); + if (!existingMeetingTimes.isEmpty()) { + meetingTimeRepository.deleteAll(existingMeetingTimes); + } + + // 새로운 MeetingTime 엔티티 생성 및 저장 + List meetingTimes = request.getMeetingTimes().stream() .map(dto -> { MeetingTime meetingTime = new MeetingTime(); meetingTime.setAllowedNum(dto.getAllowedNum()); @@ -60,9 +71,15 @@ public void createMeetingTimes(Long recruitingId, List getMeetingTimesByRecruitingId(Long recruitingId) { // recruiting 찾기 Recruiting recruiting = recruitingRepository.findById(recruitingId) @@ -104,7 +121,15 @@ public CommonResponse getMeetingTimesByRecruitingId( }) .collect(Collectors.toList()); - MeetingTimeListResponseDTO responseDto = new MeetingTimeListResponseDTO(recruitingId, meetingTimeDtos); + MeetingTimeListResponseDTO responseDto = new MeetingTimeListResponseDTO( + recruiting.getId(), + recruiting.getJobTitle(), + recruiting.getReservationStartTime(), + recruiting.getReservationEndTime(), + meetingTimeDtos + ); + return new CommonResponse<>(responseDto); } + }