diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/FilterPendingApprovalResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/FilterPendingApprovalResponse.java new file mode 100644 index 00000000..0ab86e16 --- /dev/null +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/FilterPendingApprovalResponse.java @@ -0,0 +1,16 @@ +package clap.server.adapter.inbound.web.dto.task; + + + +import java.time.LocalDateTime; + +public record FilterPendingApprovalResponse( + Long taskId, + String taskCode, + LocalDateTime requestedAt, + String mainCategoryName, + String categoryName, + String title, + String requesterName +) { +} diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/FilterTaskListRequest.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/FilterTaskListRequest.java index 3e858ed9..6b361be3 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/FilterTaskListRequest.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/FilterTaskListRequest.java @@ -4,11 +4,9 @@ import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; -import org.springframework.beans.factory.annotation.Value; import java.util.List; -@Schema(description = "작업 필터링 요청") public record FilterTaskListRequest( @Schema(description = "검색 기간 (단위: 시간)", example = "1, 24, 168, 730, 2190 (1시간, 24시간, 1주일, 1개월, 3개월)") @@ -26,7 +24,7 @@ public record FilterTaskListRequest( @NotNull String title, - @Schema(description = "사용자 닉네임", example = "atom.park") + @Schema(description = "요청자/처리자 닉네임", example = "atom.park") @NotNull String nickName, diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/FindTaskListResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/FilterTaskListResponse.java similarity index 91% rename from src/main/java/clap/server/adapter/inbound/web/dto/task/FindTaskListResponse.java rename to src/main/java/clap/server/adapter/inbound/web/dto/task/FilterTaskListResponse.java index 152624dd..649cb249 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/FindTaskListResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/FilterTaskListResponse.java @@ -4,7 +4,7 @@ import java.time.LocalDateTime; -public record FindTaskListResponse( +public record FilterTaskListResponse( Long taskId, String taskCode, LocalDateTime requestedAt, diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/OrderRequest.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/OrderRequest.java index 4c6a3e31..c756d06e 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/OrderRequest.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/OrderRequest.java @@ -3,7 +3,7 @@ import io.swagger.v3.oas.annotations.media.Schema; public record OrderRequest( - @Schema(description = "정렬 기준 (REQUESTED_AT/FINISHED_AT)", example = "REQUESTED_AT") + @Schema(description = "정렬 기준", example = "REQUESTED_AT") String sortBy, @Schema(description = "정렬 방향 (ASC/DESC)", example = "ASC") diff --git a/src/main/java/clap/server/adapter/inbound/web/task/FindTaskController.java b/src/main/java/clap/server/adapter/inbound/web/task/FindTaskController.java index 339cb5cd..f58dcdbb 100644 --- a/src/main/java/clap/server/adapter/inbound/web/task/FindTaskController.java +++ b/src/main/java/clap/server/adapter/inbound/web/task/FindTaskController.java @@ -1,9 +1,7 @@ package clap.server.adapter.inbound.web.task; import clap.server.adapter.inbound.security.SecurityUserDetails; -import clap.server.adapter.inbound.web.dto.task.FindTaskDetailsResponse; -import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest; -import clap.server.adapter.inbound.web.dto.task.FindTaskListResponse; +import clap.server.adapter.inbound.web.dto.task.*; import clap.server.application.port.inbound.task.FindTaskDetailsUsecase; import clap.server.application.port.inbound.task.FindTaskListUsecase; import clap.server.common.annotation.architecture.WebAdapter; @@ -11,7 +9,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -20,8 +17,6 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; -import java.util.List; - @Tag(name = "작업 조회") @WebAdapter @RestController @@ -34,20 +29,31 @@ public class FindTaskController { @Operation(summary = "사용자 요청 작업 목록 조회") @Secured({"ROLE_USER"}) @GetMapping("/requests") - public ResponseEntity> getRequestedTaskList( + public ResponseEntity> findTasksRequestedByUser( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int pageSize, @ModelAttribute FilterTaskListRequest filterTaskListRequest, @AuthenticationPrincipal SecurityUserDetails userInfo){ Pageable pageable = PageRequest.of(page, pageSize); - return ResponseEntity.ok(taskListUsecase.findRequestedTaskList(userInfo.getUserId(), pageable, filterTaskListRequest)); + return ResponseEntity.ok(taskListUsecase.findTasksRequestedByUser(userInfo.getUserId(), pageable, filterTaskListRequest)); } @Operation(summary = "요청한 작업 상세 조회") @Secured({"ROLE_USER", "ROLE_MANAGER"}) @GetMapping("/requests/details/{taskId}") - public ResponseEntity> getRequestedTaskDetails( + public ResponseEntity findRequestedTaskDetails( @PathVariable Long taskId, @AuthenticationPrincipal SecurityUserDetails userInfo){ return ResponseEntity.ok(taskDetailsUsecase.findRequestedTaskDetails(userInfo.getUserId(), taskId)); } + @Operation(summary = "승인대기 중인 요청 목록 조회") + @Secured({"ROLE_MANAGER"}) + @GetMapping("/requests/pending") + public ResponseEntity> findPendingApprovalTasks( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "20") int pageSize, + @ModelAttribute FilterTaskListRequest filterTaskListRequest, + @AuthenticationPrincipal SecurityUserDetails userInfo){ + Pageable pageable = PageRequest.of(page, pageSize); + return ResponseEntity.ok(taskListUsecase.findPendingApprovalTasks(userInfo.getUserId(), pageable, filterTaskListRequest)); + } } \ No newline at end of file diff --git a/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java b/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java index c8128d32..2274fba1 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java @@ -1,7 +1,8 @@ package clap.server.adapter.outbound.persistense; import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest; -import clap.server.adapter.inbound.web.dto.task.FindTaskListResponse; +import clap.server.adapter.inbound.web.dto.task.FilterTaskListResponse; +import clap.server.adapter.inbound.web.dto.task.FilterPendingApprovalResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.mapper.TaskPersistenceMapper; import clap.server.adapter.outbound.persistense.repository.task.TaskRepository; @@ -38,10 +39,17 @@ public Optional findById(Long id) { } @Override - public Page findAllByRequesterId(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest) { - Page taskList = taskRepository.findRequestedTaskList(requesterId, pageable, findTaskListRequest) + public Page findTasksRequestedByUser(Long requesterId, Pageable pageable, FilterTaskListRequest filterTaskListRequest) { + Page taskList = taskRepository.findTasksRequestedByUser(requesterId, pageable, filterTaskListRequest) .map(taskPersistenceMapper::toDomain); - return taskList.map(TaskMapper::toFindTaskListResponse); + return taskList.map(TaskMapper::toFilterTaskListResponse); + } + + @Override + public Page findPendingApprovalTasks(Pageable pageable, FilterTaskListRequest filterTaskListRequest) { + Page taskList = taskRepository.findPendingApprovalTasks(pageable, filterTaskListRequest) + .map(taskPersistenceMapper::toDomain); + return taskList.map(TaskMapper::toFilterPendingApprovalTasksResponse); } @Override diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepository.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepository.java index dd7028c5..e0385877 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepository.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepository.java @@ -7,5 +7,6 @@ public interface TaskCustomRepository { - Page findRequestedTaskList(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest); + Page findTasksRequestedByUser(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest); + Page findPendingApprovalTasks(Pageable pageable, FilterTaskListRequest findTaskListRequest); } diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java index be184f6f..12b632f3 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java @@ -26,39 +26,48 @@ public class TaskCustomRepositoryImpl implements TaskCustomRepository { private final JPAQueryFactory queryFactory; @Override - public Page findRequestedTaskList(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest) { - BooleanBuilder whereClause = new BooleanBuilder(); + public Page findTasksRequestedByUser(Long requesterId, Pageable pageable, FilterTaskListRequest filterTaskListRequest) { + BooleanBuilder whereClause = createFilter(filterTaskListRequest); + if (!filterTaskListRequest.nickName().isEmpty()) { + whereClause.and(taskEntity.processor.nickname.eq(filterTaskListRequest.nickName())); + } whereClause.and(taskEntity.requester.memberId.eq(requesterId)); - List categoryIds = findTaskListRequest.categoryIds(); - List mainCategoryIds = findTaskListRequest.mainCategoryIds(); - String title = findTaskListRequest.title(); - String nickName = findTaskListRequest.nickName(); - List taskStatuses = findTaskListRequest.taskStatus(); - Integer termHours = findTaskListRequest.term(); - String sortBy = findTaskListRequest.orderRequest().sortBy(); - String sortDirection = findTaskListRequest.orderRequest().sortDirection(); + return getTasksPage(pageable, whereClause, filterTaskListRequest.orderRequest().sortBy(), filterTaskListRequest.orderRequest().sortDirection()); + } - if (termHours != null) { - LocalDateTime fromDate = LocalDateTime.now().minusHours(termHours); - whereClause.and(taskEntity.createdAt.after(fromDate)); + @Override + public Page findPendingApprovalTasks(Pageable pageable, FilterTaskListRequest filterTaskListRequest) { + BooleanBuilder whereClause = createFilter(filterTaskListRequest); + if (!filterTaskListRequest.nickName().isEmpty()) { + whereClause.and(taskEntity.requester.nickname.eq(filterTaskListRequest.nickName())); } - if (!categoryIds.isEmpty()) { - whereClause.and(taskEntity.category.categoryId.in(categoryIds)); + whereClause.and(taskEntity.taskStatus.eq(TaskStatus.REQUESTED)); + return getTasksPage(pageable, whereClause, filterTaskListRequest.orderRequest().sortBy(), filterTaskListRequest.orderRequest().sortDirection()); + } + + private BooleanBuilder createFilter(FilterTaskListRequest request) { + BooleanBuilder whereClause = new BooleanBuilder(); + if (request.term() != null) { + LocalDateTime fromDate = LocalDateTime.now().minusHours(request.term()); + whereClause.and(taskEntity.createdAt.after(fromDate)); } - if (!mainCategoryIds.isEmpty()) { - whereClause.and(taskEntity.category.mainCategory.categoryId.in(mainCategoryIds)); + if (!request.categoryIds().isEmpty()) { + whereClause.and(taskEntity.category.categoryId.in(request.categoryIds())); } - if (!title.isEmpty()) { - whereClause.and(taskEntity.title.containsIgnoreCase(title)); + if (!request.mainCategoryIds().isEmpty()) { + whereClause.and(taskEntity.category.mainCategory.categoryId.in(request.mainCategoryIds())); } - if (!nickName.isEmpty()) { - whereClause.and(taskEntity.processor.nickname.eq(nickName)); + if (!request.title().isEmpty()) { + whereClause.and(taskEntity.title.containsIgnoreCase(request.title())); } - if (!taskStatuses.isEmpty()) { - whereClause.and(taskEntity.taskStatus.in(taskStatuses)); + if (!request.taskStatus().isEmpty()) { + whereClause.and(taskEntity.taskStatus.in(request.taskStatus())); } + return whereClause; + } + private Page getTasksPage(Pageable pageable, BooleanBuilder whereClause, String sortBy, String sortDirection) { OrderSpecifier orderSpecifier = getOrderSpecifier(sortBy, sortDirection); List result = queryFactory @@ -68,7 +77,7 @@ public Page findRequestedTaskList(Long requesterId, Pageable pageabl .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch(); - int total = queryFactory + long total = queryFactory .selectFrom(taskEntity) .where(whereClause) .fetch().size(); @@ -85,4 +94,4 @@ private OrderSpecifier getOrderSpecifier(String sortBy, String sortDirection) ? new OrderSpecifier<>(ASC, sortColumn) : new OrderSpecifier<>(DESC, sortColumn); } -} +} \ No newline at end of file diff --git a/src/main/java/clap/server/application/Task/FindTaskDetailsService.java b/src/main/java/clap/server/application/Task/FindTaskDetailsService.java index c48dc7b9..2920f46d 100644 --- a/src/main/java/clap/server/application/Task/FindTaskDetailsService.java +++ b/src/main/java/clap/server/application/Task/FindTaskDetailsService.java @@ -28,11 +28,11 @@ public class FindTaskDetailsService implements FindTaskDetailsUsecase { private final LoadAttachmentPort loadAttachmentPort; @Override - public List findRequestedTaskDetails(final Long requesterId, final Long taskId) { + public FindTaskDetailsResponse findRequestedTaskDetails(final Long requesterId, final Long taskId) { memberService.findActiveMember(requesterId); Task task = loadTaskPort.findById(taskId) .orElseThrow(()-> new ApplicationException(TaskErrorCode.TASK_NOT_FOUND)); List attachments = loadAttachmentPort.findAllByTaskIdAndCommentIsNull(taskId); - return TaskMapper.toFindTaskDetailResponses(task, attachments); + return TaskMapper.toFindTaskDetailResponse(task, attachments); } } diff --git a/src/main/java/clap/server/application/Task/FindTaskListService.java b/src/main/java/clap/server/application/Task/FindTaskListService.java index bb8d9183..57570230 100644 --- a/src/main/java/clap/server/application/Task/FindTaskListService.java +++ b/src/main/java/clap/server/application/Task/FindTaskListService.java @@ -1,8 +1,9 @@ package clap.server.application.Task; import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest; -import clap.server.adapter.inbound.web.dto.task.FindTaskListResponse; +import clap.server.adapter.inbound.web.dto.task.FilterTaskListResponse; +import clap.server.adapter.inbound.web.dto.task.FilterPendingApprovalResponse; import clap.server.application.port.inbound.domain.MemberService; import clap.server.application.port.inbound.task.FindTaskListUsecase; @@ -28,8 +29,14 @@ public class FindTaskListService implements FindTaskListUsecase { @Override - public Page findRequestedTaskList(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest) { + public Page findTasksRequestedByUser(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest) { Member requester = memberService.findActiveMember(requesterId); - return loadTaskPort.findAllByRequesterId(requester.getMemberId(), pageable, findTaskListRequest); + return loadTaskPort.findTasksRequestedByUser(requester.getMemberId(), pageable, findTaskListRequest); + } + + @Override + public Page findPendingApprovalTasks(Long managerId, Pageable pageable, FilterTaskListRequest filterTaskListRequest) { + memberService.findActiveMember(managerId); + return loadTaskPort.findPendingApprovalTasks(pageable, filterTaskListRequest); } } diff --git a/src/main/java/clap/server/application/mapper/TaskMapper.java b/src/main/java/clap/server/application/mapper/TaskMapper.java index 752c8833..7fce4e8f 100644 --- a/src/main/java/clap/server/application/mapper/TaskMapper.java +++ b/src/main/java/clap/server/application/mapper/TaskMapper.java @@ -6,9 +6,7 @@ import clap.server.domain.model.task.Attachment; import clap.server.domain.model.task.Task; -import lombok.extern.slf4j.Slf4j; -import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; @@ -24,8 +22,8 @@ public static UpdateTaskResponse toUpdateTaskResponse(Task task) { return new UpdateTaskResponse(task.getTaskId(), task.getCategory().getCategoryId(), task.getTitle()); } - public static FindTaskListResponse toFindTaskListResponse(Task task) { - return new FindTaskListResponse( + public static FilterTaskListResponse toFilterTaskListResponse(Task task) { + return new FilterTaskListResponse( task.getTaskId(), task.getTaskCode(), task.getUpdatedAt(), @@ -38,7 +36,19 @@ public static FindTaskListResponse toFindTaskListResponse(Task task) { ); } - public static List toFindTaskDetailResponses(Task task, List attachments){ + public static FilterPendingApprovalResponse toFilterPendingApprovalTasksResponse(Task task) { + return new FilterPendingApprovalResponse( + task.getTaskId(), + task.getTaskCode(), + task.getUpdatedAt(), + task.getCategory().getMainCategory().getName(), + task.getCategory().getName(), + task.getTitle(), + task.getRequester().getMemberInfo().getNickname() + ); + } + + public static FindTaskDetailsResponse toFindTaskDetailResponse(Task task, List attachments){ List attachmentResponses = attachments.stream() .map(attachment -> new AttachmentResponse( @@ -50,7 +60,7 @@ public static List toFindTaskDetailResponses(Task task, )) .collect(Collectors.toList()); - FindTaskDetailsResponse response = new FindTaskDetailsResponse( + return new FindTaskDetailsResponse( task.getTaskId(), task.getTaskCode(), task.getCreatedAt(), @@ -66,7 +76,5 @@ public static List toFindTaskDetailResponses(Task task, task.getDescription(), attachmentResponses ); - - return List.of(response); } } diff --git a/src/main/java/clap/server/application/port/inbound/task/FindTaskDetailsUsecase.java b/src/main/java/clap/server/application/port/inbound/task/FindTaskDetailsUsecase.java index 0006c376..009eca07 100644 --- a/src/main/java/clap/server/application/port/inbound/task/FindTaskDetailsUsecase.java +++ b/src/main/java/clap/server/application/port/inbound/task/FindTaskDetailsUsecase.java @@ -5,5 +5,5 @@ import java.util.List; public interface FindTaskDetailsUsecase { - List findRequestedTaskDetails(Long memberId, Long taskId); + FindTaskDetailsResponse findRequestedTaskDetails(Long memberId, Long taskId); } diff --git a/src/main/java/clap/server/application/port/inbound/task/FindTaskListUsecase.java b/src/main/java/clap/server/application/port/inbound/task/FindTaskListUsecase.java index 8d85fdbf..7aed8dce 100644 --- a/src/main/java/clap/server/application/port/inbound/task/FindTaskListUsecase.java +++ b/src/main/java/clap/server/application/port/inbound/task/FindTaskListUsecase.java @@ -1,10 +1,13 @@ package clap.server.application.port.inbound.task; import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest; -import clap.server.adapter.inbound.web.dto.task.FindTaskListResponse; +import clap.server.adapter.inbound.web.dto.task.FilterTaskListResponse; +import clap.server.adapter.inbound.web.dto.task.FilterPendingApprovalResponse; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; public interface FindTaskListUsecase { - Page findRequestedTaskList(Long memberId, Pageable pageable, FilterTaskListRequest findTaskListRequest); + Page findTasksRequestedByUser(Long memberId, Pageable pageable, FilterTaskListRequest findTaskListRequest); + + Page findPendingApprovalTasks(Long userId, Pageable pageable, FilterTaskListRequest filterTaskListRequest); } diff --git a/src/main/java/clap/server/application/port/outbound/task/LoadTaskPort.java b/src/main/java/clap/server/application/port/outbound/task/LoadTaskPort.java index 9e8cb996..50042219 100644 --- a/src/main/java/clap/server/application/port/outbound/task/LoadTaskPort.java +++ b/src/main/java/clap/server/application/port/outbound/task/LoadTaskPort.java @@ -1,7 +1,8 @@ package clap.server.application.port.outbound.task; import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest; -import clap.server.adapter.inbound.web.dto.task.FindTaskListResponse; +import clap.server.adapter.inbound.web.dto.task.FilterTaskListResponse; +import clap.server.adapter.inbound.web.dto.task.FilterPendingApprovalResponse; import clap.server.domain.model.task.Task; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -15,6 +16,8 @@ public interface LoadTaskPort { List findYesterdayTaskByDate(LocalDateTime now); - Page findAllByRequesterId(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest); + Page findTasksRequestedByUser(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest); + + Page findPendingApprovalTasks(Pageable pageable, FilterTaskListRequest filterTaskListRequest); } \ No newline at end of file diff --git a/src/test/java/clap/server/task/FindTaskDetailsUsecase.java b/src/test/java/clap/server/task/FindTaskDetailsUsecase.java deleted file mode 100644 index 6fc35e9d..00000000 --- a/src/test/java/clap/server/task/FindTaskDetailsUsecase.java +++ /dev/null @@ -1,4 +0,0 @@ -package clap.server.task; - -public class FindTaskDetailsUsecase { -} diff --git a/src/test/java/clap/server/task/FindTaskListServiceTest.java b/src/test/java/clap/server/task/FindTaskListServiceTest.java new file mode 100644 index 00000000..695cf439 --- /dev/null +++ b/src/test/java/clap/server/task/FindTaskListServiceTest.java @@ -0,0 +1,97 @@ +package clap.server.task; + +import clap.server.adapter.inbound.web.dto.task.FilterPendingApprovalResponse; +import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest; +import clap.server.adapter.inbound.web.dto.task.OrderRequest; + +import clap.server.application.Task.FindTaskListService; +import clap.server.application.port.inbound.domain.MemberService; +import clap.server.application.port.outbound.task.LoadTaskPort; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.*; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class FindTaskListServiceTest { + + @Mock + private MemberService memberService; + @Mock + private LoadTaskPort loadTaskPort; + @InjectMocks + private FindTaskListService findTaskListService; + + private FilterTaskListRequest filterTaskListRequest; + private Pageable pageable; + private Page expectedResponse; + + @BeforeEach + void setUp() { + pageable = PageRequest.of(0, 20); + filterTaskListRequest = new FilterTaskListRequest( + null, List.of(2L), List.of(1L), "작업 제목", "", List.of(), new OrderRequest("REQUESTED_AT", "DESC") + ); + + FilterPendingApprovalResponse response = new FilterPendingApprovalResponse( + 1L, "TC001", LocalDateTime.of(2025, 1, 24, 12, 30), + "메인 카테고리", "서브 카테고리", "작업 제목", "atom.park" + ); + + FilterPendingApprovalResponse response2 = new FilterPendingApprovalResponse( + 2L, "TC002", LocalDateTime.of(2025, 1, 15, 14, 30), + "메인 카테고리2", "서브 카테고리2", "다른 작업 제목", "john.doe" + ); + expectedResponse = new PageImpl<>(List.of(response, response2), pageable, 1); + } + + @Test + @DisplayName("승인대기 중인 작업요청목록 조회") + void findPendingApprovalTasks_ReturnFilteredTasks() { + // given + Long managerId = 1L; + when(loadTaskPort.findPendingApprovalTasks(pageable, filterTaskListRequest)) + .thenReturn(expectedResponse); + + // when + Page result = findTaskListService.findPendingApprovalTasks(managerId, pageable, filterTaskListRequest); + + // then + assertThat(result).isNotNull(); + assertThat(result.getTotalElements()).isEqualTo(2); + + assertThat(result.getContent()).hasSize(2) + .extracting(FilterPendingApprovalResponse::taskId) + .containsExactly(1L, 2L); + + assertThat(result.getContent().get(0)) + .extracting(FilterPendingApprovalResponse::taskId, FilterPendingApprovalResponse::taskCode, + FilterPendingApprovalResponse::requestedAt, FilterPendingApprovalResponse::mainCategoryName, + FilterPendingApprovalResponse::categoryName, FilterPendingApprovalResponse::title, + FilterPendingApprovalResponse::requesterName) + .containsExactly(1L, "TC001", LocalDateTime.of(2025, 1, 24, 12, 30), + "메인 카테고리", "서브 카테고리", "작업 제목", "atom.park"); + + assertThat(result.getContent().get(1)) + .extracting(FilterPendingApprovalResponse::taskId, FilterPendingApprovalResponse::taskCode, + FilterPendingApprovalResponse::requestedAt, FilterPendingApprovalResponse::mainCategoryName, + FilterPendingApprovalResponse::categoryName, FilterPendingApprovalResponse::title, + FilterPendingApprovalResponse::requesterName) + .containsExactly(2L, "TC002", LocalDateTime.of(2025, 1, 15, 14, 30), + "메인 카테고리2", "서브 카테고리2", "다른 작업 제목", "john.doe"); + + verify(loadTaskPort).findPendingApprovalTasks(pageable, filterTaskListRequest); + } +}