Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ private String makeTerminatedStatusBlock(PushNotificationTemplate request, Strin
"inlines", new Object[]{
Map.of(
"type", "styled",
"text", " - 거절 사유 : " + request.reason(),
"text", " - 반려 사유 : " + request.reason(),
"bold", false
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package clap.server.adapter.outbound.persistense.mapper;

import clap.server.adapter.outbound.persistense.entity.task.CommentEntity;
import clap.server.adapter.outbound.persistense.entity.task.TaskEntity;
import clap.server.adapter.outbound.persistense.mapper.common.PersistenceMapper;
import clap.server.domain.model.task.Comment;
import clap.server.domain.model.task.Task;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,6 @@ List<TaskEntity> findYesterdayTaskByUpdatedAtIsBetween(

List<TaskEntity> findByProcessor_MemberIdAndTaskStatusIn(Long memberId, Collection<TaskStatus> taskStatuses);


@Query("SELECT t FROM TaskEntity t " +
"WHERE t.processor.memberId = :processorId " +
"AND t.taskStatus IN :taskStatus " +
"AND (:fromDateTime IS NULL OR t.taskStatus != 'COMPLETED' OR " +
" (t.taskStatus = 'COMPLETED' AND t.finishedAt >= :fromDateTime)) " +
"ORDER BY t.processorOrder ASC ")
List<TaskEntity> findTasksWithTaskStatusAndCompletedAt(
@Param("processorId") Long processorId,
@Param("taskStatus") List<TaskStatus> taskStatus,
@Param("fromDateTime") LocalDateTime fromDateTime
);


Optional<TaskEntity> findByTaskIdAndTaskStatus(Long id, TaskStatus status);

Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderLessThanOrderByProcessorOrderAsc(Long processorId, TaskStatus taskStatus, Long processorOrder);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package clap.server.application.port.inbound.domain;

import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
import clap.server.application.port.outbound.task.CommandTaskPort;
import clap.server.application.port.outbound.task.LoadTaskPort;
import clap.server.domain.model.task.Task;
Expand All @@ -23,4 +24,8 @@ public Task findById(Long taskId) {
public Task upsert(Task task) {
return commandTaskPort.save(task);
}

public Task findByIdAndStatus(Long taskId, TaskStatus status) {
return loadTaskPort.findByIdAndStatus(taskId, status).orElseThrow(() -> new ApplicationException(TaskErrorCode.TASK_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -1,49 +1,29 @@
package clap.server.application.service.task;

import clap.server.adapter.inbound.web.dto.task.request.UpdateTaskOrderRequest;
import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole;
import clap.server.adapter.outbound.persistense.entity.notification.constant.NotificationType;
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskHistoryType;
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
import clap.server.application.port.inbound.domain.MemberService;
import clap.server.application.port.inbound.domain.TaskService;
import clap.server.application.port.inbound.task.UpdateTaskBoardUsecase;
import clap.server.application.port.inbound.task.UpdateTaskOrderAndStatusUsecase;
import clap.server.application.port.outbound.task.LoadTaskPort;
import clap.server.application.port.outbound.taskhistory.CommandTaskHistoryPort;
import clap.server.application.service.webhook.SendNotificationService;
import clap.server.common.annotation.architecture.ApplicationService;
import clap.server.domain.model.member.Member;
import clap.server.domain.model.task.Task;
import clap.server.domain.model.task.TaskHistory;
import clap.server.domain.policy.task.ProcessorValidationPolicy;
import clap.server.domain.policy.task.TaskOrderCalculationPolicy;
import clap.server.domain.policy.task.TaskPolicyConstants;
import clap.server.exception.ApplicationException;
import clap.server.exception.code.TaskErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@ApplicationService
@RequiredArgsConstructor
class UpdateTaskBoardService implements UpdateTaskBoardUsecase, UpdateTaskOrderAndStatusUsecase {
public class UpdateTaskBoardService implements UpdateTaskBoardUsecase {
private final MemberService memberService;
private final TaskService taskService;
private final LoadTaskPort loadTaskPort;
private final SendNotificationService sendNotificationService;
private final CommandTaskHistoryPort commandTaskHistoryPort;

private final TaskOrderCalculationPolicy taskOrderCalculationPolicy;
private final ProcessorValidationPolicy processorValidationPolicy;

private Task findByIdAndStatus(Long taskId, TaskStatus status) {
return loadTaskPort.findByIdAndStatus(taskId, status).orElseThrow(() -> new ApplicationException(TaskErrorCode.TASK_NOT_FOUND));
}

/**
* 작업(Task)의 순서를 업데이트하는 메서드
*
Expand All @@ -53,30 +33,28 @@ private Task findByIdAndStatus(Long taskId, TaskStatus status) {
@Override
@Transactional
public void updateTaskOrder(Long processorId, UpdateTaskOrderRequest request) {
// 요청 유효성 검증
validateRequest(request, null);
Member processor = memberService.findActiveMember(processorId);
Task targetTask = taskService.findById(request.targetTaskId());
processorValidationPolicy.validateProcessor(processorId, targetTask);

// 가장 상위로 이동
if (request.prevTaskId() == 0) {
Task nextTask = findByIdAndStatus(request.nextTaskId(), targetTask.getTaskStatus());
Task nextTask = taskService.findByIdAndStatus(request.nextTaskId(), targetTask.getTaskStatus());
// 해당 상태에서 바로 앞에 있는 작업 찾기
Task prevTask = loadTaskPort.findPrevOrderTaskByProcessorOrderAndStatus(processorId, targetTask.getTaskStatus(), nextTask.getProcessorOrder()).orElse(null);
long newOrder = taskOrderCalculationPolicy.calculateOrderForTop(prevTask, nextTask);
updateNewTaskOrder(targetTask, newOrder);
}
// 가장 하위로 이동
else if (request.nextTaskId() == 0) {
Task prevTask = findByIdAndStatus(request.prevTaskId(), targetTask.getTaskStatus());
Task prevTask = taskService.findByIdAndStatus(request.prevTaskId(), targetTask.getTaskStatus());
// 해당 상태에서 바로 뒤에 있는 작업 찾기
Task nextTask = loadTaskPort.findNextOrderTaskByProcessorOrderAndStatus(processorId, targetTask.getTaskStatus(), prevTask.getProcessorOrder()).orElse(null);
long newOrder = taskOrderCalculationPolicy.calculateOrderForBottom(prevTask, nextTask);
updateNewTaskOrder(targetTask, newOrder);
} else {
Task prevTask = findByIdAndStatus(request.prevTaskId(), targetTask.getTaskStatus());
Task nextTask = findByIdAndStatus(request.nextTaskId(), targetTask.getTaskStatus());
Task prevTask = taskService.findByIdAndStatus(request.prevTaskId(), targetTask.getTaskStatus());
Task nextTask = taskService.findByIdAndStatus(request.nextTaskId(), targetTask.getTaskStatus());
long newOrder = taskOrderCalculationPolicy.calculateNewProcessorOrder(prevTask.getProcessorOrder(), nextTask.getProcessorOrder());
updateNewTaskOrder(targetTask, newOrder);
}
Expand All @@ -93,103 +71,5 @@ private void updateNewTaskOrder(Task targetTask, Long newOrder) {
taskService.upsert(targetTask);
}

/**
* 작업의 상태와 순서를 동시에 변경하는 메서드
*
* @param processorId 작업을 수행하는 멤버 ID
* @param request 순서 변경 요청 객체
* @param targetStatus 변경할 작업 상태
*/
@Override
@Transactional
public void updateTaskOrderAndStatus(Long processorId, UpdateTaskOrderRequest request, TaskStatus targetStatus) {
validateRequest(request, targetStatus);
Member processor = memberService.findActiveMember(processorId);
Task targetTask = taskService.findById(request.targetTaskId());
processorValidationPolicy.validateProcessor(processorId, targetTask);

Task updatedTask;
Task prevTask;
Task nextTask;

// 조회된 작업 보드에서 하나의 작업만 존재하고, 이 작업을 이동할 때
if (request.prevTaskId() == 0 && request.nextTaskId() == 0) {

// 요청 시간 기준으로 가장 가장 근접한 이전의 Task를 조회
prevTask = loadTaskPort.findPrevOrderTaskByTaskIdAndStatus(processorId, targetStatus, targetTask.getTaskId()).orElse(null);
if (prevTask != null) {
// 이전 Task가 있다면 바로 다음의 Task 조회
nextTask = loadTaskPort.findNextOrderTaskByProcessorOrderAndStatus(processorId, targetStatus, prevTask.getProcessorOrder()).orElse(null);
} // 요청 시간 기준으로 가장 가장 근접한 이후의 Task를 조회
else
nextTask = loadTaskPort.findNextOrderTaskByTaskIdAndStatus(processorId, targetStatus, targetTask.getTaskId()).orElse(null);

// 하나의 task만 존재할 경우 상태만 update
if (prevTask == null && nextTask == null) {
targetTask.updateTaskStatus(targetStatus);
updatedTask = taskService.upsert(targetTask);
} else if (prevTask == null) {
long newOrder = taskOrderCalculationPolicy.calculateOrderForBottom(null, nextTask);
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
} else if (nextTask == null) {
long newOrder = taskOrderCalculationPolicy.calculateOrderForBottom(prevTask, null);
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
} else {
long newOrder = taskOrderCalculationPolicy.calculateNewProcessorOrder(prevTask.getProcessorOrder(), nextTask.getProcessorOrder());
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
}
} else if (request.prevTaskId() == 0) {
nextTask = findByIdAndStatus(request.nextTaskId(), targetStatus);
// 해당 상태에서 바로 앞 있는 작업 찾기
prevTask = loadTaskPort.findPrevOrderTaskByProcessorOrderAndStatus(processorId, targetStatus, nextTask.getProcessorOrder()).orElse(null);
long newOrder = taskOrderCalculationPolicy.calculateOrderForTop(prevTask, nextTask);
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
} else if (request.nextTaskId() == 0) {
prevTask = findByIdAndStatus(request.prevTaskId(), targetStatus);
// 해당 상태에서 바로 뒤에 있는 작업 찾기
nextTask = loadTaskPort.findNextOrderTaskByProcessorOrderAndStatus(processorId, targetStatus, prevTask.getProcessorOrder()).orElse(null);
long newOrder = taskOrderCalculationPolicy.calculateOrderForBottom(prevTask, nextTask);
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
} else {
prevTask = findByIdAndStatus(request.prevTaskId(), targetStatus);
nextTask = findByIdAndStatus(request.nextTaskId(), targetStatus);
long newOrder = taskOrderCalculationPolicy.calculateNewProcessorOrder(prevTask.getProcessorOrder(), nextTask.getProcessorOrder());
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
}

TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.STATUS_SWITCHED, updatedTask, targetStatus.getDescription(), null,null);
commandTaskHistoryPort.save(taskHistory);
publishNotification(targetTask);
}

/**
* 작업의 상태와 순서를 업데이트하는 메서드
*/
private Task updateNewTaskOrderAndStatus(TaskStatus targetStatus, Task targetTask, long newOrder) {
targetTask.updateProcessorOrder(newOrder);
targetTask.updateTaskStatus(targetStatus);
return taskService.upsert(targetTask);
}

/**
* 순서 변경 요청의 유효성을 검증하는 메서드
*/
public void validateRequest(UpdateTaskOrderRequest request, TaskStatus targetStatus) {
// 타겟 상태가 유효한지 검증
if (targetStatus != null && !TaskPolicyConstants.TASK_BOARD_STATUS_FILTER.contains(targetStatus)) {
throw new ApplicationException(TaskErrorCode.INVALID_TASK_STATUS_TRANSITION);
}
}

private void publishNotification(Task task) {
List<Member> receivers = List.of(task.getRequester(), task.getProcessor());
receivers.forEach(receiver -> {
boolean isManager = receiver.getMemberInfo().getRole() == MemberRole.ROLE_MANAGER;
sendNotificationService.sendPushNotification(receiver, NotificationType.STATUS_SWITCHED, task, String.valueOf(task.getTaskStatus()), null, null, isManager);
});
sendNotificationService.sendAgitNotification(NotificationType.STATUS_SWITCHED,
task, String.valueOf(task.getTaskStatus()), null);
}

}

Loading