package com.srsystem.service; import com.srsystem.dto.CreateDispatchRequest; import com.srsystem.dto.NotificationEvent; import com.srsystem.entity.DispatchHistory; import com.srsystem.entity.Employee; import com.srsystem.entity.Project; import com.srsystem.entity.enums.DispatchStatus; import com.srsystem.exception.BusinessException; import com.srsystem.exception.ErrorCode; import com.srsystem.listener.NotificationPublisher; import com.srsystem.repository.DispatchHistoryRepository; import com.srsystem.repository.EmployeeRepository; import com.srsystem.repository.ProjectRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.util.List; @Service @RequiredArgsConstructor @Transactional(readOnly = true) public class DispatchHistoryService { private final DispatchHistoryRepository dispatchHistoryRepository; private final EmployeeRepository employeeRepository; private final ProjectRepository projectRepository; private final NotificationPublisher notificationPublisher; public List findByEmployeeId(Long empId) { employeeRepository.findById(empId) .orElseThrow(() -> new BusinessException(ErrorCode.EMPLOYEE_NOT_FOUND)); return dispatchHistoryRepository.findByEmployee_EmpId(empId); } public List getActiveDispatches() { return dispatchHistoryRepository.findByEndDateIsNull(); } public Page findAll(Pageable pageable, Long empId, Long projectId) { if (empId != null && projectId != null) { return dispatchHistoryRepository.findByEmployee_EmpIdAndProject_ProjectId(empId, projectId, pageable); } if (empId != null) { return dispatchHistoryRepository.findByEmployee_EmpId(empId, pageable); } if (projectId != null) { return dispatchHistoryRepository.findByProject_ProjectId(projectId, pageable); } return dispatchHistoryRepository.findAll(pageable); } public DispatchHistory findById(Long dispatchId) { return dispatchHistoryRepository.findById(dispatchId) .orElseThrow(() -> new BusinessException(ErrorCode.DISPATCH_NOT_FOUND)); } @Transactional public void delete(Long dispatchId) { DispatchHistory dh = findById(dispatchId); dispatchHistoryRepository.delete(dh); } @Transactional public DispatchHistory createDispatch(CreateDispatchRequest request) { Employee employee = employeeRepository.findById(request.employeeId()) .orElseThrow(() -> new BusinessException(ErrorCode.EMPLOYEE_NOT_FOUND)); Project project = projectRepository.findById(request.projectId()) .orElseThrow(() -> new BusinessException(ErrorCode.PROJECT_NOT_FOUND)); DispatchHistory history = DispatchHistory.builder() .employee(employee) .project(project) .roleTitle(request.roleTitle()) .contributionRate(request.contributionRate()) .individualTech(request.individualTech()) .performedTasks(request.performedTasks()) .startDate(request.startDate() != null ? request.startDate() : LocalDate.now()) .build(); DispatchHistory saved = dispatchHistoryRepository.save(history); // Update employee dispatch status to DISPATCHED employee.setDispatchStatus(DispatchStatus.DISPATCHED); employeeRepository.save(employee); // Send notification notificationPublisher.publish(new NotificationEvent( "DISPATCH_ASSIGNED", "신규 파견 발령: " + project.getProjectName(), String.format("'%s' 프로젝트에 %s 역할로 파견 등록되었습니다.", project.getProjectName(), request.roleTitle()), "/dispatch", employee.getEmpId() )); return saved; } @Transactional public DispatchHistory endDispatch(Long dispatchId) { DispatchHistory history = dispatchHistoryRepository.findById(dispatchId) .orElseThrow(() -> new BusinessException(ErrorCode.DISPATCH_NOT_FOUND)); history.setEndDate(LocalDate.now()); DispatchHistory saved = dispatchHistoryRepository.save(history); // Check active dispatches remaining List active = dispatchHistoryRepository.findByEmployee_EmpIdAndEndDateIsNull(history.getEmployee().getEmpId()); if (active.isEmpty()) { Employee emp = history.getEmployee(); emp.setDispatchStatus(DispatchStatus.WAITING); employeeRepository.save(emp); } return saved; } }