yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeContractServiceImpl.java
@@ -2,26 +2,34 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractPageReqVO;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractRespVO;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractSaveReqVO;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractImportExcelVO;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractImportReqVO;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractImportRespVO;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractTerminateReqVO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeContractDO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO;
import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeContractMapper;
import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper;
import cn.iocoder.yudao.module.hrm.dal.redis.HrmNoRedisDAO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -50,11 +58,16 @@
    @Resource
    private HrmEmployeeService employeeService;
    @Resource
    private HrmEmployeeMapper employeeMapper;
    @Resource
    private DeptApi deptApi;
    @Resource
    private StorageAttachmentApi storageAttachmentApi;
    @Resource
    private HrmNoRedisDAO noRedisDAO;
    @Resource
    @Lazy // 自注入需延迟加载,导入时逐条走事务边界
    private HrmEmployeeContractService self;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -318,4 +331,101 @@
        }
    }
    @Override
    public HrmEmployeeContractImportRespVO importContractList(List<HrmEmployeeContractImportExcelVO> importContracts,
                                                              HrmEmployeeContractImportReqVO importReqVO) {
        // 1. 过滤员工姓名为空的行
        importContracts = importContracts.stream()
                .filter(item -> item.getName() != null && StrUtil.isNotBlank(item.getName().trim()))
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(importContracts)) {
            throw exception(EMPLOYEE_CONTRACT_IMPORT_LIST_IS_EMPTY);
        }
        // 2. 预加载员工姓名 -> 员工档案 映射(含已离职,便于补录历史合同)
        Map<String, List<HrmEmployeeDO>> employeeNameMap = employeeMapper.selectList().stream()
                .filter(emp -> StrUtil.isNotBlank(emp.getName()))
                .collect(Collectors.groupingBy(emp -> emp.getName().trim(), LinkedHashMap::new, Collectors.toList()));
        // 3. 逐条处理:匹配到则覆盖更新,否则新建
        HrmEmployeeContractImportRespVO respVO = HrmEmployeeContractImportRespVO.builder()
                .createNames(new ArrayList<>())
                .updateNames(new ArrayList<>())
                .failureNames(new LinkedHashMap<>())
                .build();
        for (HrmEmployeeContractImportExcelVO importContract : importContracts) {
            String name = importContract.getName().trim();
            try {
                // 3.1 员工姓名转员工 ID
                Long employeeId = parseEmployeeId(name, employeeNameMap);
                // 3.2 组装保存请求(必填字段校验)
                HrmEmployeeContractSaveReqVO saveReqVO = buildImportSaveReqVO(importContract, employeeId);
                // 3.3 按「员工 + 合同类型 + 合同开始日期」判定已存在
                HrmEmployeeContractDO exist = contractMapper.selectByEmployeeTypeStartDate(employeeId,
                        saveReqVO.getContractType(), saveReqVO.getStartDate());
                if (exist == null) {
                    self.createContract(saveReqVO);
                    respVO.getCreateNames().add(name);
                } else {
                    if (!Boolean.TRUE.equals(importReqVO.getUpdateSupport())) {
                        respVO.getFailureNames().put(name,
                                StrUtil.format(EMPLOYEE_CONTRACT_IMPORT_CONTRACT_EXISTS.getMsg(),
                                        saveReqVO.getStartDate().toString()));
                        continue;
                    }
                    saveReqVO.setId(exist.getId());
                    self.updateContract(saveReqVO);
                    respVO.getUpdateNames().add(name);
                }
            } catch (ServiceException ex) {
                respVO.getFailureNames().put(name, ex.getMessage());
            } catch (Exception ex) {
                respVO.getFailureNames().put(name, ex.getMessage());
            }
        }
        return respVO;
    }
    /**
     * 员工姓名解析为员工 ID,重名时提示需手工处理
     */
    private Long parseEmployeeId(String name, Map<String, List<HrmEmployeeDO>> employeeNameMap) {
        List<HrmEmployeeDO> employees = employeeNameMap.get(name);
        if (CollUtil.isEmpty(employees)) {
            throw exception(EMPLOYEE_CONTRACT_IMPORT_EMPLOYEE_NAME_NOT_EXISTS, name);
        }
        if (employees.size() > 1) {
            throw exception(EMPLOYEE_CONTRACT_IMPORT_EMPLOYEE_NAME_MULTIPLE, name);
        }
        return employees.get(0).getId();
    }
    /**
     * 组装导入合同保存请求并做必填字段校验(日期逻辑校验交由 create/update 处理)
     */
    private HrmEmployeeContractSaveReqVO buildImportSaveReqVO(HrmEmployeeContractImportExcelVO importContract,
                                                              Long employeeId) {
        if (importContract.getContractType() == null) {
            throw exception(EMPLOYEE_CONTRACT_IMPORT_FIELD_REQUIRED, "合同类型");
        }
        if (importContract.getContractTermType() == null) {
            throw exception(EMPLOYEE_CONTRACT_IMPORT_FIELD_REQUIRED, "合同期限类型");
        }
        if (importContract.getStartDate() == null) {
            throw exception(EMPLOYEE_CONTRACT_IMPORT_FIELD_REQUIRED, "合同开始日期");
        }
        HrmEmployeeContractSaveReqVO reqVO = new HrmEmployeeContractSaveReqVO();
        reqVO.setEmployeeId(employeeId);
        reqVO.setContractType(importContract.getContractType());
        reqVO.setContractTermType(importContract.getContractTermType());
        reqVO.setSignCompany(importContract.getSignCompany());
        reqVO.setSignDate(importContract.getSignDate());
        reqVO.setStartDate(importContract.getStartDate());
        reqVO.setEndDate(importContract.getEndDate());
        reqVO.setProbationStartDate(importContract.getProbationStartDate());
        reqVO.setProbationEndDate(importContract.getProbationEndDate());
        reqVO.setProbationSalary(importContract.getProbationSalary());
        reqVO.setRegularSalary(importContract.getRegularSalary());
        reqVO.setRemark(importContract.getRemark());
        return reqVO;
    }
}