diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/request/FilterTaskBoardRequest.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/request/FilterTaskBoardRequest.java index bde8cfe4..758e8720 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/request/FilterTaskBoardRequest.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/request/FilterTaskBoardRequest.java @@ -1,16 +1,21 @@ package clap.server.adapter.inbound.web.dto.task.request; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; + +import java.util.List; public record FilterTaskBoardRequest( @Schema(description = "라벨 ID") Long labelId, - @Schema(description = "1차 카테고리 ID, ** 2차 카테고리로 검색할 시에는 1차 카테고리 값은 넣지 않습니다.") - Long mainCategoryId, + @Schema(description = "1차 카테고리 ID 목록", example = "[1, 3, 5]") + @NotNull + List mainCategoryIds, - @Schema(description = "2차 카테고리 ID") - Long subCategoryId, + @Schema(description = "2차 카테고리 ID 목록", example = "[2, 4]") + @NotNull + List categoryIds, @Schema(description = "작업 제목", example = "작업 제목") String title, diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskBoardResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskBoardResponse.java index 1c973647..f1953e11 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskBoardResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskBoardResponse.java @@ -5,9 +5,6 @@ public record TaskBoardResponse( List tasksInProgress, List tasksPendingComplete, - List tasksCompleted, - boolean hasNext, - boolean isFirst, - boolean isLast + List tasksCompleted ){ } diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskItemResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskItemResponse.java index a67406d6..196d2407 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskItemResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskItemResponse.java @@ -1,5 +1,6 @@ package clap.server.adapter.inbound.web.dto.task.response; +import clap.server.adapter.outbound.persistense.entity.task.constant.LabelColor; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import java.time.LocalDateTime; @@ -10,11 +11,19 @@ public record TaskItemResponse( String title, String mainCategoryName, String categoryName, + LabelInfo labelInfo, String requesterNickname, String requesterImageUrl, String requesterDepartment, long processorOrder, TaskStatus taskStatus, LocalDateTime createdAt -){ +) { + public static record LabelInfo( + String labelName, + LabelColor labelColor + ) { + } + } + diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java index 61cd5dfc..1cad188c 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java @@ -3,9 +3,9 @@ import java.util.List; public record TeamStatusResponse( - List members + List members ) { - public TeamStatusResponse(List members) { + public TeamStatusResponse(List members) { this.members = (members == null) ? List.of() : members; } } diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskItemResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskItemResponse.java new file mode 100644 index 00000000..43ae6c43 --- /dev/null +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskItemResponse.java @@ -0,0 +1,20 @@ +package clap.server.adapter.inbound.web.dto.task.response; + +import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; + +import java.time.LocalDateTime; + +public record TeamTaskItemResponse( + Long taskId, + String taskCode, + String title, + String mainCategoryName, + String categoryName, + String requesterNickname, + String requesterImageUrl, + String requesterDepartment, + long processorOrder, + TaskStatus taskStatus, + LocalDateTime createdAt +) { +} diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskResponse.java similarity index 79% rename from src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java rename to src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskResponse.java index 157993a4..557b77f4 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskResponse.java @@ -4,7 +4,7 @@ import java.util.List; -public record TeamMemberTaskResponse( +public record TeamTaskResponse( Long processorId, String nickname, String imageUrl, @@ -12,10 +12,10 @@ public record TeamMemberTaskResponse( int inProgressTaskCount, int pendingTaskCount, int totalTaskCount, - List tasks + List tasks ) { @QueryProjection - public TeamMemberTaskResponse { + public TeamTaskResponse { tasks = (tasks == null) ? List.of() : tasks; } } diff --git a/src/main/java/clap/server/adapter/inbound/web/history/CommandCommentController.java b/src/main/java/clap/server/adapter/inbound/web/history/CommandCommentController.java index 81a74390..e7a44d8d 100644 --- a/src/main/java/clap/server/adapter/inbound/web/history/CommandCommentController.java +++ b/src/main/java/clap/server/adapter/inbound/web/history/CommandCommentController.java @@ -1,6 +1,6 @@ package clap.server.adapter.inbound.web.history; -import clap.server.adapter.inbound.security.SecurityUserDetails; +import clap.server.adapter.inbound.security.service.SecurityUserDetails; import clap.server.adapter.inbound.web.dto.history.request.EditCommentRequest; import clap.server.application.port.inbound.history.DeleteCommentUsecase; import clap.server.application.port.inbound.history.EditCommentUsecase; diff --git a/src/main/java/clap/server/adapter/inbound/web/history/PostCommentController.java b/src/main/java/clap/server/adapter/inbound/web/history/PostCommentController.java index c473f6fc..cc2b6207 100644 --- a/src/main/java/clap/server/adapter/inbound/web/history/PostCommentController.java +++ b/src/main/java/clap/server/adapter/inbound/web/history/PostCommentController.java @@ -1,6 +1,6 @@ package clap.server.adapter.inbound.web.history; -import clap.server.adapter.inbound.security.SecurityUserDetails; +import clap.server.adapter.inbound.security.service.SecurityUserDetails; import clap.server.adapter.inbound.web.dto.history.request.CreateCommentRequest; import clap.server.application.port.inbound.history.SaveCommentAttachmentUsecase; import clap.server.application.port.inbound.history.SaveCommentUsecase; diff --git a/src/main/java/clap/server/adapter/inbound/web/task/TaskBoardController.java b/src/main/java/clap/server/adapter/inbound/web/task/TaskBoardController.java index 7153ba95..44570e00 100644 --- a/src/main/java/clap/server/adapter/inbound/web/task/TaskBoardController.java +++ b/src/main/java/clap/server/adapter/inbound/web/task/TaskBoardController.java @@ -7,7 +7,6 @@ import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import clap.server.application.port.inbound.task.FilterTaskBoardUsecase; import clap.server.application.port.inbound.task.UpdateTaskBoardUsecase; -import clap.server.application.port.inbound.task.GetTaskBoardUsecase; import clap.server.application.port.inbound.task.UpdateTaskOrderAndStatusUsecase; import clap.server.common.annotation.architecture.WebAdapter; import io.swagger.v3.oas.annotations.Operation; @@ -15,9 +14,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.security.access.annotation.Secured; @@ -26,14 +22,12 @@ import java.time.LocalDate; -@Slf4j @Tag(name = "02. Task [담당자]") @WebAdapter @RestController @RequiredArgsConstructor @RequestMapping("/api/task-board") public class TaskBoardController { - private final GetTaskBoardUsecase getTaskBoardUsecase; private final FilterTaskBoardUsecase filterTaskBoardUsecase; private final UpdateTaskBoardUsecase updateTaskBoardUsecase; private final UpdateTaskOrderAndStatusUsecase updateTaskOrderAndStatus; @@ -41,23 +35,19 @@ public class TaskBoardController { @Operation(summary = "작업 보드 조회 API") @Secured({"ROLE_MANAGER"}) @GetMapping - public ResponseEntity getTaskBoard(@RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") int pageSize, - @Parameter(description = "작업 완료 일자 조회 기준, yyyy-mm-dd 형식으로 입력합니다.") @RequestParam(required = false) - @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate untilDate, - @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "필터링 조회 request") @ModelAttribute FilterTaskBoardRequest request, - @AuthenticationPrincipal SecurityUserDetails userInfo) { - Pageable pageable = PageRequest.of(page, pageSize); - if (request != null) { - return ResponseEntity.ok(filterTaskBoardUsecase.getTaskBoardByFilter(userInfo.getUserId(), untilDate, request, pageable)); - } else - return ResponseEntity.ok(getTaskBoardUsecase.getTaskBoards(userInfo.getUserId(), untilDate, pageable)); + public ResponseEntity getTaskBoard( + @Parameter(description = "작업 완료 일자 조회 기준, yyyy-mm-dd 형식으로 입력합니다.") @RequestParam(required = false) + @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate fromDate, + @ModelAttribute FilterTaskBoardRequest request, + @AuthenticationPrincipal SecurityUserDetails userInfo) { + return ResponseEntity.ok(filterTaskBoardUsecase.getTaskBoardByFilter(userInfo.getUserId(), fromDate, request)); } @Operation(summary = "작업 보드 순서 및 상태 변경 API") @Secured({"ROLE_MANAGER"}) @PatchMapping - public void updateTaskBoard(@Parameter(description = "전환될 작업의 상태, 상태 전환이 아니라면 입력 X", schema = @Schema(allowableValues = {"IN_PROGRESS", "PENDING_COMPLETED", "COMPLETED"})) + public void updateTaskBoard(@Parameter(description = "전환될 작업의 상태, 상태 전환이 아니라면 입력 X", + schema = @Schema(allowableValues = {"IN_PROGRESS", "PENDING_COMPLETED", "COMPLETED"})) @RequestParam(required = false) TaskStatus status, @RequestBody UpdateTaskOrderRequest request, @AuthenticationPrincipal SecurityUserDetails userInfo) { 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 7171871b..9c300113 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java @@ -1,9 +1,9 @@ package clap.server.adapter.outbound.persistense; -import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest; +import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import clap.server.adapter.outbound.persistense.mapper.TaskPersistenceMapper; @@ -16,8 +16,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; import java.time.LocalDateTime; import java.util.List; @@ -61,12 +59,6 @@ public Page findPendingApprovalTasks(Pageable pageable, FilterTaskListRequ .map(taskPersistenceMapper::toDomain); } - @Override - public Slice findByProcessorAndStatus(Long processorId, List statuses, LocalDateTime untilDate, Pageable pageable) { - Slice tasks = taskRepository.findTasksWithTaskStatusAndCompletedAt(processorId, statuses, untilDate, pageable); - return tasks.map(taskPersistenceMapper::toDomain); - } - @Override public Optional findByIdAndStatus(Long id, TaskStatus status) { Optional taskEntity = taskRepository.findByTaskIdAndTaskStatus(id, status); @@ -98,21 +90,14 @@ public Optional findNextOrderTaskByProcessorIdAndStatus(Long processorId, } @Override - public Slice findTaskBoardByFilter(Long processorId, List statuses, LocalDateTime untilDate, FilterTaskBoardRequest request, Pageable pageable) { - List taskList = new java.util.ArrayList<>(taskRepository.findTasksByFilter(processorId, statuses, untilDate, request, pageable) + public List findTaskBoardByFilter(Long processorId, List statuses, LocalDateTime fromDate, FilterTaskBoardRequest request) { + return taskRepository.findTasksByFilter(processorId, statuses, fromDate, request) .stream() - .map(taskPersistenceMapper::toDomain) - .toList()); - - boolean hasNext = taskList.size() > pageable.getPageSize(); - if (hasNext) { - taskList.remove(taskList.size() - 1); - } - return new SliceImpl<>(taskList, pageable, hasNext); + .map(taskPersistenceMapper::toDomain).toList(); } @Override - public List findTeamStatus(Long memberId, FilterTeamStatusRequest filter) { + public List findTeamStatus(Long memberId, FilterTeamStatusRequest filter) { return taskRepository.findTeamStatus(memberId, filter); } 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 b016c5cb..dfcd6fe3 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 @@ -3,7 +3,7 @@ import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import org.springframework.data.domain.Page; @@ -15,9 +15,9 @@ public interface TaskCustomRepository { Page findTasksRequestedByUser(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest); - List findTeamStatus(Long memberId, FilterTeamStatusRequest filter); + List findTeamStatus(Long memberId, FilterTeamStatusRequest filter); Page findPendingApprovalTasks(Pageable pageable, FilterTaskListRequest findTaskListRequest); Page findAllTasks(Pageable pageable, FilterTaskListRequest findTaskListRequest); - List findTasksByFilter(Long processorId, List statuses, LocalDateTime localDateTime, FilterTaskBoardRequest request, Pageable pageable); + List findTasksByFilter(Long processorId, List statuses, LocalDateTime localDateTime, FilterTaskBoardRequest request); Page findTasksAssignedByManager(Long processorId, 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 b6fa1e00..5a9e9a29 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 @@ -1,18 +1,17 @@ package clap.server.adapter.outbound.persistense.repository.task; -import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest; +import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TaskItemResponse; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskItemResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.CaseBuilder; import com.querydsl.core.types.dsl.DateTimePath; import com.querydsl.jpa.impl.JPAQueryFactory; -import jakarta.persistence.EntityManager; -import com.querydsl.core.types.dsl.CaseBuilder; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -32,7 +31,6 @@ public class TaskCustomRepositoryImpl implements TaskCustomRepository { private final JPAQueryFactory queryFactory; - private final EntityManager entityManager; @Override public Page findTasksRequestedByUser(Long requesterId, Pageable pageable, FilterTaskListRequest filterTaskListRequest) { @@ -57,7 +55,7 @@ public Page findTasksAssignedByManager(Long processorId, Pageable pa } @Override - public List findTeamStatus(Long memberId, FilterTeamStatusRequest filter) { + public List findTeamStatus(Long memberId, FilterTeamStatusRequest filter) { BooleanBuilder builder = new BooleanBuilder(); // 담당자 ID 필터링 @@ -101,8 +99,8 @@ public List findTeamStatus(Long memberId, FilterTeamStat .collect(Collectors.groupingBy(t -> t.getProcessor().getMemberId())) .entrySet().stream() .map(entry -> { - List taskResponses = entry.getValue().stream() - .map(taskEntity -> new TaskItemResponse( + List taskResponses = entry.getValue().stream() + .map(taskEntity -> new TeamTaskItemResponse( taskEntity.getTaskId(), taskEntity.getTaskCode(), taskEntity.getTitle(), @@ -116,7 +114,7 @@ public List findTeamStatus(Long memberId, FilterTeamStat taskEntity.getCreatedAt() )).collect(Collectors.toList()); - return new TeamMemberTaskResponse( + return new TeamTaskResponse( entry.getKey(), entry.getValue().get(0).getProcessor().getNickname(), entry.getValue().get(0).getProcessor().getImageUrl(), @@ -156,32 +154,37 @@ public Page findAllTasks(Pageable pageable, FilterTaskListRequest fi } @Override - public List findTasksByFilter(Long processorId, List statuses, LocalDateTime untilDateTime, FilterTaskBoardRequest request, Pageable pageable) { + public List findTasksByFilter(Long processorId, List statuses, LocalDateTime untilDateTime, FilterTaskBoardRequest request) { BooleanBuilder builder = createTaskBoardFilter(processorId, statuses, untilDateTime, request); return queryFactory .selectFrom(taskEntity) .where(builder) .orderBy(taskEntity.processorOrder.asc()) - .limit(pageable.getPageSize() + 1) - .offset(pageable.getOffset()) .fetch(); } - private BooleanBuilder createTaskBoardFilter(Long processorId, List statuses, LocalDateTime untilDateTime, FilterTaskBoardRequest request) { + private BooleanBuilder createTaskBoardFilter(Long processorId, List statuses, LocalDateTime fromDateTime, FilterTaskBoardRequest request) { BooleanBuilder builder = new BooleanBuilder(); builder.and(taskEntity.processor.memberId.eq(processorId)); builder.and(taskEntity.taskStatus.in(statuses)); - builder.and(taskEntity.finishedAt.isNull().or(taskEntity.finishedAt.loe(untilDateTime))); + + if (fromDateTime != null) { + builder.and(taskEntity.taskStatus.ne(TaskStatus.COMPLETED) + .or(taskEntity.taskStatus.eq(TaskStatus.COMPLETED) + .and(taskEntity.finishedAt.goe(fromDateTime)))); + } if (request.labelId() != null) { builder.and(taskEntity.label.labelId.eq(request.labelId())); } - if (request.mainCategoryId() != null) { - builder.and(taskEntity.category.mainCategory.categoryId.eq(request.mainCategoryId())); + if (!request.mainCategoryIds().isEmpty()) { + builder.and(taskEntity.category.mainCategory.categoryId.in(request.mainCategoryIds()) + .and(taskEntity.category.mainCategory.isDeleted.eq(false))); } - if (request.subCategoryId() != null) { - builder.and(taskEntity.category.categoryId.eq(request.subCategoryId())); + if (!request.categoryIds().isEmpty()) { + builder.and(taskEntity.category.categoryId.in(request.categoryIds()) + .and(taskEntity.category.isDeleted.eq(false))); } if (request.title() != null && !request.title().isEmpty()) { String titleFilter = "%" + request.title() + "%"; diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java index adf87e22..5c8fd21e 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java @@ -2,13 +2,12 @@ import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import io.lettuce.core.dynamic.annotation.Param; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -38,15 +37,16 @@ List findYesterdayTaskByUpdatedAtIsBetween( @Query("SELECT t FROM TaskEntity t " + "WHERE t.processor.memberId = :processorId " + "AND t.taskStatus IN :taskStatus " + - "AND (t.taskStatus != 'COMPLETED' OR t.finishedAt <= :untilDate) " + + "AND (:fromDateTime IS NULL OR t.taskStatus != 'COMPLETED' OR " + + " (t.taskStatus = 'COMPLETED' AND t.finishedAt >= :fromDateTime)) " + "ORDER BY t.processorOrder ASC ") - Slice findTasksWithTaskStatusAndCompletedAt( + List findTasksWithTaskStatusAndCompletedAt( @Param("processorId") Long processorId, @Param("taskStatus") List taskStatus, - @Param("untilDate") LocalDateTime untilDate, - Pageable pageable + @Param("fromDateTime") LocalDateTime fromDateTime ); + Optional findByTaskIdAndTaskStatus(Long id, TaskStatus status); Optional findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderLessThanOrderByProcessorOrderDesc(Long processorId, TaskStatus taskStatus, Long processorOrder); @@ -55,7 +55,7 @@ Optional findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderAf Long processorId, TaskStatus taskStatus, Long processorOrder); @Query("SELECT t FROM TaskEntity t JOIN FETCH t.processor p WHERE (:memberId IS NULL OR p.memberId = :memberId) ") - Page findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter, Pageable pageable); + Page findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter, Pageable pageable); diff --git a/src/main/java/clap/server/application/mapper/TaskResponseMapper.java b/src/main/java/clap/server/application/mapper/TaskResponseMapper.java index 7381a5ed..f68a80ef 100644 --- a/src/main/java/clap/server/application/mapper/TaskResponseMapper.java +++ b/src/main/java/clap/server/application/mapper/TaskResponseMapper.java @@ -1,14 +1,12 @@ package clap.server.application.mapper; -import clap.server.adapter.inbound.web.dto.task.response.TaskBoardResponse; -import clap.server.adapter.inbound.web.dto.task.response.TaskItemResponse; import clap.server.adapter.inbound.web.dto.task.response.*; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import clap.server.domain.model.member.Member; import clap.server.domain.model.task.Attachment; +import clap.server.domain.model.task.Label; import clap.server.domain.model.task.Task; -import org.springframework.data.domain.Slice; import java.util.Collections; import java.util.List; @@ -44,6 +42,7 @@ public static FilterRequestedTasksResponse toFilterRequestedTasksResponse(Task t task.getFinishedAt() != null ? task.getFinishedAt() : null ); } + public static FilterAssignedTaskListResponse toFilterAssignedTaskListResponse(Task task) { return new FilterAssignedTaskListResponse( task.getTaskId(), @@ -58,6 +57,7 @@ public static FilterAssignedTaskListResponse toFilterAssignedTaskListResponse(Ta task.getFinishedAt() != null ? task.getFinishedAt() : null ); } + public static FilterPendingApprovalResponse toFilterPendingApprovalTasksResponse(Task task) { return new FilterPendingApprovalResponse( task.getTaskId(), @@ -71,7 +71,7 @@ public static FilterPendingApprovalResponse toFilterPendingApprovalTasksResponse ); } - public static FindTaskDetailsResponse toFindTaskDetailResponse(Task task, List attachments){ + public static FindTaskDetailsResponse toFindTaskDetailResponse(Task task, List attachments) { List attachmentResponses = toAttachmentResponseList(attachments); return new FindTaskDetailsResponse( task.getTaskId(), @@ -119,18 +119,15 @@ public static FilterAllTasksResponse toFilterAllTasksResponse(Task task) { ); } - public static TaskBoardResponse toSliceTaskItemResponse(Slice tasks) { - Map> tasksByStatus =tasks.getContent().stream() + public static TaskBoardResponse toTaskBoardResponse(List tasks) { + Map> tasksByStatus = tasks.stream() .map(TaskResponseMapper::toTaskItemResponse) .collect(Collectors.groupingBy(TaskItemResponse::taskStatus)); return new TaskBoardResponse( tasksByStatus.getOrDefault(TaskStatus.IN_PROGRESS, Collections.emptyList()), tasksByStatus.getOrDefault(TaskStatus.PENDING_COMPLETED, Collections.emptyList()), - tasksByStatus.getOrDefault(TaskStatus.COMPLETED, Collections.emptyList()), - tasks.hasNext(), - tasks.isFirst(), - tasks.isLast() + tasksByStatus.getOrDefault(TaskStatus.COMPLETED, Collections.emptyList()) ); } @@ -141,6 +138,7 @@ public static TaskItemResponse toTaskItemResponse(Task task) { task.getTitle(), task.getCategory().getMainCategory().getName(), task.getCategory().getName(), + task.getLabel() != null ? toLabelInfo(task.getLabel()) : null, task.getRequester().getNickname(), task.getRequester().getImageUrl(), task.getRequester().getMemberInfo().getDepartment().getName(), @@ -150,6 +148,13 @@ public static TaskItemResponse toTaskItemResponse(Task task) { ); } + public static TaskItemResponse.LabelInfo toLabelInfo(Label label) { + return new TaskItemResponse.LabelInfo( + label.getLabelName(), + label.getLabelColor() + ); + } + public static FindTaskDetailsForManagerResponse toFindTaskDetailForManagerResponse(Task task, List attachments) { List attachmentResponses = toAttachmentResponseList(attachments); return new FindTaskDetailsForManagerResponse( diff --git a/src/main/java/clap/server/application/port/inbound/task/FilterTaskBoardUsecase.java b/src/main/java/clap/server/application/port/inbound/task/FilterTaskBoardUsecase.java index a245ca28..7c096a26 100644 --- a/src/main/java/clap/server/application/port/inbound/task/FilterTaskBoardUsecase.java +++ b/src/main/java/clap/server/application/port/inbound/task/FilterTaskBoardUsecase.java @@ -7,5 +7,5 @@ import java.time.LocalDate; public interface FilterTaskBoardUsecase { - TaskBoardResponse getTaskBoardByFilter(Long processorId, LocalDate untilDate, FilterTaskBoardRequest request, Pageable pageable); + TaskBoardResponse getTaskBoardByFilter(Long processorId, LocalDate fromDate, FilterTaskBoardRequest request); } diff --git a/src/main/java/clap/server/application/port/inbound/task/GetTaskBoardUsecase.java b/src/main/java/clap/server/application/port/inbound/task/GetTaskBoardUsecase.java deleted file mode 100644 index ccf7dce9..00000000 --- a/src/main/java/clap/server/application/port/inbound/task/GetTaskBoardUsecase.java +++ /dev/null @@ -1,10 +0,0 @@ -package clap.server.application.port.inbound.task; - -import clap.server.adapter.inbound.web.dto.task.response.TaskBoardResponse; -import org.springframework.data.domain.Pageable; - -import java.time.LocalDate; - -public interface GetTaskBoardUsecase { - TaskBoardResponse getTaskBoards(Long processorId, LocalDate untilDate,Pageable pageable); -} \ No newline at end of file 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 054d0343..a069ab78 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,14 +1,13 @@ package clap.server.application.port.outbound.task; -import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest; +import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import clap.server.domain.model.task.Task; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; import java.time.LocalDateTime; import java.util.List; @@ -27,15 +26,13 @@ public interface LoadTaskPort { Page findAllTasks(Pageable pageable, FilterTaskListRequest findTaskListRequest); - Slice findByProcessorAndStatus(Long processorId, List statuses, LocalDateTime untilDate, Pageable pageable); - Optional findByIdAndStatus(Long id, TaskStatus status); Optional findPrevOrderTaskByProcessorIdAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder); Optional findNextOrderTaskByProcessorIdAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder); - Slice findTaskBoardByFilter(Long processorId, List statuses, LocalDateTime untilDateTime, FilterTaskBoardRequest request, Pageable pageable); + List findTaskBoardByFilter(Long processorId, List statuses, LocalDateTime untilDateTime, FilterTaskBoardRequest request); - List findTeamStatus(Long memberId, FilterTeamStatusRequest filter); + List findTeamStatus(Long memberId, FilterTeamStatusRequest filter); } diff --git a/src/main/java/clap/server/application/service/task/GetTaskBoardService.java b/src/main/java/clap/server/application/service/task/GetTaskBoardService.java index 3f126e17..1427d140 100644 --- a/src/main/java/clap/server/application/service/task/GetTaskBoardService.java +++ b/src/main/java/clap/server/application/service/task/GetTaskBoardService.java @@ -5,15 +5,12 @@ import clap.server.application.mapper.TaskResponseMapper; import clap.server.application.port.inbound.domain.MemberService; import clap.server.application.port.inbound.task.FilterTaskBoardUsecase; -import clap.server.application.port.inbound.task.GetTaskBoardUsecase; import clap.server.application.port.outbound.task.LoadTaskPort; import clap.server.common.annotation.architecture.ApplicationService; import clap.server.domain.model.task.Task; import clap.server.domain.policy.task.TaskPolicyConstants; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; @@ -24,23 +21,15 @@ @ApplicationService @RequiredArgsConstructor @Transactional(readOnly = true) -class GetTaskBoardService implements GetTaskBoardUsecase, FilterTaskBoardUsecase { +class GetTaskBoardService implements FilterTaskBoardUsecase { private final MemberService memberService; private final LoadTaskPort loadTaskPort; @Override - public TaskBoardResponse getTaskBoards(Long processorId, LocalDate untilDate, Pageable pageable) { + public TaskBoardResponse getTaskBoardByFilter(Long processorId, LocalDate fromDate, FilterTaskBoardRequest request) { memberService.findActiveMember(processorId); - LocalDateTime untilDateTime = untilDate == null ? LocalDate.now().plusDays(1).atStartOfDay() : untilDate.plusDays(1).atStartOfDay(); - Slice tasks = loadTaskPort.findByProcessorAndStatus(processorId, TaskPolicyConstants.TASK_BOARD_STATUS_FILTER, untilDateTime, pageable); - return TaskResponseMapper.toSliceTaskItemResponse(tasks); - } - - @Override - public TaskBoardResponse getTaskBoardByFilter(Long processorId, LocalDate untilDate, FilterTaskBoardRequest request, Pageable pageable) { - memberService.findActiveMember(processorId); - LocalDateTime untilDateTime = untilDate == null ? LocalDate.now().plusDays(1).atStartOfDay() : untilDate.plusDays(1).atStartOfDay(); - Slice tasks = loadTaskPort.findTaskBoardByFilter(processorId, TaskPolicyConstants.TASK_BOARD_STATUS_FILTER, untilDateTime, request, pageable); - return TaskResponseMapper.toSliceTaskItemResponse(tasks); + LocalDateTime fromDateTime = fromDate != null ? fromDate.atStartOfDay() : null; + List tasks = loadTaskPort.findTaskBoardByFilter(processorId, TaskPolicyConstants.TASK_BOARD_STATUS_FILTER, fromDateTime, request); + return TaskResponseMapper.toTaskBoardResponse(tasks); } } diff --git a/src/main/java/clap/server/application/service/task/TeamStatusService.java b/src/main/java/clap/server/application/service/task/TeamStatusService.java index e24d09a6..24ad09a6 100644 --- a/src/main/java/clap/server/application/service/task/TeamStatusService.java +++ b/src/main/java/clap/server/application/service/task/TeamStatusService.java @@ -1,7 +1,7 @@ package clap.server.application.service.task; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.inbound.web.dto.task.response.TeamStatusResponse; import clap.server.application.port.inbound.task.FilterTeamStatusUsecase; import clap.server.application.port.inbound.task.LoadTeamStatusUsecase; @@ -22,13 +22,13 @@ public TeamStatusService(LoadTaskPort loadTaskPort) { @Override public TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter, Pageable pageable) { - List members = loadTaskPort.findTeamStatus(memberId, filter); // 페이징 처리 + List members = loadTaskPort.findTeamStatus(memberId, filter); // 페이징 처리 return new TeamStatusResponse(members); } @Override public TeamStatusResponse filterTeamStatus(FilterTeamStatusRequest filter) { - List members = loadTaskPort.findTeamStatus(null, filter); + List members = loadTaskPort.findTeamStatus(null, filter); return new TeamStatusResponse(members); } diff --git a/src/main/java/clap/server/application/service/task/UpdateTaskService.java b/src/main/java/clap/server/application/service/task/UpdateTaskService.java index 667114df..82029f1d 100644 --- a/src/main/java/clap/server/application/service/task/UpdateTaskService.java +++ b/src/main/java/clap/server/application/service/task/UpdateTaskService.java @@ -21,13 +21,12 @@ import clap.server.application.port.outbound.task.LoadAttachmentPort; import clap.server.application.service.webhook.SendNotificationService; import clap.server.common.annotation.architecture.ApplicationService; -import clap.server.domain.policy.attachment.FilePathPolicy; import clap.server.domain.model.member.Member; import clap.server.domain.model.task.Attachment; import clap.server.domain.model.task.Category; import clap.server.domain.model.task.Label; import clap.server.domain.model.task.Task; -import clap.server.domain.policy.task.TaskPolicyConstants; +import clap.server.domain.policy.attachment.FilePathPolicy; import clap.server.exception.ApplicationException; import clap.server.exception.code.TaskErrorCode; import lombok.RequiredArgsConstructor; @@ -71,7 +70,7 @@ public UpdateTaskResponse updateTask(Long requesterId, Long taskId, UpdateTaskRe @Override @Transactional - public UpdateTaskResponse updateTaskState(Long memberId, Long taskId, UpdateTaskStatusRequest updateTaskStatusRequest) { + public UpdateTaskResponse updateTaskStatus(Long memberId, Long taskId, TaskStatus taskStatus) { memberService.findActiveMember(memberId); memberService.findReviewer(memberId); Task task = taskService.findById(taskId);